Skip to content

Commit 1078779

Browse files
committed
refactor(function): Add markdown rendering of ticket reference
ref: #40 #42 nofusscomputing/centurion_erp#466
1 parent 925a4a7 commit 1078779

File tree

3 files changed

+160
-5
lines changed

3 files changed

+160
-5
lines changed

src/functions/RenderMarkdown.js

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import hljs from 'highlight.js'
33
import markdownIt from "markdown-it";
44
import { full as emoji } from 'markdown-it-emoji'
55
import model_link_plugin from './markdown_plugins/ModelLink';
6+
import ticket_link_plugin from './markdown_plugins/TicketLink';
67

78

89

@@ -37,6 +38,8 @@ const md = markdownIt({
3738

3839
.use( require('markdown-it-task-lists') )
3940

41+
.use(ticket_link_plugin)
42+
4043
.use(model_link_plugin);
4144

4245

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { renderToStaticMarkup } from "react-dom/server";
2+
import IconLoader from "../../components/IconLoader";
3+
4+
5+
const UNESCAPE_RE = /(?<markdown>#(?<model_id>\d+))/g
6+
7+
8+
9+
function ticket_link (state, silent) {
10+
/**
11+
* Render ticket tag links
12+
* i.e. #<ticket_id>
13+
*/
14+
15+
const max = state.posMax
16+
let start = state.pos
17+
let end = state.pos
18+
19+
let begining = state.pos
20+
21+
const re = new RegExp(UNESCAPE_RE);
22+
23+
const fields = [ ...String(state.src).matchAll(re) ]
24+
25+
26+
if( fields.length === 0 ) {
27+
28+
return false
29+
30+
}
31+
32+
if( fields[0].index !== begining ) {
33+
34+
return false
35+
36+
}
37+
38+
39+
for( let item_link of fields) {
40+
41+
start = item_link.index
42+
end = start + String(item_link.groups.markdown).length
43+
44+
if ( start !== state.posMax ) { // middle text
45+
46+
const middle_text = state.push('text', '', 0)
47+
middle_text.content = state.src.slice(state.posMax, start)
48+
49+
}
50+
51+
state.pos = start
52+
state.posMax = end
53+
54+
if( state.env.tickets[item_link.groups.model_id] ?? null ) {
55+
56+
const span_o = state.push('span_open', 'span', 1)
57+
span_o.attrPush(['class', 'text-inline'])
58+
59+
const anchor_o = state.push('a_open', 'a', 1)
60+
anchor_o.attrPush(['href', state.env.tickets[item_link.groups.model_id].url])
61+
62+
63+
const icon_o = state.push('icon_open', 'span', 1)
64+
icon_o.attrPush([
65+
'class', 'badge-icon ticket-status-icon ticket-status-icon-' + String(state.env.tickets[item_link.groups.model_id].status).toLowerCase().replace(' ', '_').replace('(', '').replace(')', '')
66+
])
67+
68+
const icon_t = state.push('html_inline', '', 0)
69+
70+
icon_t.content = renderToStaticMarkup(
71+
<IconLoader
72+
name={'ticket_status_new'}
73+
/>
74+
)
75+
76+
const icon_c = state.push('icon_close', 'span', -1)
77+
78+
79+
const ref_o = state.push('ref_open', 'span', 1)
80+
ref_o.attrPush(["class", "sub-script metadata"])
81+
82+
const ref_t = state.push('text', '', 0)
83+
ref_t.content = ' #' + String( item_link.groups.model_id ) + ' '
84+
85+
const ref_c = state.push('ref_close', 'span', -1)
86+
87+
88+
const anchor_t = state.push('text', '', 0)
89+
anchor_t.content = state.env.tickets[item_link.groups.model_id].title
90+
91+
92+
const item_o = state.push('item_open', 'span', 1)
93+
item_o.attrPush(["class", "sub-script metadata"])
94+
95+
const item_t = state.push('text', '', 0)
96+
item_t.content = ', ' + String( state.env.tickets[item_link.groups.model_id].ticket_type ) + ' '
97+
98+
const item_c = state.push('item_close', 'span', -1)
99+
100+
101+
const anchor_c = state.push('a_close', 'a', -1)
102+
103+
104+
const span_c = state.push('span_close', 'span', -1)
105+
106+
}
107+
108+
}
109+
110+
111+
state.pos = end
112+
state.posMax = max
113+
114+
115+
return true
116+
117+
}
118+
119+
export default function ticket_link_plugin (md) {
120+
md.inline.ruler.push('ticket_link', ticket_link)
121+
};

src/index.css

+36-5
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,29 @@ span.sub-script.metadata,
802802
padding: 10px
803803
}
804804

805+
.external-links a {
806+
color: var(--text-colour);
807+
text-decoration: none;
808+
}
809+
810+
811+
span.text-inline {
812+
display: inline-block;
813+
line-height: inherit;
814+
}
815+
816+
span.text-inline span.badge-icon {
817+
display: inline-block;
818+
width: fit-content;
819+
820+
}
821+
822+
span.text-inline span.badge-icon svg {
823+
transform: translateY(5px);
824+
825+
}
826+
827+
805828
span.badge {
806829
background-color: var(--background-colour-active);
807830
border: 1px solid var(--border-colour-form-field);
@@ -815,11 +838,6 @@ span.badge {
815838
margin: 0px 2px;
816839
}
817840

818-
.external-links a {
819-
color: var(--text-colour);
820-
text-decoration: none;
821-
}
822-
823841

824842
span.badge span {
825843
display: inline-block;
@@ -877,65 +895,78 @@ span.badge span.badge-text.badge-text-action-remove {
877895

878896

879897

898+
span.badge-icon.ticket-status-icon svg,
880899
span.badge span.badge-icon.ticket-status-icon svg {
881900
border-radius: 10px;
882901
}
883902

903+
span.badge-icon.ticket-status-icon-accepted svg,
884904
span.badge span.badge-icon.ticket-status-icon-accepted svg {
885905
background-color: #e1ffb2;
886906
fill: #2e9200;
887907
}
888908

909+
span.badge-icon.ticket-status-icon-approvals svg,
889910
span.badge span.badge-icon.ticket-status-icon-approvals svg {
890911
background-color: #ffceb2;
891912
fill: #d86100;
892913
}
893914

915+
span.badge-icon.ticket-status-icon-assigned svg,
894916
span.badge span.badge-icon.ticket-status-icon-assigned svg {
895917
background-color: #e1ffb2;
896918
fill: #2e9200;
897919
}
898920

921+
span.badge-icon.ticket-status-icon-assigned_planning svg,
899922
span.badge span.badge-icon.ticket-status-icon-assigned_planning svg {
900923
background-color: #e1ffb2;
901924
fill: #2e9200;
902925
}
903926

927+
span.badge-icon.ticket-status-icon-closed svg,
904928
span.badge span.badge-icon.ticket-status-icon-closed svg {
905929
background-color: #c9b2ff;
906930
fill: #640092;
907931
}
908932

933+
span.badge-icon.ticket-status-icon-draft svg,
909934
span.badge span.badge-icon.ticket-status-icon-draft svg {
910935
background-color: #cacaca;
911936
fill: #4d4d4d;
912937
}
913938

939+
span.badge-icon.ticket-status-icon-evaluation svg,
914940
span.badge span.badge-icon.ticket-status-icon-evaluation svg {
915941
background-color: #b2d6ff;
916942
fill: #007592;
917943
}
918944

945+
span.badge-icon.ticket-status-icon-invalid svg,
919946
span.badge span.badge-icon.ticket-status-icon-invalid svg {
920947
background-color: #ffb2b6;
921948
fill: #920000;
922949
}
923950

951+
span.badge-icon.ticket-status-icon-new svg,
924952
span.badge span.badge-icon.ticket-status-icon-new svg {
925953
background-color: #b2dcff;
926954
fill: #004492
927955
}
928956

957+
span.badge-icon.ticket-status-icon-pending svg,
929958
span.badge span.badge-icon.ticket-status-icon-pending svg {
930959
background-color: #ffceb2;
931960
fill: #d86100;
932961
}
933962

963+
span.badge-icon.ticket-status-icon-solved svg,
934964
span.badge span.badge-icon.ticket-status-icon-solved svg {
935965
background-color: #c9b2ff;
936966
fill: #640092;
937967
}
938968

969+
span.badge-icon.ticket-status-icon-testing svg,
939970
span.badge span.badge-icon.ticket-status-icon-testing svg {
940971
background-color: #b2d3ff;
941972
fill: #8c00ff;

0 commit comments

Comments
 (0)