domma-cms 0.76.0 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -1
- package/admin/js/api.js +1 -1
- package/admin/js/app.js +2 -2
- package/admin/js/lib/action-editor-arrange.js +1 -0
- package/admin/js/lib/api-endpoint-editor-arrange.js +2 -0
- package/admin/js/lib/block-editor-arrange.js +2 -0
- package/admin/js/lib/collection-editor-arrange.js +3 -0
- package/admin/js/lib/collection-entries-arrange.js +1 -0
- package/admin/js/lib/component-editor-arrange.js +27 -0
- package/admin/js/lib/context-menu-editor-arrange.js +1 -0
- package/admin/js/lib/dashboard-arrange.js +1 -0
- package/admin/js/lib/form-editor-arrange.js +1 -0
- package/admin/js/lib/form-submissions-arrange.js +2 -0
- package/admin/js/lib/menu-editor-arrange.js +2 -0
- package/admin/js/lib/page-editor-arrange.js +1 -0
- package/admin/js/lib/plugin-code-arrange.js +1 -0
- package/admin/js/lib/project-page-arrange.js +1 -0
- package/admin/js/lib/role-editor-arrange.js +3 -0
- package/admin/js/lib/user-editor-arrange.js +1 -0
- package/admin/js/lib/view-editor-arrange.js +14 -0
- package/admin/js/templates/action-editor.html +223 -147
- package/admin/js/templates/api-endpoint-editor.html +172 -117
- package/admin/js/templates/block-editor.html +194 -203
- package/admin/js/templates/collection-editor.html +191 -113
- package/admin/js/templates/collection-entries.html +99 -36
- package/admin/js/templates/component-editor.html +128 -126
- package/admin/js/templates/context-menu-editor.html +208 -148
- package/admin/js/templates/dashboard.html +184 -22
- package/admin/js/templates/form-editor.html +41 -26
- package/admin/js/templates/form-submissions.html +78 -26
- package/admin/js/templates/menu-editor.html +57 -17
- package/admin/js/templates/menu-locations.html +54 -11
- package/admin/js/templates/page-editor.html +47 -26
- package/admin/js/templates/plugin-code.html +91 -73
- package/admin/js/templates/project-detail.html +83 -145
- package/admin/js/templates/project-settings.html +88 -53
- package/admin/js/templates/role-editor.html +158 -83
- package/admin/js/templates/user-editor.html +150 -14
- package/admin/js/templates/view-editor.html +203 -180
- package/admin/js/templates/view-preview.html +45 -45
- package/admin/js/views/action-editor.js +7 -1
- package/admin/js/views/api-endpoint-editor.js +2 -3
- package/admin/js/views/block-editor.js +14 -8
- package/admin/js/views/collection-editor.js +64 -5
- package/admin/js/views/collection-entries.js +50 -1
- package/admin/js/views/component-editor.js +2 -28
- package/admin/js/views/context-menu-editor.js +54 -55
- package/admin/js/views/dashboard.js +7 -1
- package/admin/js/views/form-editor.js +7 -7
- package/admin/js/views/form-submissions.js +11 -1
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/login.js +2 -2
- package/admin/js/views/menu-editor.js +21 -43
- package/admin/js/views/menu-locations.js +16 -1
- package/admin/js/views/page-editor.js +26 -26
- package/admin/js/views/plugin-code.js +23 -4
- package/admin/js/views/project-detail.js +9 -1
- package/admin/js/views/project-settings.js +1 -1
- package/admin/js/views/role-editor.js +11 -3
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/view-editor.js +1 -1
- package/admin/js/views/view-preview.js +1 -1
- package/package.json +1 -1
- package/server/routes/api/dashboard.js +32 -4
- package/server/routes/api/forms.js +104 -13
- package/server/routes/api/users.js +12 -2
- package/server/routes/api/views.js +55 -1
- package/server/services/components.js +9 -0
- package/server/services/users.js +2 -2
- package/server/services/views.js +14 -0
- package/admin/js/templates/dashboard/activity-feed.html +0 -3
- package/admin/js/templates/dashboard/cache.html +0 -32
- package/admin/js/templates/dashboard/health-detail.html +0 -2
- package/admin/js/templates/dashboard/journeys.html +0 -17
- package/admin/js/templates/dashboard/kpi-strip.html +0 -34
- package/admin/js/templates/dashboard/spike-feed.html +0 -3
- package/admin/js/templates/dashboard/top-pages.html +0 -3
- package/admin/js/templates/dashboard/traffic-chart.html +0 -3
- package/admin/js/views/block-editor-enhance.js +0 -1
- package/admin/js/views/dashboard/lib/escape.js +0 -1
- package/admin/js/views/dashboard/widgets/activity-feed.js +0 -1
- package/admin/js/views/dashboard/widgets/cache.js +0 -1
- package/admin/js/views/dashboard/widgets/health-detail.js +0 -1
- package/admin/js/views/dashboard/widgets/journeys.js +0 -1
- package/admin/js/views/dashboard/widgets/kpi-strip.js +0 -1
- package/admin/js/views/dashboard/widgets/spike-feed.js +0 -6
- package/admin/js/views/dashboard/widgets/top-pages.js +0 -1
- package/admin/js/views/dashboard/widgets/traffic-chart.js +0 -1
|
@@ -1,72 +1,87 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
<!-- API Builder - endpoint editor. See admin/js/views/api-endpoint-editor.js. No page heading: the Tool banner
|
|
2
|
+
("API Builder › <endpoint>") is the heading, with All endpoints and Save in it. Parts are bound with
|
|
3
|
+
M.applyBindings - never the Query panel, whose hints show {{params.x}} literally. #endpoint-project and
|
|
4
|
+
#ep-editor-tabs are relied on by app.js (?project= pre-fill) and admin.css (full-width view). -->
|
|
5
|
+
<div class="epx">
|
|
6
|
+
<div class="epx-bar" id="ep-bar" data-bind-hidden="!dirty.value">
|
|
7
|
+
<span class="epx-chip is-warn">Unsaved</span>
|
|
8
|
+
<span class="epx-bar-text" data-bind-text="barText.value"></span>
|
|
9
|
+
<span class="epx-spacer"></span>
|
|
10
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="discard">Discard</button>
|
|
11
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="saving.value">
|
|
12
|
+
<span data-icon="save" data-icon-size="13"></span> Save</button>
|
|
6
13
|
</div>
|
|
7
|
-
</div>
|
|
8
14
|
|
|
9
|
-
<div class="ep-editor-grid">
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
<div class="ep-editor-grid">
|
|
16
|
+
<div>
|
|
17
|
+
<div class="tabs" id="ep-editor-tabs">
|
|
18
|
+
<div class="tab-list">
|
|
19
|
+
<button class="tab-item active">Definition <span class="epx-dot" id="ep-def-dot" hidden></span></button>
|
|
20
|
+
<button class="tab-item">Query <span class="epx-dot" id="ep-query-dot" hidden></span></button>
|
|
21
|
+
<button class="tab-item">Response fields</button>
|
|
22
|
+
</div>
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<div class="card-body">
|
|
24
|
+
<div class="tab-panel active" id="ep-def-panel">
|
|
25
|
+
<div class="epx-card">
|
|
21
26
|
<div class="form-group">
|
|
22
|
-
<label class="form-label" for="ep-name">Name
|
|
23
|
-
|
|
27
|
+
<label class="form-label" for="ep-name">Name
|
|
28
|
+
<span data-help="For you and your team - shown in the API Builder list. Callers never see it."></span></label>
|
|
29
|
+
<input type="text" class="form-input" id="ep-name" placeholder="e.g. Fixtures by day" maxlength="120">
|
|
30
|
+
<small class="epx-err" data-bind-hidden="!err.value.name" data-bind-text="err.value.name"></small>
|
|
24
31
|
</div>
|
|
25
32
|
<div class="form-group">
|
|
26
|
-
<label class="form-label" for="endpoint-project">Project
|
|
33
|
+
<label class="form-label" for="endpoint-project">Project
|
|
34
|
+
<span data-help="The first part of the address, after /api/x/. It is the endpoint's namespace, so it cannot change once saved. The endpoint may only expose collections from this project or Core."></span></label>
|
|
27
35
|
<select class="form-input" id="endpoint-project"></select>
|
|
28
|
-
<
|
|
36
|
+
<small class="epx-err" data-bind-hidden="!err.value.project" data-bind-text="err.value.project"></small>
|
|
29
37
|
</div>
|
|
30
38
|
<div class="form-group">
|
|
31
|
-
<label class="form-label" for="ep-path">Path
|
|
32
|
-
|
|
33
|
-
<
|
|
39
|
+
<label class="form-label" for="ep-path">Path
|
|
40
|
+
<span data-help-title="Path" data-help="Lowercase letters, numbers and hyphens, one segment at a time, or :name for a value the caller supplies (/fixtures-day/:date). Two endpoints in a project cannot have the same shape - /a/:x and /a/:y clash."></span></label>
|
|
41
|
+
<input type="text" class="form-input font-mono" id="ep-path" placeholder="/fixtures-day/:date">
|
|
42
|
+
<small class="epx-err" data-bind-hidden="!pathErr.value" data-bind-text="pathErr.value"></small>
|
|
43
|
+
<small class="epx-hint">Full address: <code id="ep-url-preview">/api/x/…</code></small>
|
|
34
44
|
</div>
|
|
35
45
|
<div class="form-group">
|
|
36
|
-
<label class="form-label" for="ep-collection">Collection
|
|
46
|
+
<label class="form-label" for="ep-collection">Collection
|
|
47
|
+
<span data-help="Where the answers come from. Only collections in this project or Core are offered; system collections (users, tokens…) can never be exposed."></span></label>
|
|
37
48
|
<select class="form-input" id="ep-collection"></select>
|
|
49
|
+
<small class="epx-err" data-bind-hidden="!err.value.collection" data-bind-text="err.value.collection"></small>
|
|
38
50
|
</div>
|
|
39
|
-
<div
|
|
51
|
+
<div class="epx-grid2">
|
|
40
52
|
<div class="form-group">
|
|
41
|
-
<label class="form-label" for="ep-auth">Access
|
|
53
|
+
<label class="form-label" for="ep-auth">Access
|
|
54
|
+
<span data-help-title="Access" data-help="Public: anyone. Token: only a project API token (System › API Tokens) for this project - never a signed-in session. A role: a signed-in user holding that role or a more senior one."></span></label>
|
|
42
55
|
<select class="form-input" id="ep-auth"></select>
|
|
43
56
|
</div>
|
|
44
57
|
<div class="form-group">
|
|
45
|
-
<label class="form-label" for="ep-mode">Mode
|
|
58
|
+
<label class="form-label" for="ep-mode">Mode
|
|
59
|
+
<span data-help="List answers an array of entries. Single answers the first match, or 404 when there is none - for /thing/:id style addresses."></span></label>
|
|
46
60
|
<select class="form-input" id="ep-mode">
|
|
47
61
|
<option value="list">List - array of entries</option>
|
|
48
62
|
<option value="single">Single - first match or 404</option>
|
|
49
63
|
</select>
|
|
50
64
|
</div>
|
|
51
65
|
</div>
|
|
52
|
-
<
|
|
53
|
-
<
|
|
54
|
-
|
|
55
|
-
|
|
66
|
+
<div class="epx-setting">
|
|
67
|
+
<label class="form-label" for="ep-enabled">Enabled
|
|
68
|
+
<span data-help="Off answers 404 to every caller, as if the endpoint did not exist. The definition is kept."></span></label>
|
|
69
|
+
<input type="checkbox" class="form-switch" id="ep-enabled" checked>
|
|
70
|
+
</div>
|
|
56
71
|
</div>
|
|
57
72
|
</div>
|
|
58
|
-
</div>
|
|
59
73
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<div id="ep-filter-rows"></div>
|
|
68
|
-
<p class="
|
|
69
|
-
<
|
|
74
|
+
<div class="tab-panel">
|
|
75
|
+
<div class="epx-card">
|
|
76
|
+
<div class="epx-card-title">Filters
|
|
77
|
+
<span data-help-title="Filters" data-help="Every filter must match. A value can be a literal, {{params.name}} (from a :name segment - required) or {{query.name}} (from ?name= - optional: the filter is dropped when the caller leaves it out). Right-click a filter (or ⋮) to move, duplicate or remove it."></span>
|
|
78
|
+
<span class="epx-spacer"></span>
|
|
79
|
+
<button type="button" class="btn btn-sm btn-ghost" id="ep-add-filter"><span data-icon="plus" data-icon-size="13"></span> Add filter</button>
|
|
80
|
+
</div>
|
|
81
|
+
<div id="ep-filter-rows" class="epx-list"></div>
|
|
82
|
+
<p class="epx-note" id="ep-filter-empty">No filters - every entry matches.</p>
|
|
83
|
+
<small class="epx-err" id="ep-filter-err" hidden></small>
|
|
84
|
+
<div class="epx-grid3">
|
|
70
85
|
<div class="form-group">
|
|
71
86
|
<label class="form-label" for="ep-sort">Sort field</label>
|
|
72
87
|
<select class="form-input" id="ep-sort"></select>
|
|
@@ -79,99 +94,139 @@
|
|
|
79
94
|
</select>
|
|
80
95
|
</div>
|
|
81
96
|
<div class="form-group">
|
|
82
|
-
<label class="form-label" for="ep-limit">Limit
|
|
97
|
+
<label class="form-label" for="ep-limit">Limit
|
|
98
|
+
<span data-help="At most this many entries per answer (0 = no limit, up to 500). A caller may ask for fewer with ?limit=, never more."></span></label>
|
|
83
99
|
<input type="number" class="form-input" id="ep-limit" min="0" max="500" value="50">
|
|
100
|
+
<small class="epx-err" id="ep-limit-err" hidden></small>
|
|
84
101
|
</div>
|
|
85
102
|
</div>
|
|
86
|
-
<p class="text-muted" style="font-size:.8rem;margin:0;">Limit 0 = no limit.</p>
|
|
87
103
|
</div>
|
|
88
104
|
</div>
|
|
89
|
-
</div>
|
|
90
105
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
106
|
+
<div class="tab-panel">
|
|
107
|
+
<div class="epx-card">
|
|
108
|
+
<div class="epx-card-title">Response fields
|
|
109
|
+
<span data-help-title="Response fields" data-help="Tick the fields callers get back - none ticked returns every field. Anything not ticked cannot be read or filtered on through this endpoint. Right-click the list (or ⋮) to tick all, none, or invert."></span>
|
|
110
|
+
<span class="epx-spacer"></span>
|
|
111
|
+
<button type="button" class="epx-kebab" id="ep-fields-more" aria-label="Field actions" title="Actions">⋮</button>
|
|
112
|
+
</div>
|
|
113
|
+
<div id="ep-fields-list" class="epx-fields" tabindex="0"></div>
|
|
114
|
+
<p class="epx-note" id="ep-fields-note"></p>
|
|
97
115
|
</div>
|
|
98
116
|
</div>
|
|
99
117
|
</div>
|
|
100
118
|
</div>
|
|
101
|
-
</div>
|
|
102
119
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<div id="tryit-dirty-note" class="text-muted" style="display:none;font-size:.85rem;margin-bottom:.75rem;">
|
|
111
|
-
<span data-icon="info"></span> Save to test your changes.
|
|
112
|
-
</div>
|
|
113
|
-
<div id="tryit-params"></div>
|
|
114
|
-
<div id="tryit-query-params"></div>
|
|
115
|
-
<div class="form-group" id="tryit-token-group" style="display:none;">
|
|
116
|
-
<label class="form-label" for="tryit-token">API token</label>
|
|
117
|
-
<input type="text" class="form-input" id="tryit-token" placeholder="dcms_…">
|
|
118
|
-
</div>
|
|
119
|
-
<div class="form-group">
|
|
120
|
-
<label class="form-label" for="tryit-query">Extra query string (optional)</label>
|
|
121
|
-
<input type="text" class="form-input" id="tryit-query" placeholder="nation=France&status=published">
|
|
122
|
-
<p class="text-muted" style="font-size:.8rem;margin:.25rem 0 0;">Applied as extra filters <em>on top of</em> the definition's own filters (which always win). Only fields this endpoint returns can be filtered; operators work too - e.g. <code>title_contains=cup</code>. <code>page</code>, <code>limit</code>, <code>sort</code> and <code>order</code> control pagination/sort instead (<code>limit</code> is capped at the endpoint's own limit); <code>search</code> is reserved.</p>
|
|
123
|
-
</div>
|
|
124
|
-
<button class="btn btn-primary" id="tryit-send" style="width:100%;"><span data-icon="play"></span> Send</button>
|
|
125
|
-
<div id="tryit-result" style="display:none;margin-top:.75rem;">
|
|
126
|
-
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:.4rem;">
|
|
127
|
-
<span class="form-label" style="margin:0;">Request</span>
|
|
128
|
-
<button class="btn btn-sm btn-ghost" id="tryit-copy-curl" data-tooltip="Copy as curl"><span data-icon="copy"></span> Copy curl</button>
|
|
120
|
+
<div class="ep-tryit-col">
|
|
121
|
+
<div class="epx-card">
|
|
122
|
+
<div class="epx-card-title"><span data-icon="zap" data-icon-size="15"></span> Try it
|
|
123
|
+
<span data-help-title="Try it" data-help="Calls the SAVED endpoint exactly as an outside caller would - no admin sign-in is sent, so what you see is what they get. Ctrl+Enter sends. Unsaved changes are not tested until you save."></span></div>
|
|
124
|
+
<div id="tryit-dirty-note" class="epx-alert" style="display:none;">
|
|
125
|
+
<span>Save to test your changes.</span>
|
|
126
|
+
<button type="button" class="btn btn-sm btn-primary" id="tryit-save-send">Save and send</button>
|
|
129
127
|
</div>
|
|
130
|
-
<
|
|
131
|
-
|
|
132
|
-
<div style="display:
|
|
133
|
-
<
|
|
134
|
-
|
|
128
|
+
<div id="tryit-params"></div>
|
|
129
|
+
<div id="tryit-query-params"></div>
|
|
130
|
+
<div class="form-group" id="tryit-token-group" style="display:none;">
|
|
131
|
+
<label class="form-label" for="tryit-token">API token
|
|
132
|
+
<span data-help="A dcms_… token for this endpoint's project. Used for this request only - never stored, and not kept in the history."></span></label>
|
|
133
|
+
<input type="password" class="form-input font-mono" id="tryit-token" placeholder="dcms_…" autocomplete="new-password">
|
|
135
134
|
</div>
|
|
136
|
-
<div
|
|
137
|
-
<
|
|
138
|
-
|
|
135
|
+
<div class="form-group">
|
|
136
|
+
<label class="form-label" for="tryit-query">Extra query string
|
|
137
|
+
<span data-help-title="Extra query string" data-help="Added as filters on top of the definition's own (which always win). Only fields this endpoint returns can be filtered; operators work too - title_contains=cup. page, limit, sort and order page and sort instead (limit is capped at the endpoint's own); search is reserved."></span></label>
|
|
138
|
+
<input type="text" class="form-input font-mono" id="tryit-query" placeholder="nation=France&status=published">
|
|
139
|
+
</div>
|
|
140
|
+
<button type="button" class="btn btn-primary epx-wide" id="tryit-send"><span data-icon="play" data-icon-size="13"></span> Send</button>
|
|
141
|
+
<div id="tryit-result" style="display:none;">
|
|
142
|
+
<div class="epx-subhead"><span class="form-label">Request</span>
|
|
143
|
+
<button type="button" class="btn btn-sm btn-ghost" id="tryit-copy-curl"><span data-icon="copy" data-icon-size="13"></span> Copy curl</button></div>
|
|
144
|
+
<pre id="tryit-curl" class="epx-pre"></pre>
|
|
145
|
+
<div class="epx-subhead"><span class="form-label">Response</span>
|
|
146
|
+
<span id="tryit-status" class="epx-chip">-</span></div>
|
|
147
|
+
<div id="tryit-headers-group">
|
|
148
|
+
<p class="epx-mini">Headers</p>
|
|
149
|
+
<pre id="tryit-headers" class="epx-pre"></pre>
|
|
150
|
+
</div>
|
|
139
151
|
</div>
|
|
140
152
|
</div>
|
|
141
153
|
</div>
|
|
142
|
-
</div>
|
|
143
|
-
</div>
|
|
144
154
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
<
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
<
|
|
157
|
-
<button class="btn btn-sm btn-ghost" id="tryit-body-copy" data-tooltip="Copy body"><span data-icon="copy"></span></button>
|
|
155
|
+
<div class="ep-results-col">
|
|
156
|
+
<div class="epx-card" id="tryit-results-placeholder">
|
|
157
|
+
<p class="epx-note epx-center"><span data-icon="zap" data-icon-size="20"></span><br>Send a request to see the response here.</p>
|
|
158
|
+
</div>
|
|
159
|
+
<div class="epx-card" id="tryit-response-card" style="display:none;">
|
|
160
|
+
<div class="epx-card-title"><span data-icon="code" data-icon-size="15"></span> Response body
|
|
161
|
+
<span class="epx-spacer"></span>
|
|
162
|
+
<button type="button" class="btn btn-sm btn-ghost" id="tryit-json-toggle">Raw</button>
|
|
163
|
+
<button type="button" class="btn btn-sm btn-ghost" id="tryit-body-copy" title="Copy the body" aria-label="Copy the body"><span data-icon="copy" data-icon-size="13"></span></button>
|
|
164
|
+
</div>
|
|
165
|
+
<div id="tryit-json" class="epx-json"></div>
|
|
166
|
+
<pre id="tryit-body" class="epx-pre epx-tall" style="display:none;"></pre>
|
|
158
167
|
</div>
|
|
159
|
-
</div>
|
|
160
|
-
<div class="card-body" style="padding-top:.5rem;">
|
|
161
|
-
<div id="tryit-json" style="max-height:460px;overflow:auto;font-family:var(--dm-font-mono,ui-monospace,monospace);font-size:.8rem;line-height:1.5;padding:.6rem;"></div>
|
|
162
|
-
<pre id="tryit-body" style="display:none;max-height:460px;overflow:auto;font-size:.8rem;padding:.6rem;margin:0;white-space:pre-wrap;word-break:break-word;"></pre>
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
168
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
169
|
+
<div class="epx-card" id="tryit-history-card" style="display:none;">
|
|
170
|
+
<div class="epx-card-title"><span data-icon="clock" data-icon-size="15"></span> Test history
|
|
171
|
+
<span data-help="The last requests you sent from this editor, kept in this browser (never a token). Click one to run it again; right-click (or ⋮) to copy its address or remove it."></span>
|
|
172
|
+
<span class="epx-spacer"></span>
|
|
173
|
+
<button type="button" class="btn btn-sm btn-ghost" id="tryit-history-clear" title="Clear the history" aria-label="Clear the history"><span data-icon="trash" data-icon-size="13"></span></button>
|
|
174
|
+
</div>
|
|
175
|
+
<div id="tryit-history-list" class="epx-list"></div>
|
|
176
|
+
</div>
|
|
174
177
|
</div>
|
|
175
178
|
</div>
|
|
176
|
-
</div>
|
|
177
179
|
</div>
|
|
180
|
+
|
|
181
|
+
<style>
|
|
182
|
+
.epx { display: flex; flex-direction: column; gap: .75rem; }
|
|
183
|
+
.epx [hidden] { display: none !important; }
|
|
184
|
+
.epx-bar { display: flex; align-items: center; gap: .5rem; padding: .5rem .75rem; border-radius: var(--dm-radius-md);
|
|
185
|
+
background: color-mix(in srgb, var(--dm-warning) 12%, transparent); position: sticky; top: 0; z-index: 5; }
|
|
186
|
+
.epx-bar-text { color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
187
|
+
.epx-spacer { flex: 1; }
|
|
188
|
+
.epx-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .75rem .9rem; display: flex; flex-direction: column;
|
|
189
|
+
gap: .6rem; margin-bottom: .75rem; background: var(--dm-surface); }
|
|
190
|
+
.epx-card-title { display: flex; align-items: center; gap: .35rem; font-weight: 600; }
|
|
191
|
+
.epx-card-title .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
192
|
+
.epx-card .form-group { margin: 0; }
|
|
193
|
+
.epx .form-label { display: flex; align-items: center; gap: .3rem; }
|
|
194
|
+
.epx-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: .75rem; }
|
|
195
|
+
.epx-grid3 { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: .75rem; margin-top: .25rem; }
|
|
196
|
+
.epx-setting { display: flex; align-items: center; justify-content: space-between; gap: .75rem; padding-top: .6rem; border-top: 1px solid var(--dm-border); }
|
|
197
|
+
.epx-setting .form-label { margin: 0; }
|
|
198
|
+
.epx-err { display: block; color: var(--dm-danger); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
199
|
+
.epx-hint { display: block; color: var(--dm-text-muted); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
200
|
+
.epx-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
201
|
+
.epx-center { text-align: center; padding: 1.5rem 0; }
|
|
202
|
+
.epx-mini { margin: 0 0 .2rem; color: var(--dm-text-muted); font-size: var(--dm-text-xs); text-transform: uppercase; letter-spacing: .03em; }
|
|
203
|
+
.epx-alert { display: flex; align-items: center; gap: .5rem; justify-content: space-between; padding: .45rem .6rem; border-radius: var(--dm-radius-sm);
|
|
204
|
+
background: color-mix(in srgb, var(--dm-warning) 12%, transparent); font-size: var(--dm-text-sm); }
|
|
205
|
+
.epx-dot { display: inline-block; width: .45rem; height: .45rem; border-radius: 50%; background: var(--dm-warning); margin-left: .25rem; vertical-align: middle; }
|
|
206
|
+
.epx-list { display: flex; flex-direction: column; gap: .35rem; }
|
|
207
|
+
.epx-frow { display: grid; grid-template-columns: 2fr 1.2fr 2fr auto; gap: .5rem; align-items: center; border-radius: var(--dm-radius-sm); }
|
|
208
|
+
.epx-frow:focus-within, .epx-frow:focus-visible { outline: none; box-shadow: 0 0 0 1px var(--dm-border); }
|
|
209
|
+
.epx-kebab { border: 0; background: none; cursor: pointer; font-size: var(--dm-text-lg); color: var(--dm-text-muted); border-radius: var(--dm-radius-sm); padding: 0 .3rem; line-height: 1; }
|
|
210
|
+
.epx-kebab:hover { color: var(--dm-primary); }
|
|
211
|
+
.epx-fields { display: flex; flex-wrap: wrap; gap: .4rem 1.1rem; outline: none; }
|
|
212
|
+
.epx-fields label { display: inline-flex; align-items: center; gap: .35rem; cursor: pointer; font-size: var(--dm-text-sm); }
|
|
213
|
+
.epx-chip { display: inline-flex; align-items: center; font-size: var(--dm-text-xs); font-weight: 600; padding: .1rem .5rem; border-radius: 999px; white-space: nowrap;
|
|
214
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
215
|
+
.epx-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
216
|
+
.epx-chip.is-warn { background: color-mix(in srgb, var(--dm-warning) 18%, transparent); color: var(--dm-warning); }
|
|
217
|
+
.epx-chip.is-danger { background: color-mix(in srgb, var(--dm-danger) 16%, transparent); color: var(--dm-danger); }
|
|
218
|
+
.epx-subhead { display: flex; align-items: center; justify-content: space-between; margin: .6rem 0 .3rem; }
|
|
219
|
+
.epx-subhead .form-label { margin: 0; }
|
|
220
|
+
.epx-subhead .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
221
|
+
.epx-pre { max-height: 180px; overflow: auto; font-size: var(--dm-text-xs); padding: .6rem; margin: 0; white-space: pre-wrap; word-break: break-all;
|
|
222
|
+
background: var(--dm-surface-raised, var(--dm-background)); border: 1px solid var(--dm-border); border-radius: var(--dm-radius-sm); color: var(--dm-text); }
|
|
223
|
+
.epx-tall { max-height: 460px; }
|
|
224
|
+
.epx-json { max-height: 460px; overflow: auto; font-family: var(--dm-font-mono, ui-monospace, monospace); font-size: var(--dm-text-xs); line-height: 1.5; padding: .6rem;
|
|
225
|
+
background: var(--dm-surface-raised, var(--dm-background)); border: 1px solid var(--dm-border); border-radius: var(--dm-radius-sm); }
|
|
226
|
+
.epx-wide { width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: .3rem; }
|
|
227
|
+
.epx-hrow { display: flex; align-items: center; gap: .5rem; width: 100%; text-align: left; border: 0; background: none; cursor: pointer; color: var(--dm-text);
|
|
228
|
+
font-family: var(--dm-font-mono, monospace); font-size: var(--dm-text-xs); padding: .35rem .45rem; border-radius: var(--dm-radius-sm); }
|
|
229
|
+
.epx-hrow:hover, .epx-hrow:focus-visible { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); outline: none; }
|
|
230
|
+
.epx-hrow .epx-url { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
231
|
+
@media (max-width: 640px) { .epx-grid2, .epx-grid3, .epx-frow { grid-template-columns: 1fr; } }
|
|
232
|
+
</style>
|