|
12 | 12 | <div>Message has no HTML body</div> |
13 | 13 | </div> |
14 | 14 |
|
15 | | - <el-table class="fill table" stripe :data="warnings" v-if="message?.hasHtmlBody" empty-text="There are no warnings"> |
| 15 | + <div v-if="message?.hasHtmlBody && isHtmlCompatibilityCheckDisabled" class="fill nodetails centrecontents"> |
| 16 | + <div>HTML compatibility check is disabled</div> |
| 17 | + </div> |
| 18 | + |
| 19 | + <el-table class="fill table" stripe :data="warnings" v-if="message?.hasHtmlBody && !isHtmlCompatibilityCheckDisabled" empty-text="There are no warnings"> |
16 | 20 | <el-table-column prop="feature" label="Feature" width="180"> |
17 | 21 | <template #default="scope"> |
18 | 22 | <span style="font-family: Courier New, Courier, monospace">{{scope.row.feature}}</span> |
|
41 | 45 |
|
42 | 46 | import MessagesController from "../ApiClient/MessagesController"; |
43 | 47 | import Message from "../ApiClient/Message"; |
44 | | - import { doIUseEmail } from '@jsx-email/doiuse-email'; |
| 48 | + import HubConnectionManager from "../ApiClient/HubConnectionManager"; |
| 49 | + import { HtmlCompatibilityWorkerManager, type CompatibilityWarning } from "../workers/HtmlCompatibilityWorkerManager"; |
45 | 50 |
|
46 | 51 | @Component |
47 | 52 | class MessageClientAnalysis extends Vue { |
48 | 53 |
|
49 | 54 | @Prop({ default: null }) |
50 | 55 | message: Message | null | undefined; |
51 | 56 |
|
| 57 | + @Prop({ default: null }) |
| 58 | + connection: HubConnectionManager | null = null; |
| 59 | +
|
52 | 60 | error: Error | null = null; |
53 | 61 | loading = false; |
| 62 | + isHtmlCompatibilityCheckDisabled = false; |
| 63 | + private workerManager = new HtmlCompatibilityWorkerManager(); |
54 | 64 |
|
55 | | - warnings: { message: string, feature: string, type: string, browsers: string[], url: string, isError: boolean }[] =[]; |
| 65 | + warnings: CompatibilityWarning[] = []; |
56 | 66 |
|
57 | 67 | @Watch("message") |
58 | 68 | async onMessageChanged(value: Message | null, oldValue: Message | null) { |
59 | 69 |
|
60 | 70 | await this.loadMessage(); |
61 | 71 | } |
62 | 72 |
|
| 73 | + @Watch("connection") |
| 74 | + onConnectionChanged() { |
| 75 | + if (this.connection) { |
| 76 | + this.connection.onServerChanged( async () => { |
| 77 | + await this.loadMessage(); |
| 78 | + }); |
| 79 | + } |
| 80 | + } |
| 81 | +
|
63 | 82 | @Watch("warnings") |
64 | 83 | onWarningsChanged() { |
65 | 84 | this.fireWarningCountChanged() |
|
70 | 89 | return this.warnings?.length ?? 0; |
71 | 90 | } |
72 | 91 |
|
73 | | - private parseWarning(warning: string, isError: boolean) { |
74 | | -
|
75 | | - const details = { message: warning, type: "", feature: "", browser: "", url: "", isError: false }; |
76 | | - const detailsMatch = warning.match(/^`(.+)` (support )?is (.+) (by|for) `(.+)`$/); |
77 | | -
|
78 | | - if (detailsMatch) { |
79 | | - details.feature = detailsMatch[1] ?? null; |
80 | | - details.type = detailsMatch[3] ?? null; |
81 | | - details.browser = detailsMatch[5] ?? null; |
82 | | - details.isError = isError; |
83 | | -
|
84 | | - if (details.feature.endsWith(" element")) { |
85 | | - details.url = `https://www.caniemail.com/features/html-${details.feature.replace("<", "").replace("> element", "")}/`; |
86 | | - } else { |
87 | | - details.url = `https://www.caniemail.com/features/css-${details.feature.replace(":", "-")}/`; |
88 | | -
|
89 | | - } |
90 | | - } else { |
91 | | - details.type = warning; |
92 | | - } |
93 | | -
|
94 | | - return details; |
95 | | - } |
96 | | -
|
97 | 92 | async loadMessage() { |
98 | 93 |
|
99 | 94 | this.warnings = []; |
100 | 95 | this.error = null; |
101 | 96 | this.loading = true; |
102 | 97 |
|
103 | 98 | try { |
104 | | - const newWarnings = []; |
105 | | - if (this.message != null && this.message.hasHtmlBody) { |
106 | | -
|
107 | | - const html = await new MessagesController().getMessageHtml(this.message.id); |
108 | | - const doIUseResults = doIUseEmail(html, { emailClients: ["*"] }); |
109 | | -
|
110 | | - const allWarnings = []; |
111 | | - for (const warning of doIUseResults.warnings) { |
112 | | - const details = this.parseWarning(warning, false); |
113 | | - allWarnings.push(details); |
| 99 | + if (this.message != null && this.message.hasHtmlBody && this.connection) { |
| 100 | + const server = await this.connection.getServer(); |
| 101 | + this.isHtmlCompatibilityCheckDisabled = server.disableHtmlCompatibilityCheck; |
| 102 | + |
| 103 | + if (!this.isHtmlCompatibilityCheckDisabled) { |
| 104 | + const html = await new MessagesController().getMessageHtml(this.message.id); |
| 105 | + |
| 106 | + // Use web worker for compatibility checking |
| 107 | + const compatibilityResults = await this.workerManager.checkCompatibility(html); |
| 108 | + this.warnings = compatibilityResults; |
114 | 109 | } |
115 | | -
|
116 | | - if (doIUseResults.success == false) { |
117 | | - for (const warning of doIUseResults.errors) { |
118 | | - const details = this.parseWarning(warning,true); |
119 | | - allWarnings.push(details); |
120 | | - } |
121 | | -
|
122 | | - } |
123 | | -
|
124 | | - const allGrouped = Object.groupBy(allWarnings, i => i.feature + " " + i.type); |
125 | | - for (const groupKey in allGrouped) { |
126 | | - const groupItems = allGrouped[groupKey]!; |
127 | | - newWarnings.push({ |
128 | | - type: groupItems[0].type, |
129 | | - |
130 | | - feature: groupItems[0].feature, |
131 | | - message: groupItems[0].message, |
132 | | - |
133 | | - url: groupItems[0].url, |
134 | | - browsers: groupItems.map(i => i.browser).filter((value, index, array) => array.indexOf(value) === index), |
135 | | - isError: groupItems[0].isError |
136 | | - }) |
137 | | - } |
138 | | -
|
139 | | - this.warnings = newWarnings; |
140 | | -
|
141 | 110 | } |
142 | 111 | } catch (e: any) { |
143 | 112 | this.error = e; |
|
152 | 121 | } |
153 | 122 |
|
154 | 123 | async destroyed() { |
155 | | -
|
| 124 | + this.workerManager.destroy(); |
156 | 125 | } |
157 | 126 |
|
158 | 127 | } |
|
0 commit comments