domma-cms 0.75.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 +4 -4
- 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/api-tokens-arrange.js +3 -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/effects-arrange.js +3 -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/layouts-arrange.js +1 -0
- package/admin/js/lib/menu-editor-arrange.js +2 -0
- package/admin/js/lib/my-profile-arrange.js +1 -0
- package/admin/js/lib/notifications-arrange.js +1 -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/plugins-arrange.js +2 -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/roles-arrange.js +1 -0
- package/admin/js/lib/search-settings-arrange.js +1 -0
- package/admin/js/lib/sidebar-renderer.js +2 -2
- package/admin/js/lib/site-settings-arrange.js +1 -0
- package/admin/js/lib/user-editor-arrange.js +1 -0
- package/admin/js/lib/users-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/api-tokens.html +83 -10
- 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/effects.html +155 -72
- package/admin/js/templates/form-editor.html +41 -26
- package/admin/js/templates/form-submissions.html +78 -26
- package/admin/js/templates/layouts.html +126 -43
- package/admin/js/templates/menu-editor.html +57 -17
- package/admin/js/templates/menu-locations.html +54 -11
- package/admin/js/templates/my-profile.html +100 -12
- package/admin/js/templates/notifications.html +70 -10
- package/admin/js/templates/page-editor.html +47 -26
- package/admin/js/templates/plugin-code.html +91 -73
- package/admin/js/templates/plugins.html +100 -28
- 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/roles.html +78 -7
- package/admin/js/templates/search.html +193 -216
- package/admin/js/templates/settings.html +404 -472
- package/admin/js/templates/user-editor.html +150 -14
- package/admin/js/templates/users.html +69 -9
- 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/api-tokens.js +62 -8
- 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/effects.js +31 -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/layouts.js +81 -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/my-profile.js +1 -1
- package/admin/js/views/notifications.js +18 -1
- package/admin/js/views/page-editor.js +26 -26
- package/admin/js/views/plugin-code.js +23 -4
- package/admin/js/views/plugins.js +97 -39
- 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/roles.js +49 -4
- package/admin/js/views/search.js +7 -1
- package/admin/js/views/settings.js +13 -3
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/users.js +13 -4
- package/admin/js/views/view-editor.js +1 -1
- package/admin/js/views/view-preview.js +1 -1
- package/package.json +1 -1
- package/plugins/_lib/admin/mail/compose-window.js +97 -40
- package/plugins/_lib/admin/mail/contacts.js +4 -1
- package/plugins/_lib/admin/mail/diagnostics-section.js +4 -1
- package/plugins/_lib/admin/mail/folder-tree.js +1 -1
- package/plugins/_lib/admin/mail/image-senders-section.js +69 -90
- package/plugins/_lib/admin/mail/mail.css +1 -1
- package/plugins/_lib/admin/mail/mail.html +1 -1
- package/plugins/_lib/admin/mail/reader-view.js +303 -44
- package/plugins/_lib/admin/mail/when-closed.js +26 -0
- package/plugins/_lib/mail/readRoutes.js +43 -1
- package/plugins/_lib/mail/unreadBadge.js +42 -0
- package/plugins/free-tier.lock.json +5 -5
- package/plugins/mail-reader/CLAUDE.md +1 -0
- package/plugins/mail-reader/plugin.js +3 -1
- package/plugins/mail-reader/plugin.json +5 -4
- package/server/routes/api/api-tokens.js +56 -0
- package/server/routes/api/auth.js +7 -1
- package/server/routes/api/collections.js +13 -1
- package/server/routes/api/dashboard.js +32 -4
- package/server/routes/api/effects.js +68 -13
- package/server/routes/api/forms.js +104 -13
- package/server/routes/api/layouts.js +93 -2
- package/server/routes/api/notifications.js +140 -14
- package/server/routes/api/plugins.js +135 -4
- package/server/routes/api/roles.js +111 -0
- package/server/routes/api/search.js +38 -4
- package/server/routes/api/settings.js +52 -0
- package/server/routes/api/users.js +65 -3
- package/server/routes/api/views.js +55 -1
- package/server/server.js +12 -0
- package/server/services/components.js +9 -0
- package/server/services/plugins.js +7 -0
- package/server/services/roles.js +3 -0
- package/server/services/search.js +58 -0
- package/server/services/users.js +16 -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/templates/plugin-marketplace.html +0 -29
- 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
- package/admin/js/views/plugin-marketplace.js +0 -1
|
@@ -1,19 +1,155 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
<!-- User editor (#/users/new, #/users/edit/:id). Bound with M.applyBindings - see
|
|
2
|
+
admin/js/views/user-editor.js, which also draws the profile fields from the user-profiles schema and inserts
|
|
3
|
+
the role / project chip templates (the router renders a templateUrl through _.render, eating any {{…}}).
|
|
4
|
+
No page heading: the Tool banner ("Users › <name>") is the heading; Back and Save are banner actions. -->
|
|
5
|
+
<div class="uex">
|
|
6
|
+
<p class="uex-note is-bad" data-bind-hidden="!loadError.value" data-bind-text="loadError.value"></p>
|
|
7
|
+
<p class="uex-note" data-bind-hidden="!loading.value">Loading…</p>
|
|
8
|
+
|
|
9
|
+
<p class="uex-alert" data-bind-hidden="loading.value || !lockedReason.value">
|
|
10
|
+
<span data-icon="lock" data-icon-size="15"></span>
|
|
11
|
+
<span data-bind-text="lockedReason.value"></span>
|
|
12
|
+
</p>
|
|
7
13
|
|
|
8
|
-
<div class="
|
|
9
|
-
|
|
10
|
-
<
|
|
14
|
+
<div class="uex-dirty" data-bind-hidden="!dirty.value">
|
|
15
|
+
<span data-icon="edit" data-icon-size="14"></span>
|
|
16
|
+
<span data-bind-text="dirtyText">You have unsaved changes.</span>
|
|
17
|
+
<span class="uex-spacer"></span>
|
|
18
|
+
<button type="button" class="btn btn-sm btn-ghost" data-on-click="discard">Discard</button>
|
|
19
|
+
<button type="button" class="btn btn-sm btn-primary" data-on-click="save" data-bind-disabled="cannotSave.value">
|
|
20
|
+
<span data-icon="check" data-icon-size="13"></span> <span data-bind-text="saveText">Save</span></button>
|
|
11
21
|
</div>
|
|
12
|
-
</div>
|
|
13
22
|
|
|
14
|
-
<div class="card
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
23
|
+
<div class="uex-card uex-who" data-bind-hidden="loading.value || loadError.value">
|
|
24
|
+
<span class="uex-avatar" aria-hidden="true" data-bind-text="avatar.value"></span>
|
|
25
|
+
<span class="uex-who-main">
|
|
26
|
+
<strong data-bind-text="shownName.value"></strong>
|
|
27
|
+
<small data-bind-text="shownEmail.value"></small>
|
|
28
|
+
<small class="uex-facts" data-bind-text="factsText.value"></small>
|
|
29
|
+
</span>
|
|
30
|
+
<span class="uex-chips">
|
|
31
|
+
<span class="uex-chip is-primary" data-bind-hidden="!isSelf.value">You</span>
|
|
32
|
+
<span class="uex-chip is-ok" data-bind-text="roleText.value"></span>
|
|
33
|
+
<span class="uex-chip is-warn" data-bind-hidden="isActive.value">Inactive</span>
|
|
34
|
+
</span>
|
|
18
35
|
</div>
|
|
36
|
+
|
|
37
|
+
<fieldset class="uex-fields" data-bind-disabled="locked.value || saving.value" data-bind-hidden="loading.value || loadError.value">
|
|
38
|
+
<div class="uex-card">
|
|
39
|
+
<div class="uex-card-title">Account
|
|
40
|
+
<span data-help="The name shown in the admin and on anything they author. The email is what they sign in with, and where password resets go - no two accounts may share one."></span></div>
|
|
41
|
+
<div class="uex-grid">
|
|
42
|
+
<div>
|
|
43
|
+
<label class="form-label" for="uex-name">Full name <span class="text-danger">*</span></label>
|
|
44
|
+
<input id="uex-name" type="text" class="form-input" maxlength="100" autocomplete="off" placeholder="Jane Smith" data-model="name.value">
|
|
45
|
+
<small class="uex-err" data-bind-hidden="!err.value.name" data-bind-text="err.value.name"></small>
|
|
46
|
+
</div>
|
|
47
|
+
<div>
|
|
48
|
+
<label class="form-label" for="uex-email">Email <span class="text-danger">*</span></label>
|
|
49
|
+
<input id="uex-email" type="email" class="form-input" maxlength="200" autocomplete="off" placeholder="jane@example.com" data-model="email.value">
|
|
50
|
+
<small class="uex-err" data-bind-hidden="!emailErr.value" data-bind-text="emailErr.value"></small>
|
|
51
|
+
</div>
|
|
52
|
+
<div>
|
|
53
|
+
<label class="form-label" for="uex-pw"><span data-bind-text="pwLabel.value">Password</span>
|
|
54
|
+
<span data-help-title="Password" data-help="At least 8 characters. When editing, leave it empty to keep the current password. It is never kept as a draft - if you leave the screen, it is typed again."></span></label>
|
|
55
|
+
<input id="uex-pw" type="password" data-bind-type="showPw.value ? 'text' : 'password'" class="form-input" autocomplete="new-password"
|
|
56
|
+
data-bind-placeholder="pwPlaceholder.value" data-model="password.value">
|
|
57
|
+
<small class="uex-err" data-bind-hidden="!err.value.password" data-bind-text="err.value.password"></small>
|
|
58
|
+
<label class="uex-show"><input type="checkbox" data-model="showPw.value"> Show what I type</label>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="uex-setting">
|
|
61
|
+
<label class="form-label" for="uex-active">Active account
|
|
62
|
+
<span data-help="An inactive account cannot sign in. Nothing it made is removed - switch it back on at any time. You cannot switch off your own account."></span></label>
|
|
63
|
+
<input id="uex-active" type="checkbox" class="form-switch" data-model="isActive.value" data-bind-disabled="isSelf.value"
|
|
64
|
+
data-bind-title="isSelf.value ? 'You cannot switch off your own account' : ''">
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div class="uex-card">
|
|
70
|
+
<div class="uex-card-title">Roles
|
|
71
|
+
<span data-help-title="Roles" data-help="The primary role is the badge shown beside their name, and what seniority is compared on. Additional roles add their permissions on top - someone can be, say, a recruiter AND a content editor; the most senior role they hold decides who may manage them. You can only give roles below your own; a role they already hold can always be kept."></span></div>
|
|
72
|
+
<div class="uex-grid">
|
|
73
|
+
<div>
|
|
74
|
+
<label class="form-label" for="uex-role">Primary role <span class="text-danger">*</span></label>
|
|
75
|
+
<select id="uex-role" class="form-input uex-role-select" data-model="role.value"></select>
|
|
76
|
+
<small class="uex-err" data-bind-hidden="!err.value.role" data-bind-text="err.value.role"></small>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="uex-wide">
|
|
79
|
+
<span class="form-label">Additional roles</span>
|
|
80
|
+
<div class="uex-pick uex-roles" data-each="extraChips.value key=name"></div>
|
|
81
|
+
<small class="uex-hint" data-bind-hidden="extraChips.value.length">No other roles to add.</small>
|
|
82
|
+
<small class="uex-err" data-bind-hidden="!err.value.additionalRoles" data-bind-text="err.value.additionalRoles"></small>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div class="uex-card" data-bind-hidden="!hasProjects.value">
|
|
88
|
+
<div class="uex-card-title">Projects
|
|
89
|
+
<span data-help-title="Projects" data-help="Owned by: where this user is filed in the sidebar's Projects section - administrative only. Access: which projects' pages, collections and forms they can see and edit - leave it all unticked for no restriction. Core is always visible."></span></div>
|
|
90
|
+
<div class="uex-grid">
|
|
91
|
+
<div>
|
|
92
|
+
<label class="form-label" for="uex-owner">Owned by project</label>
|
|
93
|
+
<select id="uex-owner" name="ownedByProject" class="form-input uex-owner-select" data-model="ownedByProject.value"></select>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="uex-wide">
|
|
96
|
+
<span class="form-label">Project access</span>
|
|
97
|
+
<div class="uex-pick uex-projects" data-each="projectChips.value key=slug"></div>
|
|
98
|
+
<small class="uex-hint" data-bind-text="accessHint.value"></small>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<div class="uex-card" data-bind-hidden="!hasProfile.value">
|
|
104
|
+
<div class="uex-card-title">Profile
|
|
105
|
+
<span data-help="Extra details about this user. Which ones are asked for is set in the User Profiles collection."></span></div>
|
|
106
|
+
<div class="uex-grid uex-profile"></div>
|
|
107
|
+
</div>
|
|
108
|
+
</fieldset>
|
|
19
109
|
</div>
|
|
110
|
+
|
|
111
|
+
<style>
|
|
112
|
+
.uex { display: flex; flex-direction: column; gap: .75rem; max-width: 60rem; }
|
|
113
|
+
.uex [hidden] { display: none !important; }
|
|
114
|
+
.uex-fields { border: 0; margin: 0; padding: 0; min-width: 0; display: flex; flex-direction: column; gap: .75rem; }
|
|
115
|
+
.uex-fields:disabled { opacity: .75; }
|
|
116
|
+
.uex-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
117
|
+
.uex-note.is-bad { color: var(--dm-danger); }
|
|
118
|
+
.uex-alert { margin: 0; display: flex; align-items: center; gap: .5rem; padding: .55rem .8rem; border-radius: var(--dm-radius-md);
|
|
119
|
+
background: color-mix(in srgb, var(--dm-warning) 16%, transparent); color: var(--dm-text); }
|
|
120
|
+
.uex-dirty { display: flex; align-items: center; gap: .5rem; padding: .5rem .8rem; border-radius: var(--dm-radius-md);
|
|
121
|
+
background: color-mix(in srgb, var(--dm-warning) 14%, transparent); color: var(--dm-text); position: sticky; top: 0; z-index: 2; }
|
|
122
|
+
.uex-dirty .btn { display: inline-flex; align-items: center; gap: .3rem; }
|
|
123
|
+
.uex-spacer { flex: 1; }
|
|
124
|
+
.uex-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .8rem .9rem; display: flex; flex-direction: column; gap: .7rem; }
|
|
125
|
+
.uex-card-title { display: flex; align-items: center; gap: .35rem; font-weight: 600; }
|
|
126
|
+
.uex-who { flex-direction: row; align-items: center; gap: .9rem; flex-wrap: wrap; }
|
|
127
|
+
.uex-avatar { display: inline-flex; align-items: center; justify-content: center; width: 3rem; height: 3rem; border-radius: 50%; flex-shrink: 0;
|
|
128
|
+
font-weight: 700; color: var(--dm-primary); background: color-mix(in srgb, var(--dm-primary) 14%, transparent); }
|
|
129
|
+
.uex-who-main { flex: 1; min-width: 12rem; display: flex; flex-direction: column; }
|
|
130
|
+
.uex-who-main small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); }
|
|
131
|
+
.uex-facts { margin-top: .15rem; }
|
|
132
|
+
.uex-chips { display: inline-flex; gap: .3rem; flex-wrap: wrap; }
|
|
133
|
+
.uex-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;
|
|
134
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
135
|
+
.uex-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
136
|
+
.uex-chip.is-warn { background: color-mix(in srgb, var(--dm-warning) 18%, transparent); color: var(--dm-warning); }
|
|
137
|
+
.uex-chip.is-primary { background: color-mix(in srgb, var(--dm-primary) 16%, transparent); color: var(--dm-primary); }
|
|
138
|
+
.uex-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .8rem; }
|
|
139
|
+
.uex-wide { grid-column: 1 / -1; }
|
|
140
|
+
.uex .form-label { display: flex; align-items: center; gap: .3rem; }
|
|
141
|
+
.uex-err { display: block; color: var(--dm-danger); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
142
|
+
.uex-hint { display: block; color: var(--dm-text-muted); font-size: var(--dm-text-xs); margin-top: .25rem; }
|
|
143
|
+
.uex-show { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--dm-text-xs); color: var(--dm-text-muted); cursor: pointer; margin-top: .3rem; }
|
|
144
|
+
.uex-setting { display: flex; align-items: center; justify-content: space-between; gap: .75rem; align-self: end; padding-bottom: .4rem; }
|
|
145
|
+
.uex-setting .form-label { margin: 0; }
|
|
146
|
+
.uex-pick { display: flex; flex-wrap: wrap; gap: .35rem; }
|
|
147
|
+
.uex-pick-chip { display: inline-flex; align-items: center; gap: .3rem; border: 1px solid var(--dm-border); border-radius: 999px; padding: .2rem .65rem;
|
|
148
|
+
background: none; color: var(--dm-text); font: inherit; font-size: var(--dm-text-sm); cursor: pointer; }
|
|
149
|
+
.uex-pick-chip:hover:not(:disabled) { border-color: var(--dm-primary); }
|
|
150
|
+
.uex-pick-chip.is-on { background: color-mix(in srgb, var(--dm-primary) 14%, transparent); border-color: var(--dm-primary); color: var(--dm-primary); }
|
|
151
|
+
.uex-pick-chip:disabled { opacity: .5; cursor: not-allowed; }
|
|
152
|
+
.uex-pick-chip small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); }
|
|
153
|
+
.uex-check { display: inline-flex; align-items: center; gap: .4rem; cursor: pointer; margin-right: .8rem; }
|
|
154
|
+
@media (max-width: 640px) { .uex-grid { grid-template-columns: 1fr; } }
|
|
155
|
+
</style>
|
|
@@ -1,12 +1,72 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
<!-- Users. Bound with M.applyBindings - see admin/views/users.js, which also inserts the row template
|
|
2
|
+
(the router renders a templateUrl through _.render, eating any {{…}}). No page heading: the Tool
|
|
3
|
+
banner above is the heading, and New user is a banner action. -->
|
|
4
|
+
<div class="usx">
|
|
5
|
+
<p class="usx-note">Everyone who can sign in to this admin, with their role and when they last signed in.
|
|
6
|
+
<span data-help-title="Users" data-help="A role decides what someone can do (System › Roles). You can edit your own account, and anyone whose role is junior to yours - not a peer, not someone senior. Project access narrows what a user sees to those projects (and Core); none means everything. An inactive account cannot sign in, but keeps its work."></span></p>
|
|
7
|
+
<p class="usx-note" data-bind-hidden="!projectNote.value">
|
|
8
|
+
<span data-bind-text="projectNote.value"></span> <a href="#/users">Show all users</a></p>
|
|
7
9
|
|
|
8
|
-
<div class="card">
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
<div class="usx-card">
|
|
11
|
+
<div class="usx-bar">
|
|
12
|
+
<div class="usx-seg" role="group" aria-label="Show">
|
|
13
|
+
<button type="button" data-on-click="showAll" data-bind-class="filter.value === 'all' && 'is-on'">All <b data-bind-text="counts.value.all"></b></button>
|
|
14
|
+
<button type="button" data-on-click="showActive" data-bind-class="filter.value === 'active' && 'is-on'">Active <b data-bind-text="counts.value.active"></b></button>
|
|
15
|
+
<button type="button" data-on-click="showInactive" data-bind-class="filter.value === 'inactive' && 'is-on'">Inactive <b data-bind-text="counts.value.inactive"></b></button>
|
|
16
|
+
</div>
|
|
17
|
+
<select class="form-input usx-select" aria-label="Role" data-model="role.value">
|
|
18
|
+
<option value="">Every role</option>
|
|
19
|
+
</select>
|
|
20
|
+
<input type="search" class="form-input usx-search" placeholder="Search name, email, role…" aria-label="Search users" data-model="query.value">
|
|
21
|
+
<select class="form-input usx-select" aria-label="Sort" data-model="sort.value">
|
|
22
|
+
<option value="name">Name</option>
|
|
23
|
+
<option value="recent">Last signed in</option>
|
|
24
|
+
</select>
|
|
25
|
+
<span data-help-title="The list" data-help="Click someone to edit them. Right-click (or ⋮, or Shift+F10) to edit, copy their email, make the account active or inactive, or delete it. Greyed actions are ones your role does not allow - the menu says why."></span>
|
|
26
|
+
</div>
|
|
27
|
+
<p class="usx-note" data-bind-hidden="!loading.value">Loading…</p>
|
|
28
|
+
<p class="usx-note is-bad" data-bind-hidden="!loadError.value" data-bind-text="loadError.value"></p>
|
|
29
|
+
<p class="usx-note" data-bind-hidden="loading.value || loadError.value || rows.value.length" data-bind-text="emptyText.value"></p>
|
|
30
|
+
<div class="usx-list" data-each="rows.value key=id"></div>
|
|
11
31
|
</div>
|
|
12
32
|
</div>
|
|
33
|
+
|
|
34
|
+
<style>
|
|
35
|
+
.usx { display: flex; flex-direction: column; gap: .75rem; }
|
|
36
|
+
.usx [hidden] { display: none !important; }
|
|
37
|
+
.usx-note { margin: 0; color: var(--dm-text-muted); font-size: var(--dm-text-sm); }
|
|
38
|
+
.usx-note.is-bad { color: var(--dm-danger); }
|
|
39
|
+
.usx-card { border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); padding: .75rem .9rem; display: flex; flex-direction: column; gap: .6rem; }
|
|
40
|
+
.usx-bar { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
|
|
41
|
+
.usx-search { flex: 1; min-width: 10rem; max-width: 20rem; }
|
|
42
|
+
.usx-select { width: auto; flex: 0 0 auto; }
|
|
43
|
+
.usx-seg { display: inline-flex; border: 1px solid var(--dm-border); border-radius: var(--dm-radius-md); overflow: hidden; }
|
|
44
|
+
.usx-seg button { border: 0; background: none; color: var(--dm-text); padding: .3rem .7rem; cursor: pointer; font: inherit; font-size: var(--dm-text-sm); }
|
|
45
|
+
.usx-seg button + button { border-left: 1px solid var(--dm-border); }
|
|
46
|
+
.usx-seg button b { font-weight: 500; opacity: .65; margin-left: .2rem; }
|
|
47
|
+
.usx-seg button:hover { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); }
|
|
48
|
+
.usx-seg button.is-on { background: var(--dm-primary); color: var(--dm-primary-text); }
|
|
49
|
+
.usx-list { display: flex; flex-direction: column; }
|
|
50
|
+
.usx-row { display: flex; align-items: center; gap: .75rem; padding: .55rem .35rem; border-bottom: 1px solid var(--dm-border); cursor: pointer; }
|
|
51
|
+
.usx-row:last-child { border-bottom: 0; }
|
|
52
|
+
.usx-row:hover, .usx-row:focus-visible { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 6%, transparent)); outline: none; }
|
|
53
|
+
.usx-row.is-locked { cursor: default; }
|
|
54
|
+
.usx-avatar { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; flex-shrink: 0; border-radius: 50%;
|
|
55
|
+
font-size: var(--dm-text-xs); font-weight: 700; color: var(--dm-primary); background: color-mix(in srgb, var(--dm-primary) 14%, transparent); }
|
|
56
|
+
.usx-row.is-off .usx-avatar { color: var(--dm-text-muted); background: color-mix(in srgb, var(--dm-text-muted) 14%, transparent); }
|
|
57
|
+
.usx-row.is-off .usx-main strong { color: var(--dm-text-muted); }
|
|
58
|
+
.usx-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
59
|
+
.usx-main strong, .usx-main small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
60
|
+
.usx-main small { color: var(--dm-text-muted); font-size: var(--dm-text-xs); }
|
|
61
|
+
.usx-chips { display: inline-flex; flex-wrap: wrap; justify-content: flex-end; gap: .3rem; flex-shrink: 0; max-width: 55%; }
|
|
62
|
+
.usx-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;
|
|
63
|
+
background: color-mix(in srgb, var(--dm-text) 10%, transparent); color: var(--dm-text-muted); }
|
|
64
|
+
.usx-chip.is-ok { background: color-mix(in srgb, var(--dm-success) 16%, transparent); color: var(--dm-success); }
|
|
65
|
+
.usx-chip.is-warn { background: color-mix(in srgb, var(--dm-warning) 18%, transparent); color: var(--dm-warning); }
|
|
66
|
+
.usx-chip.is-danger { background: color-mix(in srgb, var(--dm-danger) 16%, transparent); color: var(--dm-danger); }
|
|
67
|
+
.usx-chip.is-primary { background: color-mix(in srgb, var(--dm-primary) 14%, transparent); color: var(--dm-primary); }
|
|
68
|
+
.usx-chip.is-outline { background: none; border: 1px solid var(--dm-border); }
|
|
69
|
+
.usx-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; }
|
|
70
|
+
.usx-kebab:hover { color: var(--dm-primary); }
|
|
71
|
+
@media (max-width: 640px) { .usx-chips { max-width: 40%; } .usx-main small { white-space: normal; } }
|
|
72
|
+
</style>
|