Skip to content

Commit 38387fd

Browse files
fix(reports): 3 audit findings — HTML leak, decimal count, empty burndown (#3665)
* fix(reports): 3 audit findings — HTML leak, decimal count, empty burndown Fixes three of the four bugs surfaced in the Reports audit. Details: ## Bug 1: Raw HTML rendered as text on /reports/project The status-report header banner was showing the literal string "Est. completion <a href='...' class='btn btn-primary'><span class="fa fa-thumb-tack"></span> Complete more To-Dos to see that!</a>" because Projects\Services\Projects::getProjectProgress() built an HTML anchor into `estimatedCompletionDate` and the Blade template rendered it via `{{ }}` (which escapes). Fix: - Service now returns plain text for the message + a new `estimatedCompletionState` field (`ready`|`needs_more_data`| `complete`) so callers can branch on intent rather than parse HTML. Language strings for the two messages moved to en-US.ini. - Template renders a proper button link based on the state instead of interpolating HTML. Existing MCP/JSON-RPC callers that already `strip_tags()` the value keep working — they see the plain text (which is what they wanted anyway). ## Bug 3: "1.00" instead of "1" in Open To-Dos card `sum_open_todos + sum_progres_todos` is a SUM of `CASE WHEN status=X THEN 1` — inherently an integer count. The template ran it through `format()->decimal()` (which is `number_format(val, 2)`), rendering the count as "1.00" — read as a broken chart value in the audit. Fix: cast to `(int)` for a count. The hour-value tiles keep the 2-decimal format since they're legitimately decimal. ## Bug 4: Sprint Burndown widget renders shell when project has no sprints The outer condition guarding the section was `@if ($allSprints !== false)`, which passes for an EMPTY array (project without sprints). So a project with no sprints rendered the title + toggle-button group + empty canvas, with the chart-init JS silently guarded off. Result: title + orphaned toggle pills, no chart body — reads as broken. Fix: tighten the outer guard to `!== false && count(...) > 0` — same check the controller uses on line 70 for `currentSprint`. No sprints = whole section hidden. ## Bug 2 (audit item — no code change, notes only) Bullet points appeared to render empty on Needs Attention + In Flight sections during the audit. On investigation this turned out to be a stale browser-cache serving an older `main.css` bundle — the current committed `main.3.9.8.min.css` already has the `.reportMilestoneList { list-style: none; }` rule, and fresh browser sessions render cleanly. Included the mix-manifest.json bump (3.9.6 → 3.9.8) alongside so the manifest is aligned with the current appVersion; downstream users won't hit stale-cache patterns after future asset rebuilds. ## Test plan - [x] Bug 1: verified in-browser — banner shows a real button link, no HTML tags as text. Confirmed via Playwright: `rawTagsPresent: false`. - [x] Bug 3: verified — "Open To-Dos" tile shows "1" not "1.00". - [x] Bug 4: verified — Sprint Burndown title/toggles/canvas all hidden on a project with no sprints. - [x] MCP tools using `strip_tags(estimatedCompletionDate)` still see readable text (no HTML to strip means plain-text passes through untouched). ## Not in this PR (audit follow-ups) - Logic Model / Impact Journey empty states could use a CTA link to the actual Board (UX polish, not a bug). - StrategyPro "difference made" lens gated with no tooltip explaining why (UX polish, not a bug). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(reports): no-data early return matches getProjectProgress() shape Copilot review on #3665: the early return taken when a project has no first ticket omitted `estimatedCompletionState` and carried a hardcoded English string. Templates default a missing state to 'ready', so a project with no data rendered as though an estimate were available. The early return now emits state 'needs_more_data' with the same i18n'd copy as the computed path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GYSPNgLdUwEnxgYqTxMc85 --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent db8fd29 commit 38387fd

5 files changed

Lines changed: 76 additions & 39 deletions

File tree

app/Domain/Projects/Services/Projects.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,16 @@ public function getProject(int $id): bool|array
134134
#[RequiresPermission(ProjectsPermissions::VIEW, projectIdParam: 'projectId')]
135135
public function getProjectProgress($projectId): array
136136
{
137-
$returnValue = ['percent' => 0, 'estimatedCompletionDate' => 'We need more data to determine that.', 'plannedCompletionDate' => ''];
137+
// Same shape as the computed return below — including
138+
// `estimatedCompletionState`. Without it the no-data early return
139+
// let templates fall back to the default 'ready' state and render
140+
// as though an estimate existed. Copy is i18n'd to match.
141+
$returnValue = [
142+
'percent' => 0,
143+
'estimatedCompletionDate' => $this->language->__('label.complete_more_todos'),
144+
'estimatedCompletionState' => 'needs_more_data',
145+
'plannedCompletionDate' => '',
146+
];
138147

139148
$averageStorySize = $this->ticketRepository->getAverageTodoSize($projectId);
140149

@@ -200,11 +209,23 @@ public function getProjectProgress($projectId): array
200209
$completionDate = $today->format($this->language->__('language.dateformat'));
201210
}
202211

203-
$returnValue = ['percent' => $finalPercent, 'estimatedCompletionDate' => $completionDate, 'plannedCompletionDate' => ''];
212+
// Return shape carries a plain-text status and a machine-readable
213+
// state — templates branch on the state to render the appropriate
214+
// CTA (e.g. a "showAll" link) instead of embedding presentation
215+
// HTML in the string. Non-template callers (MCP tools, JSON-RPC)
216+
// just read the plain text as-is.
217+
$returnValue = [
218+
'percent' => $finalPercent,
219+
'estimatedCompletionDate' => $completionDate,
220+
'estimatedCompletionState' => 'ready',
221+
'plannedCompletionDate' => '',
222+
];
204223
if ($numberOfClosedTickets < 10) {
205-
$returnValue['estimatedCompletionDate'] = "<a href='".BASE_URL."/tickets/showAll' class='btn btn-primary'><span class=\"fa fa-thumb-tack\"></span> Complete more To-Dos to see that!</a>";
224+
$returnValue['estimatedCompletionState'] = 'needs_more_data';
225+
$returnValue['estimatedCompletionDate'] = $this->language->__('label.complete_more_todos');
206226
} elseif ($finalPercent == 100) {
207-
$returnValue['estimatedCompletionDate'] = "<a href='".BASE_URL."/projects/showAll' class='btn btn-primary'><span class=\"fa fa-suitcase\"></span> This project is complete, onto the next!</a>";
227+
$returnValue['estimatedCompletionState'] = 'complete';
228+
$returnValue['estimatedCompletionDate'] = $this->language->__('label.project_complete_onto_next');
208229
}
209230

210231
return $returnValue;

app/Domain/Reports/Templates/partials/projectReportBody.blade.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323
@include('reports::partials.statusPill', ['status' => $summary->latestStatus, 'date' => $summary->latestStatusDate])
2424
<span>
2525
<strong>{{ round($summary->progress['percent'] ?? 0) }}%</strong> {{ __('label.report_complete') }}
26-
@if (!empty($summary->progress['estimatedCompletionDate']) && $summary->progress['estimatedCompletionDate'] !== false)
26+
@php $completionState = $summary->progress['estimatedCompletionState'] ?? 'ready'; @endphp
27+
@if ($completionState === 'needs_more_data')
28+
· <a href="{{ BASE_URL }}/tickets/showAll" class="btn btn-primary"><i class="fa fa-thumb-tack"></i> {{ __('label.complete_more_todos') }}</a>
29+
@elseif ($completionState === 'complete')
30+
· <a href="{{ BASE_URL }}/projects/showAll" class="btn btn-primary"><i class="fa fa-suitcase"></i> {{ __('label.project_complete_onto_next') }}</a>
31+
@elseif (!empty($summary->progress['estimatedCompletionDate']) && $summary->progress['estimatedCompletionDate'] !== false)
2732
· {{ __('label.estimated_completion') }} {{ $summary->progress['estimatedCompletionDate'] }}
2833
@endif
2934
</span>

app/Domain/Reports/Templates/show.blade.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@
6060
<div class="boxedHighlight">
6161
<span class="headline">{!! __('label.open_todos') !!}</span>
6262
<span class="value">
63+
{{-- Open To-Dos is a COUNT of tickets (SUM of CASE WHEN
64+
status = X THEN 1 in the repo), so it's inherently
65+
an integer. ->decimal() rendered "1" as "1.00" —
66+
read as a broken chart value in the audit. --}}
6367
@if ($fullReportLatest !== false)
64-
{{ format(($fullReportLatest['sum_open_todos'] + $fullReportLatest['sum_progres_todos']))->decimal() }}
68+
{{ (int) ($fullReportLatest['sum_open_todos'] + $fullReportLatest['sum_progres_todos']) }}
6569
@else
6670
{{ 0 }}
6771
@endif
@@ -72,11 +76,16 @@
7276

7377
</div>
7478

75-
@if ($allSprints !== false)
79+
{{-- Hide the whole Sprint Burndown section when the project has
80+
no sprints. Previously the outer guard was just `!== false`, so an
81+
empty array (project without sprints) rendered the title + toggle
82+
buttons + empty canvas with no chart underneath — read as broken
83+
in the audit. --}}
84+
@if ($allSprints !== false && count($allSprints) > 0)
7685
<h5 class="subtitle">{!! __('subtitles.sprint_burndown') !!}</h5>
7786
<br />
7887
<span class="pull-left">
79-
@if ($allSprints !== false && count($allSprints) > 0)
88+
@if (true)
8089
<select data-placeholder="{{ __('input.placeholders.filter_by_sprint') }}" title="{{ __('input.placeholders.filter_by_sprint') }}" name="sprint" class="mainSprintSelector" onchange="location.href='{{ BASE_URL }}/reports/show?sprint='+jQuery(this).val()" id="sprintSelect">
8190

8291
<option value="" >{!! __('input.placeholders.filter_by_sprint') !!}</option>

app/Language/en-US.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2881,6 +2881,8 @@ input.placeholders.outcome_impact = "What did completing this produce? For examp
28812881
notifications.outcome_saved = "Outcome saved"
28822882
label.report_complete = "complete"
28832883
label.estimated_completion = "Est. completion"
2884+
label.complete_more_todos = "Complete more To-Dos to see that!"
2885+
label.project_complete_onto_next = "This project is complete, onto the next!"
28842886
label.progress = "Progress"
28852887
label.goals = "Goals"
28862888
text.fed_by_n_goals = "fed by %d project goals"

public/dist/mix-manifest.json

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
{
2-
"/js/compiled-htmx.3.9.6.min.js": "/js/compiled-htmx.3.9.6.min.js",
3-
"/js/compiled-htmx-extensions.3.9.6.min.js": "/js/compiled-htmx-extensions.3.9.6.min.js",
4-
"/js/compiled-lottieplayer.3.9.6.min.js": "/js/compiled-lottieplayer.3.9.6.min.js",
5-
"/js/compiled-tiptap-editor.3.9.6.min.js": "/js/compiled-tiptap-editor.3.9.6.min.js",
6-
"/css/main.3.9.6.min.css": "/css/main.3.9.6.min.css",
2+
"/js/compiled-htmx.3.9.8.min.js": "/js/compiled-htmx.3.9.8.min.js",
3+
"/js/compiled-htmx-extensions.3.9.8.min.js": "/js/compiled-htmx-extensions.3.9.8.min.js",
4+
"/js/compiled-lottieplayer.3.9.8.min.js": "/js/compiled-lottieplayer.3.9.8.min.js",
5+
"/js/compiled-tiptap-editor.3.9.8.min.js": "/js/compiled-tiptap-editor.3.9.8.min.js",
6+
"/css/main.3.9.8.min.css": "/css/main.3.9.8.min.css",
77
"/images/chosen-sprite-light.png?6768c1976c2ad78da1634b00b1e84dc2": "/images/chosen-sprite-light.png?6768c1976c2ad78da1634b00b1e84dc2",
88
"/images/chosen-sprite-light@2x.png?a0b7f3f18d93f6730bb20aa64fb27644": "/images/chosen-sprite-light@2x.png?a0b7f3f18d93f6730bb20aa64fb27644",
9-
"/images/loading-animation.svg?ab1aba24e1bc5686efac62cba12cafb7": "/images/loading-animation.svg?ab1aba24e1bc5686efac62cba12cafb7",
109
"/images/calarrow.png?560fd036ad4b37c2d23000acc81def00": "/images/calarrow.png?560fd036ad4b37c2d23000acc81def00",
10+
"/images/loading-animation.svg?ab1aba24e1bc5686efac62cba12cafb7": "/images/loading-animation.svg?ab1aba24e1bc5686efac62cba12cafb7",
11+
"/fonts/Shantell_Sans-Informal_Regular.woff2?241fa2668a31e4eb71e8539cfe60ef4b": "/fonts/Shantell_Sans-Informal_Regular.woff2?241fa2668a31e4eb71e8539cfe60ef4b",
12+
"/fonts/Shantell_Sans-Informal_Bold_Italic.woff2?f6d317a4cc41d53053afbf0a9c9228fc": "/fonts/Shantell_Sans-Informal_Bold_Italic.woff2?f6d317a4cc41d53053afbf0a9c9228fc",
13+
"/fonts/Shantell_Sans-Informal_Bold.woff2?f8bfd61789da277fc19c1e2796ac92f3": "/fonts/Shantell_Sans-Informal_Bold.woff2?f8bfd61789da277fc19c1e2796ac92f3",
14+
"/fonts/Shantell_Sans-Informal_Regular_Italic.woff2?86c11baf018aef8712abcfb4024e5da5": "/fonts/Shantell_Sans-Informal_Regular_Italic.woff2?86c11baf018aef8712abcfb4024e5da5",
15+
"/fonts/Atkinson-Hyperlegible-Regular-102.ttf?0f70189614a5d1405a86b2f339e97711": "/fonts/Atkinson-Hyperlegible-Regular-102.ttf?0f70189614a5d1405a86b2f339e97711",
16+
"/fonts/Atkinson-Hyperlegible-Regular-102a.woff2?7572a7a55ffff1170d864220b567ca60": "/fonts/Atkinson-Hyperlegible-Regular-102a.woff2?7572a7a55ffff1170d864220b567ca60",
17+
"/fonts/Atkinson-Hyperlegible-BoldItalic-102.ttf?8bec52de3cf4d8e84edadef06c7952a6": "/fonts/Atkinson-Hyperlegible-BoldItalic-102.ttf?8bec52de3cf4d8e84edadef06c7952a6",
18+
"/fonts/Atkinson-Hyperlegible-BoldItalic-102a.woff2?eeaf9fcaaa46559f4dfb380b4553c27c": "/fonts/Atkinson-Hyperlegible-BoldItalic-102a.woff2?eeaf9fcaaa46559f4dfb380b4553c27c",
19+
"/fonts/Atkinson-Hyperlegible-Bold-102.ttf?22f63e2e2471cf7f85d279a35b461b9e": "/fonts/Atkinson-Hyperlegible-Bold-102.ttf?22f63e2e2471cf7f85d279a35b461b9e",
20+
"/fonts/Atkinson-Hyperlegible-Bold-102a.woff2?fce21dab976c619b722f82fe445590fa": "/fonts/Atkinson-Hyperlegible-Bold-102a.woff2?fce21dab976c619b722f82fe445590fa",
21+
"/fonts/Atkinson-Hyperlegible-Italic-102.ttf?9d826272a7141f284ab1916b04e3cf1b": "/fonts/Atkinson-Hyperlegible-Italic-102.ttf?9d826272a7141f284ab1916b04e3cf1b",
22+
"/fonts/Atkinson-Hyperlegible-Italic-102a.woff2?deb0b45e55a4a8d034e9085ebc7a8b8d": "/fonts/Atkinson-Hyperlegible-Italic-102a.woff2?deb0b45e55a4a8d034e9085ebc7a8b8d",
1123
"/fonts/Roboto-Medium.ttf?7c8d04cd831df3033c8a96a2668d645e": "/fonts/Roboto-Medium.ttf?7c8d04cd831df3033c8a96a2668d645e",
1224
"/fonts/Roboto-Medium.woff2?42b381e5d446014a66b3c223a551ee26": "/fonts/Roboto-Medium.woff2?42b381e5d446014a66b3c223a551ee26",
1325
"/fonts/Roboto-Italic.ttf?87f3afe16a8c3c3706340b027aa43a2e": "/fonts/Roboto-Italic.ttf?87f3afe16a8c3c3706340b027aa43a2e",
@@ -20,18 +32,6 @@
2032
"/fonts/Roboto-LightItalic.woff2?190334d82bbe926404654db5b272b2a1": "/fonts/Roboto-LightItalic.woff2?190334d82bbe926404654db5b272b2a1",
2133
"/fonts/Roboto-MediumItalic.ttf?82736aaa11c64709055f2b7f1c1dcb0f": "/fonts/Roboto-MediumItalic.ttf?82736aaa11c64709055f2b7f1c1dcb0f",
2234
"/fonts/Roboto-MediumItalic.woff2?506a1f8a1053d4f4fdb2479ad4955db3": "/fonts/Roboto-MediumItalic.woff2?506a1f8a1053d4f4fdb2479ad4955db3",
23-
"/fonts/Atkinson-Hyperlegible-Regular-102.ttf?0f70189614a5d1405a86b2f339e97711": "/fonts/Atkinson-Hyperlegible-Regular-102.ttf?0f70189614a5d1405a86b2f339e97711",
24-
"/fonts/Atkinson-Hyperlegible-Regular-102a.woff2?7572a7a55ffff1170d864220b567ca60": "/fonts/Atkinson-Hyperlegible-Regular-102a.woff2?7572a7a55ffff1170d864220b567ca60",
25-
"/fonts/Atkinson-Hyperlegible-BoldItalic-102.ttf?8bec52de3cf4d8e84edadef06c7952a6": "/fonts/Atkinson-Hyperlegible-BoldItalic-102.ttf?8bec52de3cf4d8e84edadef06c7952a6",
26-
"/fonts/Atkinson-Hyperlegible-BoldItalic-102a.woff2?eeaf9fcaaa46559f4dfb380b4553c27c": "/fonts/Atkinson-Hyperlegible-BoldItalic-102a.woff2?eeaf9fcaaa46559f4dfb380b4553c27c",
27-
"/fonts/Atkinson-Hyperlegible-Bold-102.ttf?22f63e2e2471cf7f85d279a35b461b9e": "/fonts/Atkinson-Hyperlegible-Bold-102.ttf?22f63e2e2471cf7f85d279a35b461b9e",
28-
"/fonts/Atkinson-Hyperlegible-Bold-102a.woff2?fce21dab976c619b722f82fe445590fa": "/fonts/Atkinson-Hyperlegible-Bold-102a.woff2?fce21dab976c619b722f82fe445590fa",
29-
"/fonts/Atkinson-Hyperlegible-Italic-102.ttf?9d826272a7141f284ab1916b04e3cf1b": "/fonts/Atkinson-Hyperlegible-Italic-102.ttf?9d826272a7141f284ab1916b04e3cf1b",
30-
"/fonts/Atkinson-Hyperlegible-Italic-102a.woff2?deb0b45e55a4a8d034e9085ebc7a8b8d": "/fonts/Atkinson-Hyperlegible-Italic-102a.woff2?deb0b45e55a4a8d034e9085ebc7a8b8d",
31-
"/fonts/Shantell_Sans-Informal_Regular.woff2?241fa2668a31e4eb71e8539cfe60ef4b": "/fonts/Shantell_Sans-Informal_Regular.woff2?241fa2668a31e4eb71e8539cfe60ef4b",
32-
"/fonts/Shantell_Sans-Informal_Bold_Italic.woff2?f6d317a4cc41d53053afbf0a9c9228fc": "/fonts/Shantell_Sans-Informal_Bold_Italic.woff2?f6d317a4cc41d53053afbf0a9c9228fc",
33-
"/fonts/Shantell_Sans-Informal_Bold.woff2?f8bfd61789da277fc19c1e2796ac92f3": "/fonts/Shantell_Sans-Informal_Bold.woff2?f8bfd61789da277fc19c1e2796ac92f3",
34-
"/fonts/Shantell_Sans-Informal_Regular_Italic.woff2?86c11baf018aef8712abcfb4024e5da5": "/fonts/Shantell_Sans-Informal_Regular_Italic.woff2?86c11baf018aef8712abcfb4024e5da5",
3535
"/images/32px.png?7b8ef9809145cfec0aa699bf38d0ed96": "/images/32px.png?7b8ef9809145cfec0aa699bf38d0ed96",
3636
"/images/throbber.gif?f3bc149017432b87da2e4112539c4549": "/images/throbber.gif?f3bc149017432b87da2e4112539c4549",
3737
"/images/40px.png?106a7abc109fb5e787427a83e56d4336": "/images/40px.png?106a7abc109fb5e787427a83e56d4336",
@@ -43,21 +43,21 @@
4343
"/fonts/fa-solid-900.ttf?b48ad290d0335879a92bb6a7e8e08976": "/fonts/fa-solid-900.ttf?b48ad290d0335879a92bb6a7e8e08976",
4444
"/fonts/fa-v4compatibility.woff2?745989aab0d69cab7e70bfcc96207b3d": "/fonts/fa-v4compatibility.woff2?745989aab0d69cab7e70bfcc96207b3d",
4545
"/fonts/fa-v4compatibility.ttf?f601162ae669f88823a32a6928d1a528": "/fonts/fa-v4compatibility.ttf?f601162ae669f88823a32a6928d1a528",
46-
"/css/app.3.9.6.min.css": "/css/app.3.9.6.min.css",
47-
"/js/compiled-footer.3.9.6.min.js": "/js/compiled-footer.3.9.6.min.js",
46+
"/css/app.3.9.8.min.css": "/css/app.3.9.8.min.css",
47+
"/js/compiled-footer.3.9.8.min.js": "/js/compiled-footer.3.9.8.min.js",
4848
"/js/html2canvas.min.js": "/js/html2canvas.min.js",
4949
"/js/jspdf.umd.min.js": "/js/jspdf.umd.min.js",
50-
"/js/compiled-app.3.9.6.min.js": "/js/compiled-app.3.9.6.min.js",
51-
"/js/compiled-frameworks.3.9.6.min.js": "/js/compiled-frameworks.3.9.6.min.js",
52-
"/js/compiled-framework-plugins.3.9.6.min.js": "/js/compiled-framework-plugins.3.9.6.min.js",
53-
"/js/compiled-global-component.3.9.6.min.js": "/js/compiled-global-component.3.9.6.min.js",
54-
"/js/compiled-calendar-component.3.9.6.min.js": "/js/compiled-calendar-component.3.9.6.min.js",
55-
"/js/compiled-table-component.3.9.6.min.js": "/js/compiled-table-component.3.9.6.min.js",
56-
"/js/compiled-tiptap-toolbar.3.9.6.min.js": "/js/compiled-tiptap-toolbar.3.9.6.min.js",
57-
"/js/compiled-tiptap-tests.3.9.6.min.js": "/js/compiled-tiptap-tests.3.9.6.min.js",
58-
"/js/compiled-gantt-component.3.9.6.min.js": "/js/compiled-gantt-component.3.9.6.min.js",
59-
"/js/compiled-chart-component.3.9.6.min.js": "/js/compiled-chart-component.3.9.6.min.js",
60-
"/css/tiptap-editor.3.9.6.min.css": "/css/tiptap-editor.3.9.6.min.css",
50+
"/js/compiled-app.3.9.8.min.js": "/js/compiled-app.3.9.8.min.js",
51+
"/js/compiled-frameworks.3.9.8.min.js": "/js/compiled-frameworks.3.9.8.min.js",
52+
"/js/compiled-framework-plugins.3.9.8.min.js": "/js/compiled-framework-plugins.3.9.8.min.js",
53+
"/js/compiled-global-component.3.9.8.min.js": "/js/compiled-global-component.3.9.8.min.js",
54+
"/js/compiled-calendar-component.3.9.8.min.js": "/js/compiled-calendar-component.3.9.8.min.js",
55+
"/js/compiled-table-component.3.9.8.min.js": "/js/compiled-table-component.3.9.8.min.js",
56+
"/js/compiled-tiptap-toolbar.3.9.8.min.js": "/js/compiled-tiptap-toolbar.3.9.8.min.js",
57+
"/js/compiled-tiptap-tests.3.9.8.min.js": "/js/compiled-tiptap-tests.3.9.8.min.js",
58+
"/js/compiled-gantt-component.3.9.8.min.js": "/js/compiled-gantt-component.3.9.8.min.js",
59+
"/js/compiled-chart-component.3.9.8.min.js": "/js/compiled-chart-component.3.9.8.min.js",
60+
"/css/tiptap-editor.3.9.8.min.css": "/css/tiptap-editor.3.9.8.min.css",
6161
"/images/03-1.png": "/images/03-1.png",
6262
"/images/32px.png": "/images/32px.png",
6363
"/images/40px.png": "/images/40px.png",

0 commit comments

Comments
 (0)