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,213 +1,236 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
</
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
</button>
|
|
1
|
+
<!-- View editor. Bound with M.applyBindings - see admin/js/views/view-editor.js. No page heading: the Tool
|
|
2
|
+
banner ("Views › <title>") is the heading; Save, Results, Delete and All views are banner actions. -->
|
|
3
|
+
<div class="vex">
|
|
4
|
+
<div class="vex-unsaved" data-bind-hidden="!dirty.value">
|
|
5
|
+
<span class="vex-dot" aria-hidden="true"></span>
|
|
6
|
+
<strong>Unsaved changes</strong>
|
|
7
|
+
<small data-bind-text="errorSummary.value"></small>
|
|
8
|
+
<span class="vex-spacer"></span>
|
|
9
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="discard">Discard</button>
|
|
10
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="saving.value">
|
|
11
|
+
<span data-icon="save" data-icon-size="13"></span> Save</button>
|
|
10
12
|
</div>
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
<div class="tabs" id="view-editor-tabs">
|
|
14
|
-
<div class="tab-list">
|
|
15
|
-
<button class="tab-item active">Source</button>
|
|
16
|
-
<button class="tab-item">Pipeline</button>
|
|
17
|
-
<button class="tab-item">Display</button>
|
|
18
|
-
<button class="tab-item">Access</button>
|
|
19
|
-
</div>
|
|
20
|
-
<div class="tab-content">
|
|
21
13
|
|
|
22
|
-
|
|
23
|
-
<div class="tab-
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
</div>
|
|
30
|
-
<div>
|
|
31
|
-
<label class="form-label">Slug</label>
|
|
32
|
-
<input id="view-slug" type="text" class="form-input" placeholder="Auto-generated from title">
|
|
33
|
-
<small class="text-muted">URL-safe identifier. Leave blank to auto-generate.</small>
|
|
34
|
-
</div>
|
|
35
|
-
<div>
|
|
36
|
-
<label class="form-label">Description</label>
|
|
37
|
-
<textarea id="view-description" class="form-input" rows="2" placeholder="Describe what this view shows…"></textarea>
|
|
38
|
-
</div>
|
|
39
|
-
<div>
|
|
40
|
-
<label class="form-label">Source Collection <span style="color:var(--dm-danger,#f87171);">*</span></label>
|
|
41
|
-
<select id="view-source" class="form-input">
|
|
42
|
-
<option value="">- select collection -</option>
|
|
43
|
-
</select>
|
|
44
|
-
<small class="text-muted">Changing the collection will refresh field lists in Pipeline and
|
|
45
|
-
Display tabs.</small>
|
|
46
|
-
</div>
|
|
47
|
-
<div>
|
|
48
|
-
<label class="form-label">Project</label>
|
|
49
|
-
<select id="view-project" class="form-input">
|
|
50
|
-
<option value="">- none -</option>
|
|
51
|
-
</select>
|
|
52
|
-
<small class="text-muted">Tag this view to a project for grouping.</small>
|
|
53
|
-
</div>
|
|
54
|
-
<div>
|
|
55
|
-
<label class="form-check-label" title="Included in fresh installs via the seed script">
|
|
56
|
-
<input id="view-bundled" type="checkbox" class="form-check"> Bundled
|
|
57
|
-
</label>
|
|
58
|
-
</div>
|
|
59
|
-
<div>
|
|
60
|
-
<label class="form-label">Connection</label>
|
|
61
|
-
<select id="view-connection" class="form-input">
|
|
62
|
-
<option value="default">default</option>
|
|
63
|
-
</select>
|
|
64
|
-
<small class="text-muted">MongoDB connection to use for execution.</small>
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
14
|
+
<div class="tabs vex-tabs" id="view-editor-tabs">
|
|
15
|
+
<div class="tab-list">
|
|
16
|
+
<button type="button" class="tab-item active">Source <span class="vex-tabdot" data-bind-hidden="!errs.value.source.length" title="Something here needs fixing"></span></button>
|
|
17
|
+
<button type="button" class="tab-item">Pipeline <b class="vex-count" data-bind-text="stageCount.value"></b> <span class="vex-tabdot" data-bind-hidden="!errs.value.pipeline.length" title="Something here needs fixing"></span></button>
|
|
18
|
+
<button type="button" class="tab-item">Display <span class="vex-tabdot" data-bind-hidden="!errs.value.display.length" title="Something here needs fixing"></span></button>
|
|
19
|
+
<button type="button" class="tab-item">Access <span class="vex-tabdot" data-bind-hidden="!errs.value.access.length" title="Something here needs fixing"></span></button>
|
|
20
|
+
<button type="button" class="tab-item">Results</button>
|
|
68
21
|
</div>
|
|
22
|
+
<div class="tab-content">
|
|
69
23
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
<
|
|
83
|
-
<
|
|
84
|
-
</
|
|
85
|
-
<
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
24
|
+
<!-- Source -->
|
|
25
|
+
<div class="tab-panel active">
|
|
26
|
+
<div class="vex-card">
|
|
27
|
+
<div class="vex-card-title">What it is, and what it reads</div>
|
|
28
|
+
<div class="vex-grid">
|
|
29
|
+
<div class="vex-wide">
|
|
30
|
+
<label class="form-label" for="view-title">Title <span class="vex-req">*</span></label>
|
|
31
|
+
<input id="view-title" type="text" class="form-input" maxlength="120" placeholder="e.g. Active premium users">
|
|
32
|
+
</div>
|
|
33
|
+
<div>
|
|
34
|
+
<label class="form-label" for="view-slug">Slug
|
|
35
|
+
<span data-help-title="Slug" data-help="The view's id - in [view slug="…"] and its API addresses. Made from the title when left blank. It cannot change once the view exists; duplicate the view to get another."></span></label>
|
|
36
|
+
<input id="view-slug" type="text" class="form-input font-mono" placeholder="made from the title">
|
|
37
|
+
<small class="vex-hint" data-bind-text="slugHint.value"></small>
|
|
38
|
+
</div>
|
|
39
|
+
<div>
|
|
40
|
+
<label class="form-label" for="view-source">Source collection <span class="vex-req">*</span>
|
|
41
|
+
<span data-help-title="Source" data-help="The collection whose entries the pipeline starts from. Changing it refreshes the field lists in Pipeline and Display. A MongoDB collection runs as a native aggregation; any other as the built-in pipeline evaluator - same stages, same results."></span></label>
|
|
42
|
+
<select id="view-source" class="form-input"><option value="">- choose -</option></select>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="vex-wide">
|
|
45
|
+
<label class="form-label" for="view-description">Description</label>
|
|
46
|
+
<textarea id="view-description" class="form-input" rows="2" placeholder="What this view shows, and for whom…"></textarea>
|
|
47
|
+
</div>
|
|
48
|
+
<div>
|
|
49
|
+
<label class="form-label" for="view-project">Project
|
|
50
|
+
<span data-help="Files the view under a project - for the sidebar and for users limited to that project. Left empty, it belongs to Core."></span></label>
|
|
51
|
+
<select id="view-project" class="form-input"><option value="">- Core -</option></select>
|
|
52
|
+
</div>
|
|
53
|
+
<div>
|
|
54
|
+
<label class="form-label" for="view-connection">Connection
|
|
55
|
+
<span data-help="The MongoDB connection a MongoDB-backed source runs on. Ignored for file collections."></span></label>
|
|
56
|
+
<select id="view-connection" class="form-input"><option value="default">default</option></select>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="vex-setting vex-wide">
|
|
59
|
+
<label class="form-label" for="view-bundled">Bundled
|
|
60
|
+
<span data-help="Included in fresh installs by the seed script. Leave off for a site's own views."></span></label>
|
|
61
|
+
<input id="view-bundled" type="checkbox" class="form-switch">
|
|
62
|
+
</div>
|
|
95
63
|
</div>
|
|
96
64
|
</div>
|
|
97
65
|
</div>
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
66
|
+
|
|
67
|
+
<!-- Pipeline -->
|
|
68
|
+
<div class="tab-panel">
|
|
69
|
+
<div class="vex-card">
|
|
70
|
+
<div class="vex-card-title">Stages <small class="vex-muted">run top to bottom</small>
|
|
71
|
+
<span data-help-title="Pipeline" data-help="Each stage takes the rows from the one above and passes on its result: filter them ($match), order them ($sort), join another collection ($lookup), reshape or compute fields, group and total, keep or skip some, or count them. $match and $sort have a builder; the rest take their settings as JSON - only the inside, e.g. { "from": …, "as": … } for $lookup. Right-click a stage (or ⋮, or Shift+F10) to move, duplicate or delete it, or to see the results up to that stage."></span>
|
|
72
|
+
<span class="vex-spacer"></span>
|
|
73
|
+
<select id="add-stage-type" class="form-input vex-add-type" aria-label="Stage to add"></select>
|
|
74
|
+
<button type="button" id="add-stage-btn" class="btn btn-sm btn-ghost"><span data-icon="plus" data-icon-size="13"></span> Add stage</button>
|
|
75
|
+
</div>
|
|
76
|
+
<div id="pipeline-stages-list" class="vex-stages"></div>
|
|
77
|
+
<p class="vex-note" data-bind-hidden="stageCount.value">No stages yet - every entry of the source is shown as it is. Add one to filter, join or reshape.</p>
|
|
105
78
|
</div>
|
|
106
79
|
</div>
|
|
107
|
-
</div>
|
|
108
80
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<div>
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
<
|
|
124
|
-
<
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<input id="view-page-size" type="number" class="form-input" value="25" min="1" max="200">
|
|
134
|
-
</div>
|
|
135
|
-
<div id="view-columns-section">
|
|
136
|
-
<label class="form-label">Columns</label>
|
|
137
|
-
<small class="text-muted" style="display:block;margin-bottom:.75rem;">
|
|
138
|
-
Choose which fields to display and their labels.
|
|
139
|
-
Field dropdowns are auto-populated from the source collection.
|
|
140
|
-
</small>
|
|
141
|
-
<div id="view-columns-builder" style="min-height:2rem;"></div>
|
|
81
|
+
<!-- Display -->
|
|
82
|
+
<div class="tab-panel">
|
|
83
|
+
<div class="vex-card">
|
|
84
|
+
<div class="vex-card-title">How it is shown</div>
|
|
85
|
+
<div class="vex-grid">
|
|
86
|
+
<div>
|
|
87
|
+
<label class="form-label" for="view-display-mode">Display mode
|
|
88
|
+
<span data-help="Table: a row per result with the columns below. List: each result's first fields, one under another. Block: each result rendered through a block template of yours."></span></label>
|
|
89
|
+
<select id="view-display-mode" class="form-input">
|
|
90
|
+
<option value="table">Table</option>
|
|
91
|
+
<option value="list">List</option>
|
|
92
|
+
<option value="block">Block</option>
|
|
93
|
+
</select>
|
|
94
|
+
</div>
|
|
95
|
+
<div>
|
|
96
|
+
<label class="form-label" for="view-page-size">Page size
|
|
97
|
+
<span data-help="Results per page, 1 to 200."></span></label>
|
|
98
|
+
<input id="view-page-size" type="number" class="form-input" value="25" min="1" max="200">
|
|
99
|
+
</div>
|
|
100
|
+
<div id="view-block-section" class="vex-wide" hidden>
|
|
101
|
+
<label class="form-label" for="view-block-name">Block template</label>
|
|
102
|
+
<select id="view-block-name" class="form-input"><option value="">- choose a block -</option></select>
|
|
103
|
+
<small class="vex-hint"><a href="#/blocks">Manage blocks</a></small>
|
|
104
|
+
</div>
|
|
142
105
|
</div>
|
|
143
106
|
</div>
|
|
107
|
+
<div class="vex-card" id="view-columns-section">
|
|
108
|
+
<div class="vex-card-title">Columns
|
|
109
|
+
<span data-help-title="Columns" data-help="Which fields the table shows, in order, and what each heading says. The field lists come from the source collection. With none, the first six fields of the first result are shown. Right-click a column (or ⋮) to move or remove it."></span></div>
|
|
110
|
+
<div id="view-columns-builder" class="vex-cols"></div>
|
|
111
|
+
</div>
|
|
144
112
|
</div>
|
|
145
|
-
</div>
|
|
146
113
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
<div id="view-roles-checkboxes" style="display:flex;flex-direction:column;gap:.5rem;"></div>
|
|
157
|
-
</div>
|
|
158
|
-
<div>
|
|
159
|
-
<label style="display:flex;align-items:center;gap:.5rem;cursor:pointer;">
|
|
160
|
-
<input type="checkbox" id="view-public">
|
|
161
|
-
<span>Public (no authentication required)</span>
|
|
162
|
-
</label>
|
|
163
|
-
<small class="text-muted" style="display:block;margin-top:.4rem;">
|
|
164
|
-
When enabled, the <code>/views/:slug/public</code> endpoint requires no login.
|
|
165
|
-
</small>
|
|
114
|
+
<!-- Access -->
|
|
115
|
+
<div class="tab-panel">
|
|
116
|
+
<div class="vex-card">
|
|
117
|
+
<div class="vex-card-title">Who can see it
|
|
118
|
+
<span data-help-title="Access" data-help="Signed-in users holding one of these roles can see the view's results - on pages ([view]) and at /api/views/<slug>/public. Public lets anyone, signed in or not. Admins always can."></span></div>
|
|
119
|
+
<div id="view-roles-checkboxes" class="vex-roles"></div>
|
|
120
|
+
<div class="vex-setting">
|
|
121
|
+
<label class="form-label" for="view-public">Public - no sign-in needed</label>
|
|
122
|
+
<input type="checkbox" id="view-public" class="form-switch">
|
|
166
123
|
</div>
|
|
167
124
|
</div>
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
<
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
</label>
|
|
177
|
-
<small class="text-muted" style="display:block;margin-top:.4rem;">
|
|
178
|
-
When enabled, each user sees only their own matching entries.
|
|
179
|
-
Admins always see all results.
|
|
180
|
-
</small>
|
|
181
|
-
</div>
|
|
182
|
-
<div id="view-rowlevel-config" style="display:none;flex-direction:column;gap:1rem;">
|
|
125
|
+
<div class="vex-card">
|
|
126
|
+
<div class="vex-card-title">Row-level access
|
|
127
|
+
<span data-help-title="Row-level access" data-help="Each user sees only the results that are theirs. Owner: entries they created. Field Match: entries whose chosen field equals something about them (their id, email, name or role). Admins always see every result."></span></div>
|
|
128
|
+
<div class="vex-setting">
|
|
129
|
+
<label class="form-label" for="view-rowlevel-enabled">Show each user only their own results</label>
|
|
130
|
+
<input type="checkbox" id="view-rowlevel-enabled" class="form-switch">
|
|
131
|
+
</div>
|
|
132
|
+
<div id="view-rowlevel-config" class="vex-grid" hidden>
|
|
183
133
|
<div>
|
|
184
|
-
<label class="form-label">Mode</label>
|
|
134
|
+
<label class="form-label" for="view-rowlevel-mode">Mode</label>
|
|
185
135
|
<select id="view-rowlevel-mode" class="form-input">
|
|
186
|
-
<option value="owner">Owner -
|
|
187
|
-
<option value="field">Field Match - a field
|
|
136
|
+
<option value="owner">Owner - they created the entry</option>
|
|
137
|
+
<option value="field">Field Match - a field equals them</option>
|
|
188
138
|
</select>
|
|
189
139
|
</div>
|
|
190
|
-
<div id="view-rowlevel-field-group" style="display:none;">
|
|
191
|
-
<label class="form-label">Field Name</label>
|
|
192
|
-
<input id="view-rowlevel-field" type="text" class="form-input"
|
|
193
|
-
placeholder="e.g. assigned_to">
|
|
194
|
-
<small class="text-muted">The entry field whose value must match the user property
|
|
195
|
-
below.</small>
|
|
196
|
-
</div>
|
|
197
140
|
<div>
|
|
198
|
-
<label class="form-label">
|
|
141
|
+
<label class="form-label" for="view-rowlevel-userkey">Compared with their</label>
|
|
199
142
|
<select id="view-rowlevel-userkey" class="form-input">
|
|
200
|
-
<option value="id">id
|
|
143
|
+
<option value="id">id</option>
|
|
201
144
|
<option value="email">email</option>
|
|
202
145
|
<option value="name">name</option>
|
|
203
146
|
<option value="role">role</option>
|
|
204
147
|
</select>
|
|
205
|
-
|
|
148
|
+
</div>
|
|
149
|
+
<div id="view-rowlevel-field-group" class="vex-wide" hidden>
|
|
150
|
+
<label class="form-label" for="view-rowlevel-field">Entry field</label>
|
|
151
|
+
<input id="view-rowlevel-field" type="text" class="form-input font-mono" placeholder="e.g. assigned_to">
|
|
206
152
|
</div>
|
|
207
153
|
</div>
|
|
208
154
|
</div>
|
|
209
155
|
</div>
|
|
210
|
-
</div>
|
|
211
156
|
|
|
157
|
+
<!-- Results -->
|
|
158
|
+
<div class="tab-panel">
|
|
159
|
+
<div class="vex-card">
|
|
160
|
+
<div class="vex-card-title">Results <small class="vex-muted" data-bind-text="previewMeta.value"></small>
|
|
161
|
+
<span data-help-title="Results" data-help="The pipeline as it stands now - saved or not - run against the source, first rows only. It follows your edits. Row-level access is not applied here: this is the admin's view."></span>
|
|
162
|
+
<span class="vex-spacer"></span>
|
|
163
|
+
<button type="button" class="btn btn-sm btn-ghost" data-bind-hidden="!upTo.value" data-on-click="allStages">Run every stage</button>
|
|
164
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="runPreview"><span data-icon="refresh-cw" data-icon-size="13"></span> Run</button>
|
|
165
|
+
</div>
|
|
166
|
+
<p class="vex-note" data-bind-hidden="!previewNote.value" data-bind-text="previewNote.value"></p>
|
|
167
|
+
<p class="vex-note is-bad" data-bind-hidden="!previewError.value" data-bind-text="previewError.value"></p>
|
|
168
|
+
<div class="vex-results"></div>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
212
172
|
</div>
|
|
213
173
|
</div>
|
|
174
|
+
|
|
175
|
+
<style>
|
|
176
|
+
.vex { display: flex; flex-direction: column; gap: .75rem; }
|
|
177
|
+
.vex [hidden] { display: none !important; }
|
|
178
|
+
.vex-unsaved { position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: .5rem; padding: .5rem .75rem;
|
|
179
|
+
border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); background: var(--dm-surface-raised, var(--dm-surface));
|
|
180
|
+
box-shadow: 0 2px 8px color-mix(in srgb, var(--dm-text) 10%, transparent); }
|
|
181
|
+
.vex-unsaved small { color: var(--dm-danger); }
|
|
182
|
+
.vex-dot { width: .55rem; height: .55rem; border-radius: 50%; background: var(--dm-warning); flex-shrink: 0; }
|
|
183
|
+
.vex-spacer { flex: 1; }
|
|
184
|
+
.vex-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .75rem .9rem; display: flex; flex-direction: column; gap: .7rem; margin-top: .75rem; }
|
|
185
|
+
.vex-card-title { display: flex; align-items: center; gap: .4rem; font-weight: 600; flex-wrap: wrap; }
|
|
186
|
+
.vex-card-title .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
187
|
+
.vex-muted, .vex-hint { color: var(--dm-text-muted); font-weight: 400; font-size: var(--dm-text-sm); }
|
|
188
|
+
.vex-hint { display: block; font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
189
|
+
.vex-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
190
|
+
.vex-note.is-bad { color: var(--dm-danger); }
|
|
191
|
+
.vex-req { color: var(--dm-danger); }
|
|
192
|
+
.vex-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .85rem; }
|
|
193
|
+
.vex-wide { grid-column: 1 / -1; }
|
|
194
|
+
.vex-grid .form-label, .vex-card .form-label { display: flex; align-items: center; gap: .3rem; }
|
|
195
|
+
.vex-setting { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
|
|
196
|
+
.vex-setting .form-label { margin: 0; }
|
|
197
|
+
.vex-count { font-weight: 500; opacity: .65; font-size: var(--dm-text-xs); margin-left: .15rem; }
|
|
198
|
+
.vex-tabdot { display: inline-block; width: .45rem; height: .45rem; border-radius: 50%; background: var(--dm-danger); margin-left: .25rem; vertical-align: middle; }
|
|
199
|
+
.vex-add-type { width: auto; min-width: 12rem; }
|
|
200
|
+
.vex-stages { display: flex; flex-direction: column; gap: .5rem; }
|
|
201
|
+
.vex-stage { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); }
|
|
202
|
+
.vex-stage.has-error { border-color: var(--dm-danger); }
|
|
203
|
+
.vex-stage-head { display: flex; align-items: center; gap: .5rem; padding: .45rem .6rem; border-bottom: 1px solid var(--dm-border);
|
|
204
|
+
background: color-mix(in srgb, var(--dm-text) 3%, transparent); border-radius: var(--dm-radius-md) var(--dm-radius-md) 0 0; }
|
|
205
|
+
.vex-stage-head:focus-visible { outline: 2px solid var(--dm-primary); outline-offset: -2px; }
|
|
206
|
+
.vex-stage-no { font-variant-numeric: tabular-nums; color: var(--dm-text-muted); font-size: var(--dm-text-xs); min-width: 1.2rem; }
|
|
207
|
+
.vex-stage-type { font-family: var(--dm-font-mono, monospace); font-size: var(--dm-text-sm); color: var(--dm-primary); }
|
|
208
|
+
.vex-stage-sum { flex: 1; min-width: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
209
|
+
.vex-stage-body { padding: .6rem; display: flex; flex-direction: column; gap: .4rem; }
|
|
210
|
+
.vex-stage-body textarea { font-family: var(--dm-font-mono, monospace); font-size: var(--dm-text-sm); resize: vertical; }
|
|
211
|
+
.vex-stage-err { color: var(--dm-danger); font-size: var(--dm-text-xs); }
|
|
212
|
+
.vex-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; }
|
|
213
|
+
.vex-kebab:hover { color: var(--dm-primary); }
|
|
214
|
+
.vex-cond, .vex-sort-row, .vex-col { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; }
|
|
215
|
+
/* One line per condition: the admin's .form-input is width:100%, which stacked them. */
|
|
216
|
+
.vex-cond > select, .vex-sort-row > select { width: auto; flex: 0 1 13rem; min-width: 9rem; }
|
|
217
|
+
.vex-cond .vex-val { flex: 1 1 10rem; min-width: 8rem; display: flex; }
|
|
218
|
+
.vex-cond .vex-val > * { flex: 1; }
|
|
219
|
+
.vex-logic { display: flex; align-items: center; gap: .5rem; }
|
|
220
|
+
.vex-logic select { width: auto; }
|
|
221
|
+
.vex-x { border: 0; background: none; cursor: pointer; color: var(--dm-text-muted); padding: 0 .3rem; font-size: var(--dm-text-lg); line-height: 1; }
|
|
222
|
+
.vex-x:hover { color: var(--dm-danger); }
|
|
223
|
+
.vex-cols { display: flex; flex-direction: column; gap: .4rem; }
|
|
224
|
+
.vex-col { padding: .2rem .25rem; border-radius: var(--dm-radius-sm); }
|
|
225
|
+
.vex-col:focus-within, .vex-col:hover { background: color-mix(in srgb, var(--dm-text) 4%, transparent); }
|
|
226
|
+
.vex-col .col-key { width: auto; flex: 0 1 16rem; min-width: 12rem; }
|
|
227
|
+
.vex-col .col-label { width: auto; flex: 1; }
|
|
228
|
+
.vex-roles { display: flex; flex-wrap: wrap; gap: .4rem .9rem; }
|
|
229
|
+
.vex-roles label { display: inline-flex; align-items: center; gap: .35rem; cursor: pointer; }
|
|
230
|
+
.vex-results { overflow-x: auto; }
|
|
231
|
+
.vex-results table { width: 100%; border-collapse: collapse; font-size: var(--dm-text-sm); }
|
|
232
|
+
.vex-results th, .vex-results td { text-align: left; padding: .35rem .5rem; border-bottom: 1px solid var(--dm-border); white-space: nowrap; max-width: 22rem; overflow: hidden; text-overflow: ellipsis; }
|
|
233
|
+
.vex-results th { color: var(--dm-text-muted); font-weight: 600; }
|
|
234
|
+
.vex-results tr[tabindex]:hover, .vex-results tr[tabindex]:focus-visible { background: color-mix(in srgb, var(--dm-text) 5%, transparent); outline: none; }
|
|
235
|
+
@media (max-width: 640px) { .vex-grid { grid-template-columns: 1fr; } }
|
|
236
|
+
</style>
|
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
</a>
|
|
10
|
-
<button id="preview-run-btn" class="btn btn-primary">
|
|
11
|
-
<span data-icon="play"></span> Run
|
|
12
|
-
</button>
|
|
1
|
+
<!-- View preview. Bound with M.applyBindings - see admin/js/views/view-preview.js. No page heading: the Tool
|
|
2
|
+
banner ("Views › <title>") is the heading; Run, Edit and All views are banner actions. -->
|
|
3
|
+
<div class="vpx">
|
|
4
|
+
<div class="vpx-card">
|
|
5
|
+
<div class="vpx-card-title">What runs
|
|
6
|
+
<span data-help-title="Preview" data-help="The saved view, run as you (an admin) would see it: every row the pipeline gives, a page at a time. Row-level access narrows the results for other users, not here. To change what it shows, Edit it - the editor's Results tab runs unsaved changes too."></span></div>
|
|
7
|
+
<div class="vpx-chips" data-each="chips.value key=text"></div>
|
|
8
|
+
<p class="vpx-note" data-bind-hidden="!description.value" data-bind-text="description.value"></p>
|
|
13
9
|
</div>
|
|
14
|
-
</div>
|
|
15
|
-
|
|
16
|
-
<div class="card mb-3" id="preview-meta-card" style="display:none;">
|
|
17
|
-
<div class="card-body" style="display:flex;gap:2rem;flex-wrap:wrap;font-size:.875rem;color:var(--dm-text-muted,#888);">
|
|
18
|
-
<span>Source: <strong id="preview-source"></strong></span>
|
|
19
|
-
<span>Connection: <strong id="preview-connection"></strong></span>
|
|
20
|
-
<span>Mode: <strong id="preview-mode"></strong></span>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
10
|
|
|
24
|
-
<div class="card
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<button
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
<span id="preview-page-label" style="padding:.25rem .5rem;font-size:.875rem;align-self:center;"></span>
|
|
32
|
-
<button id="preview-next" class="btn btn-ghost btn-sm" disabled>
|
|
33
|
-
Next <span data-icon="chevron-right"></span>
|
|
34
|
-
</button>
|
|
11
|
+
<div class="vpx-card">
|
|
12
|
+
<div class="vpx-bar">
|
|
13
|
+
<strong data-bind-text="countText.value"></strong>
|
|
14
|
+
<span class="vpx-spacer"></span>
|
|
15
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="prev" data-bind-disabled="!canPrev.value" aria-label="Previous page">‹ Prev</button>
|
|
16
|
+
<span class="vpx-muted" data-bind-text="pageText.value"></span>
|
|
17
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="next" data-bind-disabled="!canNext.value" aria-label="Next page">Next ›</button>
|
|
35
18
|
</div>
|
|
19
|
+
<p class="vpx-note" data-bind-hidden="!loading.value">Running…</p>
|
|
20
|
+
<p class="vpx-note is-bad" data-bind-hidden="!error.value" data-bind-text="error.value"></p>
|
|
21
|
+
<p class="vpx-note" data-bind-hidden="loading.value || error.value || total.value">No rows come out of this view.</p>
|
|
22
|
+
<div class="vpx-results"></div>
|
|
36
23
|
</div>
|
|
37
24
|
</div>
|
|
38
25
|
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
26
|
+
<style>
|
|
27
|
+
.vpx { display: flex; flex-direction: column; gap: .75rem; }
|
|
28
|
+
.vpx [hidden] { display: none !important; }
|
|
29
|
+
.vpx-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .75rem .9rem; display: flex; flex-direction: column; gap: .6rem; }
|
|
30
|
+
.vpx-card-title { display: flex; align-items: center; gap: .4rem; font-weight: 600; }
|
|
31
|
+
.vpx-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
|
|
32
|
+
.vpx-chip { display: inline-flex; align-items: center; font-size: var(--dm-text-xs); font-weight: 600; padding: .1rem .55rem; border-radius: 999px; white-space: nowrap;
|
|
33
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
34
|
+
.vpx-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
35
|
+
.vpx-chip.is-warn { background: color-mix(in srgb, var(--dm-warning) 18%, transparent); color: var(--dm-warning); }
|
|
36
|
+
.vpx-chip.is-danger { background: color-mix(in srgb, var(--dm-danger) 16%, transparent); color: var(--dm-danger); }
|
|
37
|
+
.vpx-bar { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
|
|
38
|
+
.vpx-spacer { flex: 1; }
|
|
39
|
+
.vpx-muted { color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
40
|
+
.vpx-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
41
|
+
.vpx-note.is-bad { color: var(--dm-danger); }
|
|
42
|
+
.vpx-results { overflow-x: auto; }
|
|
43
|
+
.vpx-results table { width: 100%; border-collapse: collapse; font-size: var(--dm-text-sm); }
|
|
44
|
+
.vpx-results th, .vpx-results td { text-align: left; padding: .4rem .55rem; border-bottom: 1px solid var(--dm-border); white-space: nowrap; max-width: 22rem; overflow: hidden; text-overflow: ellipsis; }
|
|
45
|
+
.vpx-results th { color: var(--dm-text-muted); font-weight: 600; }
|
|
46
|
+
.vpx-results tr[tabindex] { cursor: default; }
|
|
47
|
+
.vpx-results tr[tabindex]:hover, .vpx-results tr[tabindex]:focus-visible { background: color-mix(in srgb, var(--dm-text) 5%, transparent); outline: none; }
|
|
48
|
+
.vpx-list-item { padding: .55rem .25rem; border-bottom: 1px solid var(--dm-border); display: grid; grid-template-columns: minmax(8rem, max-content) 1fr; gap: .15rem .75rem; font-size: var(--dm-text-sm); }
|
|
49
|
+
.vpx-list-item dt { color: var(--dm-text-muted); }
|
|
50
|
+
.vpx-list-item dd { margin: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
51
|
+
</style>
|