@protobase/ui 0.46.2 → 0.46.4

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.
Files changed (214) hide show
  1. package/dist/account/account-page.js +50 -0
  2. package/dist/account/account-pages.js +24 -9
  3. package/dist/account/account-tree.js +18 -0
  4. package/dist/account/blocks/account-loading.js +19 -0
  5. package/dist/account/blocks/connected-accounts-block.js +37 -0
  6. package/dist/account/blocks/connected-apps-block.js +21 -0
  7. package/dist/account/blocks/devices-block.js +23 -0
  8. package/dist/account/blocks/passkeys-block.js +25 -0
  9. package/dist/account/blocks/password-block.js +27 -0
  10. package/dist/account/blocks/profile-block.js +28 -0
  11. package/dist/account/blocks/two-factor-block.js +29 -0
  12. package/dist/account/blocks/use-account-data.js +24 -0
  13. package/dist/account/change-email-dialog.js +98 -0
  14. package/dist/account/connected-apps-section.js +4 -4
  15. package/dist/account/device-name.js +26 -0
  16. package/dist/account/devices-section.js +119 -0
  17. package/dist/account/messages.js +94 -2
  18. package/dist/account/passkeys-section.js +4 -4
  19. package/dist/account/password-change-dialog.js +119 -0
  20. package/dist/account/password-dialog.js +2 -2
  21. package/dist/account/password-section.js +51 -0
  22. package/dist/account/profile-section.js +107 -0
  23. package/dist/account/sign-in-policy-form.js +1 -1
  24. package/dist/account/sign-in-policy-page.js +1 -1
  25. package/dist/account/sign-in-providers-section.js +2 -2
  26. package/dist/account/staff-sign-in-log.js +1 -1
  27. package/dist/account/two-factor-section.js +1 -1
  28. package/dist/account/two-factor-setup.js +2 -2
  29. package/dist/activity-chart/activity-chart.js +2 -2
  30. package/dist/app/app.js +39 -23
  31. package/dist/app/charts/chart-view.js +2 -2
  32. package/dist/app/comments/comment-composer.js +1 -1
  33. package/dist/app/comments/comments-section.js +3 -3
  34. package/dist/app/create/create-page.js +4 -4
  35. package/dist/app/current-address.d.ts +1 -0
  36. package/dist/app/custom-section.js +4 -4
  37. package/dist/app/delete/use-delete-flow.js +1 -1
  38. package/dist/app/displays/board-column.js +1 -1
  39. package/dist/app/displays/board-display.js +2 -2
  40. package/dist/app/displays/calendar-display.js +2 -2
  41. package/dist/app/displays/custom-display.js +3 -3
  42. package/dist/app/displays/display-controls.js +1 -1
  43. package/dist/app/displays/map-display.js +2 -2
  44. package/dist/app/displays/period-controls.js +1 -1
  45. package/dist/app/displays/record-card.js +2 -2
  46. package/dist/app/displays/timeline-display.js +2 -2
  47. package/dist/app/displays/use-calendar-move.js +1 -1
  48. package/dist/app/document-title.js +2 -2
  49. package/dist/app/embedded-list/embedded-display.js +1 -1
  50. package/dist/app/embedded-list/embedded-list.js +1 -1
  51. package/dist/app/export/export-dialog.js +2 -2
  52. package/dist/app/export/use-export-flow.js +1 -1
  53. package/dist/app/field-editor.js +2 -2
  54. package/dist/app/file-field.js +3 -3
  55. package/dist/app/gallery/gallery-section.js +2 -2
  56. package/dist/app/gallery/photo-details.js +1 -1
  57. package/dist/app/gallery/use-gallery-photos.js +1 -1
  58. package/dist/app/hand-order/hand-sorted-list.js +3 -3
  59. package/dist/app/history/history-section.js +2 -2
  60. package/dist/app/import/import-button.js +1 -1
  61. package/dist/app/import/import-check-step.js +1 -1
  62. package/dist/app/incoming-card.js +2 -2
  63. package/dist/app/list-group-chart.js +1 -1
  64. package/dist/app/list-page.js +6 -6
  65. package/dist/app/messages.js +0 -2
  66. package/dist/app/meta-gate.js +1 -1
  67. package/dist/app/nav-from-meta.js +1 -1
  68. package/dist/app/new-version/new-version-banner.js +1 -1
  69. package/dist/app/new-version/new-version-button.js +1 -1
  70. package/dist/app/new-version/new-version-toast.js +1 -1
  71. package/dist/app/pages/action-inputs/action-inputs-dialog.js +2 -2
  72. package/dist/app/pages/action-inputs/input-answers.js +1 -1
  73. package/dist/app/pages/blocks/card-row.js +2 -2
  74. package/dist/app/pages/blocks/field.js +1 -1
  75. package/dist/app/pages/blocks/form-draft.js +19 -0
  76. package/dist/app/pages/blocks/modal-form.js +10 -24
  77. package/dist/app/pages/blocks/page-block.js +1 -1
  78. package/dist/app/pages/blocks/record-card.js +2 -2
  79. package/dist/app/pages/blocks/settings.js +179 -0
  80. package/dist/app/pages/blocks/stat.js +2 -2
  81. package/dist/app/pages/blocks/tabs.js +59 -0
  82. package/dist/app/pages/composed-page.js +16 -3
  83. package/dist/app/pages/custom-boundary.js +1 -1
  84. package/dist/app/pages/field-value.js +1 -1
  85. package/dist/app/pages/messages.js +6 -0
  86. package/dist/app/pages/page-tabs.js +27 -0
  87. package/dist/app/pages/record-actions.js +2 -2
  88. package/dist/app/pages/render-node.js +22 -3
  89. package/dist/app/pages/use-run-action.js +1 -1
  90. package/dist/app/project-logo.js +2 -2
  91. package/dist/app/record-chart/record-chart-section.js +4 -4
  92. package/dist/app/record-page.js +12 -12
  93. package/dist/app/record-row/record-row-body.js +1 -1
  94. package/dist/app/record-row/saved-record-row.js +1 -1
  95. package/dist/app/related-cards/related-card.js +1 -1
  96. package/dist/app/related-dots/related-dots-columns.js +1 -1
  97. package/dist/app/related-section.js +2 -2
  98. package/dist/app/relation-picker.js +1 -1
  99. package/dist/app/router.js +2 -2
  100. package/dist/app/saved/saved-list.js +1 -1
  101. package/dist/app/search/use-global-search.js +1 -1
  102. package/dist/app/searches/save-search-button.js +1 -1
  103. package/dist/app/searches/saved-search-rows.js +1 -1
  104. package/dist/app/searches/saved-search-section.js +2 -2
  105. package/dist/app/searches/saved-searches.js +3 -3
  106. package/dist/app/searches/search-controls.js +2 -2
  107. package/dist/app/searches/search-name-dialog.js +1 -1
  108. package/dist/app/searches/update-search-dialog.js +2 -2
  109. package/dist/app/searches/use-save-search.js +1 -1
  110. package/dist/app/sensitive-field.js +2 -2
  111. package/dist/app/source-notice.js +1 -1
  112. package/dist/app/staff-banner.js +2 -2
  113. package/dist/app/use-app-address.js +2 -2
  114. package/dist/app/use-incoming-counts.js +1 -1
  115. package/dist/app-shell/app-shell.js +2 -1
  116. package/dist/app-shell/breadcrumb.js +1 -1
  117. package/dist/app-shell/drawer.js +1 -1
  118. package/dist/app-shell/global-search.js +1 -1
  119. package/dist/app-shell/profile-menu.js +27 -12
  120. package/dist/app-shell/sidebar.js +2 -1
  121. package/dist/assistant-dock/widget-view.js +1 -1
  122. package/dist/auth/auth-gate.js +2 -2
  123. package/dist/auth/auth-messages.js +2 -2
  124. package/dist/auth/auth-provider.js +4 -0
  125. package/dist/auth/code-form.js +1 -1
  126. package/dist/auth/email-code-form.js +1 -1
  127. package/dist/auth/email-code-page.js +1 -1
  128. package/dist/auth/forgot-password-form.js +4 -4
  129. package/dist/auth/provider-sign-in-page.js +2 -2
  130. package/dist/auth/reset-password-form.js +1 -1
  131. package/dist/auth/setup-required-form.js +1 -1
  132. package/dist/auth/setup-required-page.js +2 -2
  133. package/dist/auth/sign-in-form.js +2 -2
  134. package/dist/auth/sign-in-page.js +1 -1
  135. package/dist/auth/sign-in-prompt.js +2 -2
  136. package/dist/auth/sign-up-code-form.js +1 -1
  137. package/dist/auth/sign-up-details-form.js +2 -2
  138. package/dist/auth/sign-up-email-form.js +1 -1
  139. package/dist/auth/sign-up-page.js +1 -1
  140. package/dist/auth/staff-sign-in-form.js +2 -2
  141. package/dist/auth/staff-sign-in-page.js +1 -1
  142. package/dist/auth/two-factor-form.js +3 -3
  143. package/dist/auth/two-factor-page.js +1 -1
  144. package/dist/chat/composer.js +1 -1
  145. package/dist/connect/connect-page.js +4 -4
  146. package/dist/data/meta-data.d.ts +3 -1
  147. package/dist/data/use-meta.js +1 -0
  148. package/dist/data-grid/cell-text.js +1 -1
  149. package/dist/data-grid/cells.js +3 -3
  150. package/dist/data-grid/grid-header.js +1 -1
  151. package/dist/data-grid/grid-row.js +2 -2
  152. package/dist/data-grid/row-menu.js +1 -1
  153. package/dist/filter-panel/facet-group.js +1 -1
  154. package/dist/forms/public-form-page.js +5 -5
  155. package/dist/index.js +20 -20
  156. package/dist/inline-child-table/line-row.js +1 -1
  157. package/dist/inline-child-table/totals-footer.js +1 -1
  158. package/dist/invitations/invite-form.js +1 -1
  159. package/dist/lists/paged-search-list.js +1 -1
  160. package/dist/live/columns-from-model.js +1 -1
  161. package/dist/live/use-filter-config.js +1 -1
  162. package/dist/live/use-reference-search.js +1 -1
  163. package/dist/notifications/bell/notification-bell.js +1 -1
  164. package/dist/notifications/bell/notification-item.js +2 -2
  165. package/dist/organizations/all-organizations.js +1 -1
  166. package/dist/organizations/invitation-page.js +6 -6
  167. package/dist/organizations/invitations-page.js +3 -3
  168. package/dist/organizations/members-page.js +5 -5
  169. package/dist/organizations/organization-page.js +3 -3
  170. package/dist/organizations/organization-row.js +1 -1
  171. package/dist/organizations/organizations-page.js +3 -3
  172. package/dist/organizations/use-organizations.js +1 -1
  173. package/dist/package.js +1 -1
  174. package/dist/plugins/before-sign-in.js +1 -1
  175. package/dist/plugins/plugin-gate.js +1 -1
  176. package/dist/primitives/sheet.js +1 -1
  177. package/dist/record-view/field.js +2 -2
  178. package/dist/record-view/record-header.js +1 -1
  179. package/dist/record-view/record-tabs.js +1 -1
  180. package/dist/roles/use-active-role.js +1 -1
  181. package/dist/shell/assets/app-BS1C66SI.js +9 -0
  182. package/dist/shell/assets/index-DMB4DCM1.js +2 -0
  183. package/dist/shell/assets/index-zVvlyz9B.css +2 -0
  184. package/dist/shell/assets/{maplibre-BlwO7zTh.js → maplibre-CjNYwEqW.js} +3 -3
  185. package/dist/shell/assets/{preload-helper-C24C2MCK.js → preload-helper-SYSsmQ2O.js} +2 -2
  186. package/dist/shell/assets/{record-map-QajKJid1.js → record-map-DjqQGqZ2.js} +2 -2
  187. package/dist/shell/assets/{records-map-B9tGF4Qv.js → records-map-peII4mzy.js} +2 -2
  188. package/dist/shell/assets/shared-protobase-ui-CQQebf-J.js +2 -0
  189. package/dist/shell/assets/vendor-BzlIWwX2.js +63 -0
  190. package/dist/shell/index.html +6 -6
  191. package/dist/shell/protobase.shell.json +1 -1
  192. package/dist/shell/protobase.sw.js +2 -2
  193. package/dist/shell-source-maps/assets/app-BS1C66SI.js.map +1 -0
  194. package/dist/shell-source-maps/assets/{index-CSQBCuCv.js.map → index-DMB4DCM1.js.map} +1 -1
  195. package/dist/shell-source-maps/assets/{maplibre-BlwO7zTh.js.map → maplibre-CjNYwEqW.js.map} +1 -1
  196. package/dist/shell-source-maps/assets/{preload-helper-C24C2MCK.js.map → preload-helper-SYSsmQ2O.js.map} +1 -1
  197. package/dist/shell-source-maps/assets/{record-map-QajKJid1.js.map → record-map-DjqQGqZ2.js.map} +1 -1
  198. package/dist/shell-source-maps/assets/{records-map-B9tGF4Qv.js.map → records-map-peII4mzy.js.map} +1 -1
  199. package/dist/shell-source-maps/assets/{shared-protobase-ui-BZ7JrZar.js.map → shared-protobase-ui-CQQebf-J.js.map} +1 -1
  200. package/dist/shell-source-maps/assets/vendor-BzlIWwX2.js.map +1 -0
  201. package/dist/side-panel/side-panel.js +1 -1
  202. package/dist/toasts/toast.js +1 -1
  203. package/dist/users/create-user-form.js +1 -1
  204. package/dist/users/use-user-roles.js +1 -1
  205. package/dist/users/user-row.js +1 -1
  206. package/package.json +4 -4
  207. package/dist/account/account-security-page.js +0 -97
  208. package/dist/shell/assets/app-DkL4XDpJ.js +0 -9
  209. package/dist/shell/assets/index-CSQBCuCv.js +0 -2
  210. package/dist/shell/assets/index-DHaeB8cs.css +0 -2
  211. package/dist/shell/assets/shared-protobase-ui-BZ7JrZar.js +0 -2
  212. package/dist/shell/assets/vendor-C4-Hop1T.js +0 -63
  213. package/dist/shell-source-maps/assets/app-DkL4XDpJ.js.map +0 -1
  214. package/dist/shell-source-maps/assets/vendor-C4-Hop1T.js.map +0 -1
@@ -2,9 +2,24 @@ import { defineMessages } from "../locale/messages.js";
2
2
  //#region src/account/messages.ts
3
3
  const text = defineMessages({
4
4
  en: {
5
- signInSecurity: "Sign-in & security",
5
+ account: "Account",
6
+ noAccount: "No account page",
7
+ noAccountDescription: "This app has no account page for you.",
6
8
  signInPolicy: "Sign-in policy",
7
9
  couldNotReadMethods: "Could not read your sign-in methods",
10
+ couldNotReadProfile: "Could not read your profile",
11
+ profile: "Profile",
12
+ profileDescription: "Your name as others see it in this app, and the address you sign in with.",
13
+ email: "Email",
14
+ changeName: "Change name",
15
+ changeNameDescription: "The name others see on your comments, changes and invitations.",
16
+ changeEmail: "Change email",
17
+ changeEmailDescription: "We email a code to the new address. Once you enter it here, you sign in with that address.",
18
+ newEmail: "New email",
19
+ sendCode: "Send code",
20
+ codeSentTo: (email) => `Enter the 6-digit code we emailed to ${email}. It works for 5 minutes. No code comes when another account has the address.`,
21
+ code: "Code",
22
+ otherAddress: "Use another address",
8
23
  theProvider: "the provider",
9
24
  loading: "Loading",
10
25
  backupCodes: "Backup codes",
@@ -15,6 +30,20 @@ const text = defineMessages({
15
30
  save: "Save",
16
31
  name: "Name",
17
32
  yourPassword: "Your password",
33
+ passwordIsSet: "Sign in with your email address and this password. Changing it asks for the current one.",
34
+ passwordNotSet: "You sign in without a password now. Set one to sign in with your email address and a password too; you stay signed in everywhere.",
35
+ passwordForbidden: "Your admin turned passwords off for this app, so they cannot be used to sign in.",
36
+ passwordStaff: "Staff signed in as someone cannot change their password.",
37
+ passwordSaved: "Your password is saved.",
38
+ changePassword: "Change password",
39
+ setPassword: "Set a password",
40
+ currentPassword: "Current password",
41
+ newPassword: "New password",
42
+ repeatPassword: "Repeat new password",
43
+ atLeast: (length) => `At least ${length} characters.`,
44
+ useAtLeast: (length) => `Use at least ${length} characters.`,
45
+ passwordTooLong: "That password is too long.",
46
+ passwordsDiffer: "The passwords are not the same.",
18
47
  continue: "Continue",
19
48
  on: "On",
20
49
  off: "Off",
@@ -45,6 +74,23 @@ const text = defineMessages({
45
74
  stopped: (time) => `Stopped ${time}`,
46
75
  ended: (time) => `Ended ${time}`,
47
76
  signedInUntil: (time) => `Signed in until ${time}`,
77
+ devices: "Devices",
78
+ devicesDescription: "The browsers and apps signed in to your account. To sign out this one, use Sign out in the menu.",
79
+ couldNotReadDevices: "Could not read your devices",
80
+ noDevices: "No device is signed in.",
81
+ thisDevice: "This device",
82
+ browserOn: (browser, system) => `${browser} on ${system}`,
83
+ aBrowserOn: (system) => `A browser on ${system}`,
84
+ unknownDevice: "Unknown device",
85
+ staffOf: (operator) => `${operator} staff`,
86
+ staff: "Staff",
87
+ signedInFromUntil: (from, until) => `Signed in ${from}, until ${until}`,
88
+ signOut: "Sign out",
89
+ signOutDevice: (name) => `Sign out ${name}?`,
90
+ signOutDeviceDescription: "It has to sign in again to use your account.",
91
+ signOutOthers: "Sign out of all other devices",
92
+ signOutOthersTitle: "Sign out of all other devices?",
93
+ signOutOthersDescription: "Every other browser and app signed in to your account has to sign in again. This device stays signed in.",
48
94
  staffSignIns: "Staff sign-ins",
49
95
  staffSignInsDescription: (operator) => `Each time staff of ${operator} signed in as someone here, newest first.`,
50
96
  noStaffSignIns: "No staff has signed in as anyone yet.",
@@ -106,9 +152,24 @@ const text = defineMessages({
106
152
  policySubtitle: "How people sign in to this app. Signed-in people keep their session, and are asked for what is newly required within 15 minutes."
107
153
  },
108
154
  nl: {
109
- signInSecurity: "Inloggen en beveiliging",
155
+ account: "Account",
156
+ noAccount: "Geen accountpagina",
157
+ noAccountDescription: "Deze app heeft geen accountpagina voor je.",
110
158
  signInPolicy: "Inlogbeleid",
111
159
  couldNotReadMethods: "Kon je inlogmethoden niet lezen",
160
+ couldNotReadProfile: "Kon je profiel niet lezen",
161
+ profile: "Profiel",
162
+ profileDescription: "Je naam zoals anderen die in deze app zien, en het adres waarmee je inlogt.",
163
+ email: "E-mail",
164
+ changeName: "Naam wijzigen",
165
+ changeNameDescription: "De naam die anderen zien bij je opmerkingen, wijzigingen en uitnodigingen.",
166
+ changeEmail: "E-mailadres wijzigen",
167
+ changeEmailDescription: "We mailen een code naar het nieuwe adres. Zodra je die hier invult, log je in met dat adres.",
168
+ newEmail: "Nieuw e-mailadres",
169
+ sendCode: "Code versturen",
170
+ codeSentTo: (email) => `Vul de code van 6 cijfers in die we naar ${email} mailden. Die werkt 5 minuten. Heeft een ander account het adres, dan komt er geen code.`,
171
+ code: "Code",
172
+ otherAddress: "Ander adres gebruiken",
112
173
  theProvider: "de provider",
113
174
  loading: "Laden",
114
175
  backupCodes: "Back-upcodes",
@@ -119,6 +180,20 @@ const text = defineMessages({
119
180
  save: "Bewaren",
120
181
  name: "Naam",
121
182
  yourPassword: "Je wachtwoord",
183
+ passwordIsSet: "Log in met je e-mailadres en dit wachtwoord. Wijzigen vraagt het huidige.",
184
+ passwordNotSet: "Je logt nu in zonder wachtwoord. Stel er een in om ook met je e-mailadres en een wachtwoord in te loggen; je blijft overal ingelogd.",
185
+ passwordForbidden: "Je beheerder heeft wachtwoorden uitgezet voor deze app, dus je kunt er niet mee inloggen.",
186
+ passwordStaff: "Een medewerker die als iemand anders is ingelogd, kan diens wachtwoord niet wijzigen.",
187
+ passwordSaved: "Je wachtwoord is bewaard.",
188
+ changePassword: "Wachtwoord wijzigen",
189
+ setPassword: "Wachtwoord instellen",
190
+ currentPassword: "Huidig wachtwoord",
191
+ newPassword: "Nieuw wachtwoord",
192
+ repeatPassword: "Nieuw wachtwoord herhalen",
193
+ atLeast: (length) => `Minstens ${length} tekens.`,
194
+ useAtLeast: (length) => `Gebruik minstens ${length} tekens.`,
195
+ passwordTooLong: "Dat wachtwoord is te lang.",
196
+ passwordsDiffer: "De wachtwoorden zijn niet hetzelfde.",
122
197
  continue: "Doorgaan",
123
198
  on: "Aan",
124
199
  off: "Uit",
@@ -149,6 +224,23 @@ const text = defineMessages({
149
224
  stopped: (time) => `Gestopt ${time}`,
150
225
  ended: (time) => `Afgelopen ${time}`,
151
226
  signedInUntil: (time) => `Ingelogd tot ${time}`,
227
+ devices: "Apparaten",
228
+ devicesDescription: "De browsers en apps die op je account zijn ingelogd. Log hier uit met Uitloggen in het menu.",
229
+ couldNotReadDevices: "Kon je apparaten niet lezen",
230
+ noDevices: "Er is geen apparaat ingelogd.",
231
+ thisDevice: "Dit apparaat",
232
+ browserOn: (browser, system) => `${browser} op ${system}`,
233
+ aBrowserOn: (system) => `Een browser op ${system}`,
234
+ unknownDevice: "Onbekend apparaat",
235
+ staffOf: (operator) => `Medewerker van ${operator}`,
236
+ staff: "Medewerker",
237
+ signedInFromUntil: (from, until) => `Ingelogd ${from}, tot ${until}`,
238
+ signOut: "Uitloggen",
239
+ signOutDevice: (name) => `${name} uitloggen?`,
240
+ signOutDeviceDescription: "Dat moet opnieuw inloggen om je account te gebruiken.",
241
+ signOutOthers: "Uitloggen op alle andere apparaten",
242
+ signOutOthersTitle: "Uitloggen op alle andere apparaten?",
243
+ signOutOthersDescription: "Elke andere browser en app die op je account is ingelogd, moet opnieuw inloggen. Dit apparaat blijft ingelogd.",
152
244
  staffSignIns: "Inlogs van medewerkers",
153
245
  staffSignInsDescription: (operator) => `Elke keer dat een medewerker van ${operator} hier als iemand anders inlogde, nieuwste eerst.`,
154
246
  noStaffSignIns: "Nog geen medewerker heeft als iemand anders ingelogd.",
@@ -1,11 +1,11 @@
1
1
  import { text } from "./messages.js";
2
- import { Badge } from "../primitives/badge.js";
3
- import { Input } from "../primitives/input.js";
4
- import { authMessage } from "../auth/auth-messages.js";
5
- import { formatDate } from "../format/date.js";
6
2
  import { Button } from "../primitives/button.js";
7
3
  import { Dialog } from "../primitives/dialog.js";
4
+ import { formatDate } from "../format/date.js";
5
+ import { Input } from "../primitives/input.js";
6
+ import { Badge } from "../primitives/badge.js";
8
7
  import { AccountSection, SectionError } from "./account-section.js";
8
+ import { authMessage } from "../auth/auth-messages.js";
9
9
  import { useState } from "react";
10
10
  import { KeyRound, Plus } from "lucide-react";
11
11
  import { AuthError } from "@protobase/client";
@@ -0,0 +1,119 @@
1
+ import { text } from "./messages.js";
2
+ import { Button } from "../primitives/button.js";
3
+ import { Dialog } from "../primitives/dialog.js";
4
+ import { Input } from "../primitives/input.js";
5
+ import { Checkbox } from "../primitives/checkbox.js";
6
+ import { SectionError } from "./account-section.js";
7
+ import { authMessage } from "../auth/auth-messages.js";
8
+ import { useId, useState } from "react";
9
+ import { AuthError } from "@protobase/client";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
+ //#region src/account/password-change-dialog.tsx
12
+ const passwordMessage = (error) => {
13
+ if (error.code === "PASSWORD_TOO_SHORT") return text("useAtLeast", 12);
14
+ if (error.code === "PASSWORD_TOO_LONG") return text("passwordTooLong");
15
+ return authMessage(error);
16
+ };
17
+ const draftProblem = (next, repeat) => {
18
+ if (next.length < 12) return text("useAtLeast", 12);
19
+ if (next !== repeat) return text("passwordsDiffer");
20
+ };
21
+ /** Changes the account's password with the current one, or sets a first one for an account without. */
22
+ const PasswordChangeDialog = ({ hasPassword, onSave, onClose }) => {
23
+ const [current, setCurrent] = useState("");
24
+ const [next, setNext] = useState("");
25
+ const [repeat, setRepeat] = useState("");
26
+ const [signOutOthers, setSignOutOthers] = useState(false);
27
+ const [busy, setBusy] = useState(false);
28
+ const [error, setError] = useState();
29
+ const formId = useId();
30
+ const filled = (!hasPassword || current) && next && repeat;
31
+ const save = async () => {
32
+ const problem = draftProblem(next, repeat);
33
+ setError(problem);
34
+ if (problem) return;
35
+ setBusy(true);
36
+ try {
37
+ await onSave({
38
+ current,
39
+ next,
40
+ signOutOthers
41
+ });
42
+ } catch (failure) {
43
+ if (!(failure instanceof AuthError)) throw failure;
44
+ setError(passwordMessage(failure));
45
+ setBusy(false);
46
+ }
47
+ };
48
+ return /* @__PURE__ */ jsx(Dialog, {
49
+ title: hasPassword ? text("changePassword") : text("setPassword"),
50
+ description: text("atLeast", 12),
51
+ onClose,
52
+ actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
53
+ onClick: onClose,
54
+ children: text("cancel")
55
+ }), /* @__PURE__ */ jsx(Button, {
56
+ variant: "primary",
57
+ type: "submit",
58
+ form: formId,
59
+ loading: busy,
60
+ disabled: !filled,
61
+ children: text("save")
62
+ })] }),
63
+ children: /* @__PURE__ */ jsxs("form", {
64
+ id: formId,
65
+ className: "flex flex-col gap-4",
66
+ onSubmit: (event) => {
67
+ event.preventDefault();
68
+ save();
69
+ },
70
+ children: [
71
+ hasPassword && /* @__PURE__ */ jsxs("label", {
72
+ className: "flex flex-col gap-1.5 font-medium",
73
+ children: [text("currentPassword"), /* @__PURE__ */ jsx(Input, {
74
+ type: "password",
75
+ name: "current-password",
76
+ autoComplete: "current-password",
77
+ autoFocus: true,
78
+ value: current,
79
+ onChange: (event) => setCurrent(event.target.value)
80
+ })]
81
+ }),
82
+ /* @__PURE__ */ jsxs("label", {
83
+ className: "flex flex-col gap-1.5 font-medium",
84
+ children: [text("newPassword"), /* @__PURE__ */ jsx(Input, {
85
+ type: "password",
86
+ name: "new-password",
87
+ autoComplete: "new-password",
88
+ autoFocus: !hasPassword,
89
+ value: next,
90
+ invalid: Boolean(error),
91
+ onChange: (event) => setNext(event.target.value)
92
+ })]
93
+ }),
94
+ /* @__PURE__ */ jsxs("label", {
95
+ className: "flex flex-col gap-1.5 font-medium",
96
+ children: [text("repeatPassword"), /* @__PURE__ */ jsx(Input, {
97
+ type: "password",
98
+ name: "repeat-password",
99
+ autoComplete: "new-password",
100
+ value: repeat,
101
+ invalid: Boolean(error),
102
+ onChange: (event) => setRepeat(event.target.value)
103
+ })]
104
+ }),
105
+ hasPassword && /* @__PURE__ */ jsxs("label", {
106
+ className: "flex items-center gap-2 text-muted-foreground",
107
+ children: [/* @__PURE__ */ jsx(Checkbox, {
108
+ checked: signOutOthers,
109
+ onChange: setSignOutOthers,
110
+ label: text("signOutOthers")
111
+ }), text("signOutOthers")]
112
+ }),
113
+ /* @__PURE__ */ jsx(SectionError, { message: error })
114
+ ]
115
+ })
116
+ });
117
+ };
118
+ //#endregion
119
+ export { PasswordChangeDialog };
@@ -1,8 +1,8 @@
1
1
  import { text } from "./messages.js";
2
- import { Input } from "../primitives/input.js";
3
- import { authMessage } from "../auth/auth-messages.js";
4
2
  import { Button } from "../primitives/button.js";
5
3
  import { Dialog } from "../primitives/dialog.js";
4
+ import { Input } from "../primitives/input.js";
5
+ import { authMessage } from "../auth/auth-messages.js";
6
6
  import { useState } from "react";
7
7
  import { AuthError } from "@protobase/client";
8
8
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -0,0 +1,51 @@
1
+ import { text } from "./messages.js";
2
+ import { Button } from "../primitives/button.js";
3
+ import { AccountSection } from "./account-section.js";
4
+ import { PasswordChangeDialog } from "./password-change-dialog.js";
5
+ import { useState } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/account/password-section.tsx
8
+ const descriptionOf = ({ rule, hasPassword, staff }) => {
9
+ if (staff) return text("passwordStaff");
10
+ if (rule === "forbidden") return text("passwordForbidden");
11
+ return hasPassword ? text("passwordIsSet") : text("passwordNotSet");
12
+ };
13
+ /** The signed-in person's password: change it with the current one, or set a first one without signing anyone out. */
14
+ const PasswordSection = ({ rule, hasPassword, staff, onChange, onSet }) => {
15
+ const [editing, setEditing] = useState(false);
16
+ const [saved, setSaved] = useState(false);
17
+ const canEdit = !staff && rule === "allowed";
18
+ return /* @__PURE__ */ jsxs(AccountSection, {
19
+ title: text("password"),
20
+ description: descriptionOf({
21
+ rule,
22
+ hasPassword,
23
+ staff
24
+ }),
25
+ children: [
26
+ saved && /* @__PURE__ */ jsx("p", {
27
+ role: "status",
28
+ className: "mb-3 font-medium",
29
+ children: text("passwordSaved")
30
+ }),
31
+ canEdit && /* @__PURE__ */ jsx(Button, {
32
+ onClick: () => {
33
+ setSaved(false);
34
+ setEditing(true);
35
+ },
36
+ children: hasPassword ? text("changePassword") : text("setPassword")
37
+ }),
38
+ editing && /* @__PURE__ */ jsx(PasswordChangeDialog, {
39
+ hasPassword,
40
+ onClose: () => setEditing(false),
41
+ onSave: async ({ current, next, signOutOthers }) => {
42
+ await (hasPassword ? onChange(current, next, signOutOthers) : onSet(next));
43
+ setEditing(false);
44
+ setSaved(true);
45
+ }
46
+ })
47
+ ]
48
+ });
49
+ };
50
+ //#endregion
51
+ export { PasswordSection };
@@ -0,0 +1,107 @@
1
+ import { text } from "./messages.js";
2
+ import { Button } from "../primitives/button.js";
3
+ import { Dialog } from "../primitives/dialog.js";
4
+ import { Input } from "../primitives/input.js";
5
+ import { AccountSection, SectionError } from "./account-section.js";
6
+ import { authMessage } from "../auth/auth-messages.js";
7
+ import { ChangeEmailDialog } from "./change-email-dialog.js";
8
+ import { useState } from "react";
9
+ import { AuthError } from "@protobase/client";
10
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
+ //#region src/account/profile-section.tsx
12
+ /** The signed-in person's name, which they can change, and the address they sign in with, which they can change with mail. */
13
+ const ProfileSection = ({ name, email, onRename, emailChange, onEmailChanged }) => {
14
+ const [editing, setEditing] = useState(false);
15
+ const [changingEmail, setChangingEmail] = useState(false);
16
+ const [draft, setDraft] = useState("");
17
+ const [busy, setBusy] = useState(false);
18
+ const [error, setError] = useState();
19
+ const rename = async () => {
20
+ setBusy(true);
21
+ setError(void 0);
22
+ try {
23
+ await onRename(draft.trim());
24
+ setEditing(false);
25
+ } catch (failure) {
26
+ if (!(failure instanceof AuthError)) throw failure;
27
+ setError(authMessage(failure));
28
+ }
29
+ setBusy(false);
30
+ };
31
+ return /* @__PURE__ */ jsxs(AccountSection, {
32
+ title: text("profile"),
33
+ description: text("profileDescription"),
34
+ children: [
35
+ /* @__PURE__ */ jsxs("dl", {
36
+ className: "mb-3 grid grid-cols-[auto_1fr] gap-x-6 gap-y-1.5",
37
+ children: [
38
+ /* @__PURE__ */ jsx("dt", {
39
+ className: "text-muted-foreground",
40
+ children: text("name")
41
+ }),
42
+ /* @__PURE__ */ jsx("dd", {
43
+ className: "min-w-0 truncate font-medium",
44
+ children: name
45
+ }),
46
+ /* @__PURE__ */ jsx("dt", {
47
+ className: "text-muted-foreground",
48
+ children: text("email")
49
+ }),
50
+ /* @__PURE__ */ jsx("dd", {
51
+ className: "min-w-0 truncate font-medium",
52
+ children: email
53
+ })
54
+ ]
55
+ }),
56
+ /* @__PURE__ */ jsxs("div", {
57
+ className: "flex flex-wrap gap-2",
58
+ children: [/* @__PURE__ */ jsx(Button, {
59
+ onClick: () => {
60
+ setDraft(name);
61
+ setError(void 0);
62
+ setEditing(true);
63
+ },
64
+ children: text("changeName")
65
+ }), emailChange && /* @__PURE__ */ jsx(Button, {
66
+ onClick: () => setChangingEmail(true),
67
+ children: text("changeEmail")
68
+ })]
69
+ }),
70
+ editing && /* @__PURE__ */ jsxs(Dialog, {
71
+ title: text("changeName"),
72
+ description: text("changeNameDescription"),
73
+ onClose: () => setEditing(false),
74
+ actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
75
+ onClick: () => setEditing(false),
76
+ children: text("cancel")
77
+ }), /* @__PURE__ */ jsx(Button, {
78
+ variant: "primary",
79
+ loading: busy,
80
+ disabled: !draft.trim() || draft.trim() === name,
81
+ onClick: () => void rename(),
82
+ children: text("save")
83
+ })] }),
84
+ children: [/* @__PURE__ */ jsxs("label", {
85
+ className: "flex flex-col gap-1.5 font-medium",
86
+ children: [text("name"), /* @__PURE__ */ jsx(Input, {
87
+ autoFocus: true,
88
+ value: draft,
89
+ maxLength: 100,
90
+ onChange: (event) => setDraft(event.target.value)
91
+ })]
92
+ }), /* @__PURE__ */ jsx(SectionError, { message: error })]
93
+ }),
94
+ changingEmail && emailChange && /* @__PURE__ */ jsx(ChangeEmailDialog, {
95
+ email,
96
+ change: emailChange,
97
+ onClose: () => setChangingEmail(false),
98
+ onDone: () => {
99
+ setChangingEmail(false);
100
+ onEmailChanged?.();
101
+ }
102
+ })
103
+ ]
104
+ });
105
+ };
106
+ //#endregion
107
+ export { ProfileSection };
@@ -1,7 +1,7 @@
1
1
  import { text } from "./messages.js";
2
2
  import { cn } from "../lib/cn.js";
3
- import { formatDateTime } from "../format/date.js";
4
3
  import { Button } from "../primitives/button.js";
4
+ import { formatDateTime } from "../format/date.js";
5
5
  import { policyRows, ruleLabel } from "./sign-in-policy-labels.js";
6
6
  import { useState } from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,8 +1,8 @@
1
1
  import { text } from "./messages.js";
2
+ import { useAuth } from "../auth/auth-provider.js";
2
3
  import { Spinner } from "../primitives/spinner.js";
3
4
  import { PageHeader } from "../app-shell/page-header.js";
4
5
  import { authMessage } from "../auth/auth-messages.js";
5
- import { useAuth } from "../auth/auth-provider.js";
6
6
  import { SignInPolicyForm } from "./sign-in-policy-form.js";
7
7
  import { StaffSignInLog } from "./staff-sign-in-log.js";
8
8
  import { useEffect, useState } from "react";
@@ -1,8 +1,8 @@
1
1
  import { text } from "./messages.js";
2
- import { Badge } from "../primitives/badge.js";
3
- import { authMessage } from "../auth/auth-messages.js";
4
2
  import { Button } from "../primitives/button.js";
3
+ import { Badge } from "../primitives/badge.js";
5
4
  import { AccountSection, SectionError } from "./account-section.js";
5
+ import { authMessage } from "../auth/auth-messages.js";
6
6
  import { useState } from "react";
7
7
  import { Link2 } from "lucide-react";
8
8
  import { AuthError } from "@protobase/client";
@@ -1,6 +1,6 @@
1
1
  import { text } from "./messages.js";
2
- import { Badge } from "../primitives/badge.js";
3
2
  import { formatDateTime } from "../format/date.js";
3
+ import { Badge } from "../primitives/badge.js";
4
4
  import { AccountSection, SectionError } from "./account-section.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/account/staff-sign-in-log.tsx
@@ -1,7 +1,7 @@
1
1
  import { text } from "./messages.js";
2
- import { Badge } from "../primitives/badge.js";
3
2
  import { Button } from "../primitives/button.js";
4
3
  import { Dialog } from "../primitives/dialog.js";
4
+ import { Badge } from "../primitives/badge.js";
5
5
  import { AccountSection } from "./account-section.js";
6
6
  import { BackupCodes } from "./backup-codes.js";
7
7
  import { PasswordDialog } from "./password-dialog.js";
@@ -1,10 +1,10 @@
1
1
  import { text } from "./messages.js";
2
2
  import { cn } from "../lib/cn.js";
3
+ import { Button } from "../primitives/button.js";
3
4
  import { Input } from "../primitives/input.js";
4
5
  import { authMessage } from "../auth/auth-messages.js";
5
- import { Button } from "../primitives/button.js";
6
- import { BackupCodes } from "./backup-codes.js";
7
6
  import { OtpInput } from "../primitives/otp-input.js";
7
+ import { BackupCodes } from "./backup-codes.js";
8
8
  import { TotpQr, totpKey } from "./totp-qr.js";
9
9
  import { useState } from "react";
10
10
  import { AuthError } from "@protobase/client";
@@ -1,9 +1,9 @@
1
1
  import { cn } from "../lib/cn.js";
2
2
  import { useMediaQuery } from "../lib/use-media-query.js";
3
- import { Segmented } from "../primitives/segmented.js";
3
+ import { activitySeries } from "../mocks/activity.js";
4
4
  import { formatInt } from "../format/number.js";
5
5
  import { formatDayShort } from "../format/date.js";
6
- import { activitySeries } from "../mocks/activity.js";
6
+ import { Segmented } from "../primitives/segmented.js";
7
7
  import { halfOverHalfDelta, totalCount } from "./activity-math.js";
8
8
  import { ActivityTooltip } from "./activity-tooltip.js";
9
9
  import { text } from "./messages.js";
package/dist/app/app.js CHANGED
@@ -1,34 +1,35 @@
1
1
  import { setFallbackLocale } from "../locale/active-locale.js";
2
- import { accountMenuItems } from "../account/account-pages.js";
3
- import { useSidebarNoticeShown } from "../app-shell/sidebar-notice.js";
4
- import { AppShell } from "../app-shell/app-shell.js";
2
+ import { accountMenuItems, readAccountPath } from "../account/account-pages.js";
5
3
  import { AuthProvider, useAuth } from "../auth/auth-provider.js";
6
- import { AccountSecurityPage } from "../account/account-security-page.js";
4
+ import { ApiProvider } from "../data/api-provider.js";
5
+ import { sourceStatusOf } from "../data/with-sources.js";
6
+ import { MetaGate, Notice, useAdminMeta } from "./meta-gate.js";
7
+ import { pageTabs, shownPageTab } from "./pages/page-tabs.js";
8
+ import { ToastProvider } from "../toasts/toast-provider.js";
9
+ import { humanize } from "../live/naming.js";
10
+ import { recordTitle } from "../live/model-helpers.js";
7
11
  import { text } from "./messages.js";
8
12
  import { Router, useRouter } from "./router.js";
13
+ import { useAppAddress } from "./use-app-address.js";
14
+ import { ProjectUiContext, useProjectUi } from "./pages/project-ui.js";
15
+ import { startErrorReporting } from "./error-reporting.js";
16
+ import { slotted } from "../locale/slotted.js";
17
+ import { CustomBoundary } from "./pages/custom-boundary.js";
18
+ import { useSidebarNoticeShown } from "../app-shell/sidebar-notice.js";
19
+ import { AppShell } from "../app-shell/app-shell.js";
9
20
  import { useSignInAddress } from "../auth/use-sign-in-address.js";
10
21
  import { SignInPrompt } from "../auth/sign-in-prompt.js";
11
- import { ApiProvider } from "../data/api-provider.js";
12
- import { sourceStatusOf } from "../data/with-sources.js";
13
- import { MetaGate, Notice, useAdminMeta } from "./meta-gate.js";
22
+ import { managesOrganization, organizationMenuItems, organizationPageTitle } from "../organizations/organization-paths.js";
23
+ import { AccountPage, useAccountPage } from "../account/account-page.js";
14
24
  import { ConnectPage } from "../connect/connect-page.js";
15
25
  import { SignInPolicyPage } from "../account/sign-in-policy-page.js";
16
- import { slotted } from "../locale/slotted.js";
17
- import { managesOrganization, organizationMenuItems, organizationPageTitle } from "../organizations/organization-paths.js";
18
- import { startErrorReporting } from "./error-reporting.js";
19
- import { CustomBoundary } from "./pages/custom-boundary.js";
20
26
  import { PluginSourceProvider } from "../plugins/plugin-source.js";
21
27
  import { AuthGate } from "../auth/auth-gate.js";
22
28
  import { isAdmin, userToShell } from "../auth/user-to-shell.js";
23
29
  import { AuthLocale } from "../auth/auth-locale.js";
24
30
  import { useLiveUpdates } from "../data/use-live-updates.js";
25
31
  import { useOpenedRecord } from "../data/use-record.js";
26
- import { humanize } from "../live/naming.js";
27
- import { ToastProvider } from "../toasts/toast-provider.js";
28
- import { recordTitle } from "../live/model-helpers.js";
29
- import { useAppAddress } from "./use-app-address.js";
30
32
  import { documentTitle, titleParts, useDocumentTitle } from "./document-title.js";
31
- import { ProjectUiContext, useProjectUi } from "./pages/project-ui.js";
32
33
  import { PublicFormPage } from "../forms/public-form-page.js";
33
34
  import { useFormAddress } from "../forms/use-form-address.js";
34
35
  import { ThemeProvider, useTheme } from "../theme/theme-provider.js";
@@ -147,7 +148,10 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
147
148
  const current = organizations.current;
148
149
  const outsideOrganizations = Boolean(organizationSettings) && current !== void 0 && !current.organization;
149
150
  const organizationPage = organizationSettings && user ? organizationPageTitle(path) : void 0;
150
- const accountPage = path === connectRoute ? "Connect an app" : !user ? void 0 : path === "/-/account" ? text("signInSecurity") : path === "/-/sign-in-policy" ? text("signInPolicy") : organizationPage;
151
+ const account = useAccountPage();
152
+ const accountAddress = user ? readAccountPath(path) : void 0;
153
+ const accountTab = accountAddress && account ? shownPageTab(pageTabs(account.tree), accountAddress.tab) : void 0;
154
+ const accountPage = path === connectRoute ? "Connect an app" : !user ? void 0 : accountAddress ? account?.title ?? text("account") : path === "/-/sign-in-policy" ? text("signInPolicy") : organizationPage;
151
155
  const resourceLabel = view?.names?.plural ?? (resource && humanize(resource));
152
156
  const breadcrumb = accountPage ? [accountPage] : breadcrumbFor({
153
157
  basePath,
@@ -159,9 +163,17 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
159
163
  recordLoading: titleLoading
160
164
  });
161
165
  const singular = view?.names?.singular ?? (resource && humanize(resource));
166
+ const pageTab = page && address?.kind === "page" ? shownPageTab(pageTabs(page.tree), address.tab) : void 0;
167
+ const pageTitle = page ? {
168
+ title: page.title,
169
+ ...pageTab && { tab: pageTab.label }
170
+ } : accountAddress && account && {
171
+ title: account.title,
172
+ ...accountTab && { tab: accountTab.label }
173
+ };
162
174
  useDocumentTitle(documentTitle(titleParts({
163
175
  address,
164
- page,
176
+ page: pageTitle,
165
177
  accountPage,
166
178
  resourceLabel,
167
179
  singular,
@@ -174,7 +186,7 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
174
186
  }) : /* @__PURE__ */ jsx(SignInPrompt, {
175
187
  as: "page",
176
188
  prompt: connectPrompt
177
- }) : user && path === "/-/account" ? /* @__PURE__ */ jsx(AccountSecurityPage, { email: user.email }) : user && path === "/-/sign-in-policy" ? admin ? /* @__PURE__ */ jsx(SignInPolicyPage, {}) : /* @__PURE__ */ jsx(Notice, {
189
+ }) : accountAddress ? /* @__PURE__ */ jsx(AccountPage, { ...accountAddress }) : user && path === "/-/sign-in-policy" ? admin ? /* @__PURE__ */ jsx(SignInPolicyPage, {}) : /* @__PURE__ */ jsx(Notice, {
178
190
  title: text("adminsOnly"),
179
191
  children: text("onlyAdminPolicy")
180
192
  }) : organizationPage && path === "/-/organization" ? /* @__PURE__ */ jsx(OrganizationPage, {
@@ -193,7 +205,10 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
193
205
  }) : /* @__PURE__ */ jsx(Notice, {
194
206
  title: text("notFound"),
195
207
  children: text("nothingHere")
196
- }) : address.kind === "page" ? page ? /* @__PURE__ */ jsx(ComposedPage, { name: page.name }, page.name) : /* @__PURE__ */ jsx(Notice, {
208
+ }) : address.kind === "page" ? page ? /* @__PURE__ */ jsx(ComposedPage, {
209
+ name: page.name,
210
+ ...address.tab && { tab: address.tab }
211
+ }, page.name) : /* @__PURE__ */ jsx(Notice, {
197
212
  title: text("notFound"),
198
213
  children: slotted(text("noPage"), address.page)
199
214
  }) : drawnFrom && drawnFrom.state !== "ready" ? /* @__PURE__ */ jsx(SourceNotice, { status: drawnFrom }) : address.kind === "create" ? /* @__PURE__ */ jsx(CreateRoute, {
@@ -219,10 +234,11 @@ const Routes = ({ workspace, sidebarMode, assistant, runtime }) => {
219
234
  navGroups: groups,
220
235
  bottomBar: bottomBarFromMeta(meta, basePath, place),
221
236
  userMenu: [
222
- ...userMenuFromMeta(meta, basePath, place),
223
- ...organizationSettings && user ? organizationMenuItems(basePath, path, current) : [],
224
- ...user ? accountMenuItems(basePath, path, admin) : []
237
+ userMenuFromMeta(meta, basePath, place),
238
+ organizationSettings && user ? organizationMenuItems(basePath, path, current) : [],
239
+ user ? accountMenuItems(basePath, path, admin) : []
225
240
  ],
241
+ account: user && `${basePath}/-/account`,
226
242
  organizations: organizationSettings && {
227
243
  ...current?.organization && { current: {
228
244
  id: current.organization.id,
@@ -1,6 +1,6 @@
1
- import { Skeleton } from "../../primitives/skeleton.js";
2
- import { viewerZone } from "../../format/zone.js";
3
1
  import { useAdminMeta } from "../meta-gate.js";
2
+ import { viewerZone } from "../../format/zone.js";
3
+ import { Skeleton } from "../../primitives/skeleton.js";
4
4
  import { labelFieldOf } from "../../live/model-helpers.js";
5
5
  import { useAggregate } from "../../data/use-aggregates.js";
6
6
  import { text } from "./messages.js";