alinea 2.0.0-preview.2 → 2.0.0-preview.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 (178) hide show
  1. package/dist/.init/content/pages/welcome.json +1 -1
  2. package/dist/LICENSES.md +157 -103
  3. package/dist/adapter/next/DevRemote.js +10 -2
  4. package/dist/adapter/next/previews.js +4 -1
  5. package/dist/adapter/next/previews.spec.d.ts +1 -0
  6. package/dist/backend/Handler.js +14 -7
  7. package/dist/backend/api/BasicAuth.d.ts +1 -1
  8. package/dist/backend/api/BasicAuth.js +14 -14
  9. package/dist/backend/api/OAuth2.d.ts +3 -3
  10. package/dist/backend/api/OAuth2.js +7 -4
  11. package/dist/bundled.d.ts +159 -42
  12. package/dist/chunks/{chunk-Y7XOMJOC.js → chunk-CFNRVI3Y.js} +220 -247
  13. package/dist/chunks/chunk-D6UJHBJJ.js +183 -0
  14. package/dist/chunks/chunk-TIJTT5ZI.js +228 -0
  15. package/dist/chunks/{chunk-UVOEM4AH.js → chunk-XMOVGDFI.js} +1 -1
  16. package/dist/cli/Serve.js +1 -1
  17. package/dist/cli/bin.js +1 -1
  18. package/dist/cli/serve/LocalAuth.js +1 -1
  19. package/dist/cloud/AuthResult.d.ts +2 -0
  20. package/dist/cloud/CloudHandshake.d.ts +7 -0
  21. package/dist/cloud/CloudHandshake.js +64 -0
  22. package/dist/cloud/CloudRemote.d.ts +4 -1
  23. package/dist/cloud/CloudRemote.js +21 -3
  24. package/dist/components/Breadcrumbs.js +2 -2
  25. package/dist/components/Calendar.js +6 -6
  26. package/dist/components/Checkbox.js +3 -3
  27. package/dist/components/ComboBox.js +11 -11
  28. package/dist/components/DateField.js +3 -3
  29. package/dist/components/DatePicker.js +4 -4
  30. package/dist/components/DateRangePicker.js +6 -6
  31. package/dist/components/Disclosure.js +8 -8
  32. package/dist/components/Label.js +5 -5
  33. package/dist/components/List.js +34 -34
  34. package/dist/components/Menu.js +4 -4
  35. package/dist/components/Modal.js +3 -3
  36. package/dist/components/MultipleSelect.js +25 -25
  37. package/dist/components/NumberField.js +6 -6
  38. package/dist/components/ProgressCircle.js +2 -2
  39. package/dist/components/RadioGroup.js +2 -2
  40. package/dist/components/SearchField.js +3 -3
  41. package/dist/components/Select.js +7 -7
  42. package/dist/components/Surface.js +2 -2
  43. package/dist/components/Table.js +7 -7
  44. package/dist/components/Tabs.js +4 -4
  45. package/dist/components/TagGroup.js +2 -2
  46. package/dist/components/TextField.js +6 -6
  47. package/dist/components/TimeField.js +2 -2
  48. package/dist/components/Toggle.d.ts +1 -1
  49. package/dist/components/Toggle.js +2 -2
  50. package/dist/components/Toolbar.js +2 -2
  51. package/dist/components/Tooltip.js +3 -3
  52. package/dist/components/Tree.d.ts +4 -2
  53. package/dist/components/Tree.js +18 -4
  54. package/dist/core/Connection.d.ts +7 -4
  55. package/dist/core/Entry.d.ts +6 -0
  56. package/dist/core/Entry.js +10 -0
  57. package/dist/core/Graph.d.ts +1 -1
  58. package/dist/core/Id.d.ts +1 -0
  59. package/dist/core/Id.js +8 -0
  60. package/dist/core/Infer.d.ts +8 -1
  61. package/dist/core/db/EntryAliases.js +1 -4
  62. package/dist/core/db/EntryResolver.js +6 -6
  63. package/dist/core/db/EntryTransaction.js +1 -0
  64. package/dist/core/db/Operation.d.ts +2 -2
  65. package/dist/core/db/Operation.js +15 -4
  66. package/dist/dashboard/App.js +37 -17
  67. package/dist/dashboard/StoryProvider.js +2 -2
  68. package/dist/dashboard/app/AccessDenied.d.ts +16 -1
  69. package/dist/dashboard/app/AccessDenied.js +21 -12
  70. package/dist/dashboard/app/ActivityStatus.js +19 -19
  71. package/dist/dashboard/app/AppearanceToggle.d.ts +1 -0
  72. package/dist/dashboard/app/AppearanceToggle.js +43 -0
  73. package/dist/dashboard/app/AuthView.d.ts +1 -1
  74. package/dist/dashboard/app/AuthView.js +16 -18
  75. package/dist/dashboard/app/Badge.js +2 -2
  76. package/dist/dashboard/app/CompactField.js +17 -17
  77. package/dist/dashboard/app/DashboardErrorBoundary.js +22 -10
  78. package/dist/dashboard/app/DashboardLayout.js +15 -8
  79. package/dist/dashboard/app/DashboardMeta.d.ts +2 -1
  80. package/dist/dashboard/app/DashboardMeta.js +20 -5
  81. package/dist/dashboard/app/EntryFields.js +6 -6
  82. package/dist/dashboard/app/EntryHeader.js +25 -25
  83. package/dist/dashboard/app/EntryReferences.js +16 -16
  84. package/dist/dashboard/app/EntrySidebar.js +26 -26
  85. package/dist/dashboard/app/EntrySidebarPreview.js +61 -34
  86. package/dist/dashboard/app/EntrySidebarPreview.story.d.ts +6 -1
  87. package/dist/dashboard/app/EntryTranslationBanner.js +8 -8
  88. package/dist/dashboard/app/Explorer.d.ts +2 -1
  89. package/dist/dashboard/app/Explorer.js +79 -67
  90. package/dist/dashboard/app/ExplorerCards.js +62 -66
  91. package/dist/dashboard/app/ExplorerFileCard.js +20 -20
  92. package/dist/dashboard/app/ExplorerList.js +22 -22
  93. package/dist/dashboard/app/ExplorerModal.js +3 -3
  94. package/dist/dashboard/app/ExplorerPickerContent.js +2 -2
  95. package/dist/dashboard/app/ExplorerTable.js +68 -68
  96. package/dist/dashboard/app/ImagePicker.js +7 -7
  97. package/dist/dashboard/app/LinkPicker.js +44 -24
  98. package/dist/dashboard/app/LocaleMenu.js +5 -7
  99. package/dist/dashboard/app/SidebarLayout.js +7 -7
  100. package/dist/dashboard/app/SidebarTree.js +66 -74
  101. package/dist/dashboard/app/WorkspaceMenu.d.ts +10 -3
  102. package/dist/dashboard/app/WorkspaceMenu.js +85 -64
  103. package/dist/dashboard/app/WorkspaceMenu.stories.d.ts +2 -0
  104. package/dist/dashboard/app/WorkspaceRoots.d.ts +3 -1
  105. package/dist/dashboard/app/WorkspaceRoots.js +82 -107
  106. package/dist/dashboard/app/editor/FileEditor.js +31 -31
  107. package/dist/dashboard/app/editor/FilePreview.js +4 -4
  108. package/dist/dashboard/app/editor/MediaAltField.view.js +4 -4
  109. package/dist/dashboard/app/modals/CreateEntry.js +14 -14
  110. package/dist/dashboard/app/pages/EntryPage.js +28 -30
  111. package/dist/dashboard/app/pages/RootPage.js +4 -4
  112. package/dist/dashboard/app/pages/SplashPage.d.ts +3 -0
  113. package/dist/dashboard/app/pages/SplashPage.js +414 -0
  114. package/dist/dashboard/app/pages/UsersPage.js +35 -35
  115. package/dist/dashboard/app/ui/DashboardModal.js +19 -19
  116. package/dist/dashboard/app/ui/Rail.js +3 -3
  117. package/dist/dashboard/atoms/ReactiveNode.js +1 -1
  118. package/dist/dashboard/atoms/activity.js +2 -3
  119. package/dist/dashboard/atoms/auth.d.ts +2 -0
  120. package/dist/dashboard/atoms/auth.js +6 -2
  121. package/dist/dashboard/atoms/config.js +1 -1
  122. package/dist/dashboard/atoms/core.js +2 -2
  123. package/dist/dashboard/atoms/create.js +1 -1
  124. package/dist/dashboard/atoms/dashboard.js +2 -2
  125. package/dist/dashboard/atoms/editor.js +1 -1
  126. package/dist/dashboard/atoms/entry.js +2 -2
  127. package/dist/dashboard/atoms/explorer.d.ts +1 -3
  128. package/dist/dashboard/atoms/explorer.js +7 -9
  129. package/dist/dashboard/atoms/graph.d.ts +1 -0
  130. package/dist/dashboard/atoms/graph.js +7 -2
  131. package/dist/dashboard/atoms/link.js +2 -2
  132. package/dist/dashboard/atoms/nav.d.ts +4 -3
  133. package/dist/dashboard/atoms/nav.js +10 -5
  134. package/dist/dashboard/atoms/preview.js +1 -1
  135. package/dist/dashboard/atoms/root.js +2 -2
  136. package/dist/dashboard/atoms/upload.js +1 -1
  137. package/dist/dashboard/atoms/user.d.ts +1 -1
  138. package/dist/dashboard/atoms/user.js +8 -6
  139. package/dist/dashboard/atoms/utils.js +2 -2
  140. package/dist/dashboard/boot/Boot.js +2 -4
  141. package/dist/dashboard/boot/DashboardWorker.js +34 -29
  142. package/dist/dashboard/editor/UseField.js +6 -6
  143. package/dist/dashboard/fixture/cms.d.ts +12 -0
  144. package/dist/dashboard/fixture/cms.js +53 -2
  145. package/dist/dashboard/hook/UseGraph.js +4 -4
  146. package/dist/dashboard/hook/UseRoot.js +4 -4
  147. package/dist/dashboard/hooks.js +16 -16
  148. package/dist/field/check/CheckField.view.js +2 -2
  149. package/dist/field/code/CodeField.view.js +15 -15
  150. package/dist/field/link/EntryLink.d.ts +1 -1
  151. package/dist/field/link/EntryLink.js +1 -0
  152. package/dist/field/link/Link.js +1 -0
  153. package/dist/field/link/LinkField.d.ts +5 -0
  154. package/dist/field/link/LinkField.view.js +81 -64
  155. package/dist/field/list/ListField.view.js +26 -26
  156. package/dist/field/localiser/LocalisedField.view.js +76 -5
  157. package/dist/field/metadata/MetadataField.d.ts +2 -0
  158. package/dist/field/metadata/MetadataField.js +2 -1
  159. package/dist/field/metadata/MetadataField.view.js +20 -20
  160. package/dist/field/richtext/PickTextLink.js +6 -6
  161. package/dist/field/richtext/RichTextBlock.js +6 -6
  162. package/dist/field/richtext/RichTextBlocks.js +1 -1
  163. package/dist/field/richtext/RichTextExtensions.js +23 -23
  164. package/dist/field/richtext/RichTextField.view.js +9 -9
  165. package/dist/field/richtext/RichTextState.js +1 -1
  166. package/dist/field/text/TextField.view.js +2 -2
  167. package/dist/index.css +436 -28
  168. package/dist/preview/PreviewMessage.d.ts +3 -0
  169. package/dist/preview/PreviewMessage.js +1 -0
  170. package/dist/preview/RegisterPreview.d.ts +1 -1
  171. package/dist/preview/RegisterPreview.js +28 -10
  172. package/dist/preview/react.d.ts +5 -1
  173. package/dist/preview/react.js +12 -9
  174. package/dist/preview/widget.js +6 -12
  175. package/dist/query.d.ts +7 -7
  176. package/package.json +1 -1
  177. package/dist/chunks/chunk-STAJCW4Z.js +0 -322
  178. package/dist/chunks/chunk-U4VOHNR2.js +0 -210
@@ -25,16 +25,18 @@ import { Icon } from "./Icon.js";
25
25
 
26
26
  // src/components/Tree.module.css
27
27
  var Tree_default = {
28
+ "Tree": "alinea-Tree",
29
+ "TreeItem": "alinea-TreeItem",
28
30
  "TreeItem-controls": "alinea-TreeItem-controls",
29
31
  "TreeItemControls": "alinea-TreeItem-controls",
30
32
  "TreeItem-dragHandle": "alinea-TreeItem-dragHandle",
31
33
  "TreeItemDragHandle": "alinea-TreeItem-dragHandle",
32
- "Tree": "alinea-Tree",
33
- "TreeItem": "alinea-TreeItem",
34
34
  "TreeItem-chevron": "alinea-TreeItem-chevron",
35
35
  "TreeItemChevron": "alinea-TreeItem-chevron",
36
36
  "TreeItem-foldIcon": "alinea-TreeItem-foldIcon",
37
- "TreeItemFoldIcon": "alinea-TreeItem-foldIcon"
37
+ "TreeItemFoldIcon": "alinea-TreeItem-foldIcon",
38
+ "TreeItem-iconLink": "alinea-TreeItem-iconLink",
39
+ "TreeItemIconLink": "alinea-TreeItem-iconLink"
38
40
  };
39
41
 
40
42
  // src/components/Tree.tsx
@@ -47,6 +49,7 @@ function Tree(props) {
47
49
  var TreeItemContent = memo(function TreeItemContent2({
48
50
  disableDragging,
49
51
  icon,
52
+ iconHref,
50
53
  suffix,
51
54
  children
52
55
  }) {
@@ -85,7 +88,16 @@ var TreeItemContent = memo(function TreeItemContent2({
85
88
  }
86
89
  )
87
90
  ] }),
88
- icon && /* @__PURE__ */ jsx("span", { "data-slot": "icon", children: /* @__PURE__ */ jsx(Icon, { icon }) }),
91
+ icon && /* @__PURE__ */ jsx("span", { "data-slot": "icon", children: iconHref ? /* @__PURE__ */ jsx(
92
+ "a",
93
+ {
94
+ "aria-hidden": true,
95
+ className: styles.TreeItem.iconLink(),
96
+ href: iconHref,
97
+ tabIndex: -1,
98
+ children: /* @__PURE__ */ jsx(Icon, { icon })
99
+ }
100
+ ) : /* @__PURE__ */ jsx(Icon, { icon }) }),
89
101
  /* @__PURE__ */ jsx("span", { "data-slot": "label", children }),
90
102
  suffix && /* @__PURE__ */ jsx("span", { "data-slot": "suffix", children: suffix })
91
103
  ] }) });
@@ -94,6 +106,7 @@ function TreeItem({
94
106
  disableDragging,
95
107
  title,
96
108
  icon,
109
+ iconHref,
97
110
  label,
98
111
  suffix,
99
112
  children,
@@ -114,6 +127,7 @@ function TreeItem({
114
127
  {
115
128
  disableDragging,
116
129
  icon,
130
+ iconHref,
117
131
  suffix,
118
132
  children: label ?? title
119
133
  }
@@ -8,11 +8,15 @@ import type { GetBlobsOptions } from './source/Source.js';
8
8
  import type { ReadonlyTree } from './source/Tree.js';
9
9
  import type { User, UserInput } from './User.js';
10
10
  export interface AuthApi {
11
- authenticate(request: Request, options?: AuthOptions): Promise<Response>;
11
+ authenticate(request: Request, options: AuthOptions): Promise<Response>;
12
12
  verify(request: Request): Promise<AuthedContext>;
13
13
  }
14
14
  export interface AuthOptions {
15
- enrichUser?(user: User): Promise<User>;
15
+ authenticated(user: User): Promise<AuthenticatedUser>;
16
+ }
17
+ export interface AuthenticatedUser {
18
+ user: User;
19
+ capabilities: BackendCapabilities;
16
20
  }
17
21
  export interface UserApi {
18
22
  enrichUser(user: User): Promise<User>;
@@ -25,7 +29,7 @@ export interface BackendCapabilities {
25
29
  users: boolean;
26
30
  }
27
31
  export interface CapabilitiesApi {
28
- capabilities?(): Promise<BackendCapabilities>;
32
+ capabilities(): Promise<BackendCapabilities>;
29
33
  }
30
34
  export interface RemoteConnection extends Connection, AuthApi, CapabilitiesApi {
31
35
  }
@@ -33,7 +37,6 @@ export interface BrowserConnection extends Connection {
33
37
  logout?(): Promise<void>;
34
38
  }
35
39
  export interface LocalConnection extends Connection, CapabilitiesApi {
36
- capabilities(): Promise<BackendCapabilities>;
37
40
  mutate(mutations: Array<Mutation>): Promise<{
38
41
  sha: string;
39
42
  }>;
@@ -30,6 +30,10 @@ export interface Entry<Data extends object = Record<string, unknown>> {
30
30
  export interface EntryAlias {
31
31
  url: string;
32
32
  }
33
+ export interface EntryAuditUser {
34
+ email: string;
35
+ name: string;
36
+ }
33
37
  export declare const Entry: {
34
38
  id: Expr<string>;
35
39
  status: Expr<EntryStatus>;
@@ -54,7 +58,9 @@ export declare const Entry: {
54
58
  url: Expr<string>;
55
59
  aliases: Expr<EntryAlias[]>;
56
60
  createdAt: Expr<number | null>;
61
+ createdBy: Expr<EntryAuditUser | null>;
57
62
  updatedAt: Expr<number | null>;
63
+ updatedBy: Expr<EntryAuditUser | null>;
58
64
  data: Expr<Record<string, any>>;
59
65
  searchableText: Expr<string>;
60
66
  };
@@ -40,11 +40,21 @@ var Entry = {
40
40
  name: "createdAt",
41
41
  path: ["metadata"]
42
42
  }),
43
+ createdBy: new Expr({
44
+ type: "entryField",
45
+ name: "createdBy",
46
+ path: ["metadata"]
47
+ }),
43
48
  updatedAt: new Expr({
44
49
  type: "entryField",
45
50
  name: "updatedAt",
46
51
  path: ["metadata"]
47
52
  }),
53
+ updatedBy: new Expr({
54
+ type: "entryField",
55
+ name: "updatedBy",
56
+ path: ["metadata"]
57
+ }),
48
58
  data: new Expr({ type: "entryField", name: "data" }),
49
59
  searchableText: new Expr({ type: "entryField", name: "searchableText" })
50
60
  };
@@ -106,7 +106,7 @@ export declare class QuerySettings {
106
106
  /** Filter by url */
107
107
  url?: Condition<string>;
108
108
  /** Filter by a metadata URL alias */
109
- alias?: string;
109
+ alias?: Condition<string>;
110
110
  /** Filter by metadata created timestamp */
111
111
  createdAt?: Condition<number | null>;
112
112
  /** Filter by metadata updated timestamp */
package/dist/core/Id.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export declare function validateId(id: string): boolean;
2
+ export declare function timestampFromId(id: string): number | undefined;
2
3
  export declare function createId(): string;
package/dist/core/Id.js CHANGED
@@ -132,10 +132,18 @@ function validateId(id) {
132
132
  return false;
133
133
  }
134
134
  }
135
+ function timestampFromId(id) {
136
+ try {
137
+ return parse(id).ts.getTime();
138
+ } catch {
139
+ return void 0;
140
+ }
141
+ }
135
142
  function createId() {
136
143
  return generate();
137
144
  }
138
145
  export {
139
146
  createId,
147
+ timestampFromId,
140
148
  validateId
141
149
  };
@@ -5,6 +5,7 @@ import type { Field } from './Field.js';
5
5
  import type { InferProjection } from './Graph.js';
6
6
  import type { ListRow } from './ListRow.js';
7
7
  import type { Type } from './Type.js';
8
+ import type { RecordField } from './field/RecordField.js';
8
9
  type QueryList<T> = Expand<UnionOfValues<{
9
10
  [K in keyof T]: {
10
11
  _type: K;
@@ -19,9 +20,15 @@ type StoredList<T> = Expand<UnionOfValues<{
19
20
  export type StoredRow<Definition> = {
20
21
  [K in keyof Definition as Definition[K] extends Field<any> ? K : never]: Definition[K] extends Field<infer T> ? T : never;
21
22
  };
22
- export type InferStoredValue<T> = T extends Type<infer Fields> ? StoredRow<Fields> : T extends Field<infer StoredValue> ? StoredValue : T extends Record<string, Type> ? StoredList<T> : {};
23
+ type CreateInputValue<T> = T extends RecordField<infer Row, infer _Options> ? Partial<Row> : T extends Field<infer StoredValue> ? StoredValue : never;
24
+ export type CreateInputRow<Definition> = {
25
+ [K in keyof Definition as Definition[K] extends Field ? K : never]: CreateInputValue<Definition[K]>;
26
+ };
27
+ export type InferStoredValue<T> = T extends Type<infer Fields> ? StoredRow<Fields> : T extends Field<infer StoredValue> ? StoredValue : T extends Record<string, Type> ? StoredList<T> : T extends object ? StoredRow<T> : {};
23
28
  export type Infer<T> = InferQueryValue<T>;
24
29
  export declare namespace Infer {
30
+ /** Stored content for creation and editing, before links are resolved. */
31
+ type Stored<T> = InferStoredValue<T>;
25
32
  type Entry<T extends Type, TypeName extends string = string> = InferQueryValue<T> & Omit<EntryFields, '_type'> & {
26
33
  _type: TypeName;
27
34
  };
@@ -17,10 +17,7 @@ function aliasesFromData(data) {
17
17
  return hasAliases ? result : void 0;
18
18
  }
19
19
  function aliasUrl(value) {
20
- const url = typeof value === "string" ? value : isRecord(value) && typeof value.url === "string" ? value.url : void 0;
21
- if (url === void 0) return void 0;
22
- const trimmed = url.trim();
23
- return trimmed.length > 0 ? trimmed : void 0;
20
+ return isRecord(value) && typeof value.url === "string" ? value.url : void 0;
24
21
  }
25
22
  export {
26
23
  aliasUrl,
@@ -536,13 +536,13 @@ function valueAtPath(value, path) {
536
536
  return current;
537
537
  }
538
538
  function aliasChecker(alias) {
539
- return (entry) => {
539
+ return filterChecker({ aliases: { includes: { url: alias } } }, (entry) => {
540
540
  const aliases = aliasesFromData(entry.data) ?? [];
541
- for (const row of aliases) {
542
- if (aliasUrl(row) === alias) return true;
543
- }
544
- return false;
545
- };
541
+ return aliases.flatMap((row) => {
542
+ const url = aliasUrl(row);
543
+ return url === void 0 ? [] : [{ url }];
544
+ });
545
+ });
546
546
  }
547
547
  function typeChecker(type) {
548
548
  if (Array.isArray(type)) {
@@ -208,6 +208,7 @@ var EntryTransaction = class {
208
208
  { id, type, index: newIndex, path, seeded, data, title },
209
209
  status
210
210
  );
211
+ if (fromSeed && data.title === void 0) delete record.title;
211
212
  const contents = new TextEncoder().encode(JSON.stringify(record, null, 2));
212
213
  this.#tx.add(filePath, contents);
213
214
  this.#messages.push(this.#reportOp("create", title));
@@ -1,4 +1,4 @@
1
- import type { StoredRow } from '../Infer.js';
1
+ import type { CreateInputRow, StoredRow } from '../Infer.js';
2
2
  import type { ImagePreviewDetails } from '../media/CreatePreview.js';
3
3
  import { Type } from '../Type.js';
4
4
  import type { Mutation } from './Mutation.js';
@@ -17,7 +17,7 @@ export interface CreateQuery<Fields> {
17
17
  parentId?: string | null;
18
18
  locale?: string | null;
19
19
  status?: 'draft' | 'published' | 'archived';
20
- set: Partial<StoredRow<Fields>>;
20
+ set: Partial<CreateInputRow<Fields>>;
21
21
  insertOrder?: 'first' | 'last';
22
22
  overwrite?: boolean;
23
23
  }
@@ -1,6 +1,7 @@
1
1
  import "../../chunks/chunk-CQ52GEHY.js";
2
2
 
3
3
  // src/core/db/Operation.ts
4
+ import { Field } from "../Field.js";
4
5
  import { HttpError } from "../HttpError.js";
5
6
  import { createId } from "../Id.js";
6
7
  import { isImage } from "../media/IsImage.js";
@@ -9,6 +10,7 @@ import { assertUploadSize } from "../media/UploadLimits.js";
9
10
  import { Schema } from "../Schema.js";
10
11
  import { Type } from "../Type.js";
11
12
  import { createFileHash } from "../util/ContentHash.js";
13
+ import { keys } from "../util/Objects.js";
12
14
  import { basename, extname } from "../util/Paths.js";
13
15
  import { slugify } from "../util/Slugs.js";
14
16
  import { Workspace } from "../Workspace.js";
@@ -37,7 +39,7 @@ var CreateOp = class extends Operation {
37
39
  locale: op.locale ?? null,
38
40
  parentId: op.parentId ?? null,
39
41
  type: typeName(config, op.type),
40
- data: op.set ?? {},
42
+ data: initializeSet(op.type, op.set),
41
43
  insertOrder: op.insertOrder,
42
44
  status: op.status,
43
45
  overwrite: op.overwrite,
@@ -49,6 +51,14 @@ var CreateOp = class extends Operation {
49
51
  this.id = op.id ?? createId();
50
52
  }
51
53
  };
54
+ function initializeSet(type, set) {
55
+ const result = { ...set };
56
+ for (const key of keys(result)) {
57
+ const field = Type.field(type, key);
58
+ if (field) result[key] = Field.withInitialValue(field, result[key]);
59
+ }
60
+ return result;
61
+ }
52
62
  var DeleteOp = class extends Operation {
53
63
  constructor(entryIds) {
54
64
  super(() => {
@@ -133,8 +143,10 @@ var UploadOperation = class extends Operation {
133
143
  assertUploadSize(fileName, fileSize, db.config.maxUploadSize);
134
144
  const body = Array.isArray(file) ? file[1] : await file.arrayBuffer();
135
145
  const contentType = file instanceof Blob ? file.type : "application/octet-stream";
136
- const extension = extname(fileName);
137
- const path = slugify(basename(fileName, extension));
146
+ const originalExtension = extname(fileName);
147
+ const title = basename(fileName, originalExtension);
148
+ const extension = originalExtension.toLowerCase();
149
+ const path = slugify(title);
138
150
  const uploadLocation = MediaLocation.storagePath(
139
151
  db.config,
140
152
  workspace,
@@ -149,7 +161,6 @@ var UploadOperation = class extends Operation {
149
161
  await sendUpload(info.url, info.method ?? "POST", contentType, body, {
150
162
  onProgress: query.onProgress
151
163
  });
152
- const title = basename(fileName, extension);
153
164
  const hash = await createFileHash(new Uint8Array(body));
154
165
  const fileLocation = MediaLocation.entryLocation(
155
166
  db.config,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  Provider,
3
3
  useAtom,
4
- useAtomValue
5
- } from "../chunks/chunk-U4VOHNR2.js";
4
+ useAtomValueRaw
5
+ } from "../chunks/chunk-D6UJHBJJ.js";
6
6
  import {
7
7
  atom,
8
8
  createStore
9
- } from "../chunks/chunk-Y7XOMJOC.js";
9
+ } from "../chunks/chunk-CFNRVI3Y.js";
10
10
  import {
11
11
  styler
12
12
  } from "../chunks/chunk-I4OYYAX5.js";
@@ -22,11 +22,11 @@ import {
22
22
 
23
23
  // src/dashboard/App.module.css
24
24
  var App_default = {
25
- "AppLoading-progress-fade-in": "alinea-AppLoading-progress-fade-in",
26
- "AppLoadingProgressFadeIn": "alinea-AppLoading-progress-fade-in",
27
25
  "AppLoading": "alinea-AppLoading",
28
26
  "AppLoading-progress": "alinea-AppLoading-progress",
29
- "AppLoadingProgress": "alinea-AppLoading-progress"
27
+ "AppLoadingProgress": "alinea-AppLoading-progress",
28
+ "AppLoading-progress-fade-in": "alinea-AppLoading-progress-fade-in",
29
+ "AppLoadingProgressFadeIn": "alinea-AppLoading-progress-fade-in"
30
30
  };
31
31
 
32
32
  // src/dashboard/App.tsx
@@ -36,17 +36,19 @@ import { DashboardLayout } from "./app/DashboardLayout.js";
36
36
  import { DashboardMeta } from "./app/DashboardMeta.js";
37
37
  import { DashboardErrorBoundary } from "./app/DashboardErrorBoundary.js";
38
38
  import { entryPage } from "./app/pages/EntryPage.js";
39
+ import { splashPage } from "./app/pages/SplashPage.js";
39
40
  import { MissingRoot, rootPage } from "./app/pages/RootPage.js";
40
41
  import { usersPage } from "./app/pages/UsersPage.js";
41
42
  import { Rail } from "./app/ui/Rail.js";
42
43
  import { activityAtom, activityPendingAtom } from "./atoms/activity.js";
43
44
  import { authAtom } from "./atoms/auth.js";
44
- import { workspaceAtom } from "./atoms/config.js";
45
+ import { workspaceAtom, workspacesAtom } from "./atoms/config.js";
45
46
  import { useInitAtoms } from "./atoms/core.js";
46
47
  import { entryAtoms, MissingEntryError } from "./atoms/entry.js";
48
+ import { graphReadyAtom } from "./atoms/graph.js";
47
49
  import { pageAtom } from "./atoms/nav.js";
48
50
  import { rootAtoms } from "./atoms/root.js";
49
- import { authReady, canManageMembersAtom } from "./atoms/user.js";
51
+ import { canManageMembersAtom, userPolicyReadyAtom } from "./atoms/user.js";
50
52
  import { atomWithPending } from "./atoms/utils.js";
51
53
  import { DashboardModelScope } from "./hooks.js";
52
54
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -59,28 +61,46 @@ var appAtom = atomWithPending(
59
61
  })
60
62
  );
61
63
  var authenticatedAtom = atom(async (get) => {
62
- const [, canManageMembers] = await Promise.all([
63
- get(authReady),
64
- get(canManageMembersAtom)
65
- ]);
64
+ await get(graphReadyAtom);
65
+ await get(userPolicyReadyAtom);
66
+ const canManageMembers = await get(canManageMembersAtom);
66
67
  const page = get(pageAtom);
67
68
  const { entry, workspace, root } = page;
68
69
  const workspaceData = workspace ? get(workspaceAtom(workspace)) : void 0;
69
- const meta = (label) => /* @__PURE__ */ jsx(
70
+ const meta = (label, plain = false) => /* @__PURE__ */ jsx(
70
71
  DashboardMeta,
71
72
  {
72
- color: workspaceData?.color ?? "#7c3aed",
73
+ color: plain ? "#6b7280" : workspaceData?.color ?? "#7c3aed",
73
74
  icon: workspaceData?.icon,
75
+ plain,
74
76
  title: dashboardTitle(workspaceData?.label ?? "Alinea", label)
75
77
  }
76
78
  );
77
- if (page.type === "users" && canManageMembers) {
79
+ if (page.type === "users") {
80
+ if (!canManageMembers) {
81
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
82
+ meta("No user management access"),
83
+ /* @__PURE__ */ jsx(AccessDenied, { canManageMembers: false, scope: "users" })
84
+ ] });
85
+ }
78
86
  const content2 = await usersPage(page, get);
79
87
  return /* @__PURE__ */ jsxs(Fragment, { children: [
80
88
  meta("Users"),
81
89
  content2
82
90
  ] });
83
91
  }
92
+ if (page.type === "splash") {
93
+ if (get(workspacesAtom).length === 0) {
94
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
95
+ meta("No workspace access"),
96
+ /* @__PURE__ */ jsx(AccessDenied, { canManageMembers, scope: "workspace" })
97
+ ] });
98
+ }
99
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
100
+ meta("Workspaces", true),
101
+ await splashPage(get)
102
+ ] });
103
+ }
84
104
  if (!workspace || !workspaceData) {
85
105
  return /* @__PURE__ */ jsxs(Fragment, { children: [
86
106
  meta("No workspace access"),
@@ -173,8 +193,8 @@ function App(props) {
173
193
  }
174
194
  function DashboardApp(props) {
175
195
  useInitAtoms(props);
176
- const [appPending, app] = useAtomValue(appAtom);
177
- const activity = useAtomValue(activityAtom);
196
+ const [appPending, app] = useAtomValueRaw(appAtom);
197
+ const activity = useAtomValueRaw(activityAtom);
178
198
  const [, setActivityPending] = useAtom(activityPendingAtom);
179
199
  const pending = appPending || activity.isFetchingUpdates || activity.isMutating;
180
200
  useEffect(() => {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  Provider
3
- } from "../chunks/chunk-U4VOHNR2.js";
3
+ } from "../chunks/chunk-D6UJHBJJ.js";
4
4
  import {
5
5
  createStore
6
- } from "../chunks/chunk-Y7XOMJOC.js";
6
+ } from "../chunks/chunk-CFNRVI3Y.js";
7
7
  import "../chunks/chunk-CQ52GEHY.js";
8
8
 
9
9
  // src/dashboard/StoryProvider.tsx
@@ -1,5 +1,20 @@
1
+ declare const copy: {
2
+ root: {
3
+ title: string;
4
+ message: string;
5
+ };
6
+ users: {
7
+ title: string;
8
+ message: string;
9
+ };
10
+ workspace: {
11
+ title: string;
12
+ message: string;
13
+ };
14
+ };
1
15
  export interface AccessDeniedProps {
2
16
  canManageMembers: boolean;
3
- scope: 'root' | 'workspace';
17
+ scope: keyof typeof copy;
4
18
  }
5
19
  export declare function AccessDenied({ canManageMembers, scope }: AccessDeniedProps): import("react").JSX.Element;
20
+ export {};
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  useSetAtom
3
- } from "../../chunks/chunk-U4VOHNR2.js";
4
- import "../../chunks/chunk-Y7XOMJOC.js";
3
+ } from "../../chunks/chunk-D6UJHBJJ.js";
4
+ import "../../chunks/chunk-CFNRVI3Y.js";
5
5
  import {
6
6
  styler
7
7
  } from "../../chunks/chunk-I4OYYAX5.js";
@@ -14,29 +14,38 @@ import { AppShell, AppShellContent, AppShellInner } from "./AppShell.js";
14
14
 
15
15
  // src/dashboard/app/AccessDenied.module.css
16
16
  var AccessDenied_default = {
17
- "AccessDenied-message": "alinea-AccessDenied-message",
18
- "AccessDeniedMessage": "alinea-AccessDenied-message",
19
17
  "AccessDenied": "alinea-AccessDenied",
20
18
  "AccessDenied-card": "alinea-AccessDenied-card",
21
19
  "AccessDeniedCard": "alinea-AccessDenied-card",
22
20
  "AccessDenied-title": "alinea-AccessDenied-title",
23
- "AccessDeniedTitle": "alinea-AccessDenied-title"
21
+ "AccessDeniedTitle": "alinea-AccessDenied-title",
22
+ "AccessDenied-message": "alinea-AccessDenied-message",
23
+ "AccessDeniedMessage": "alinea-AccessDenied-message"
24
24
  };
25
25
 
26
26
  // src/dashboard/app/AccessDenied.tsx
27
27
  import { jsx, jsxs } from "react/jsx-runtime";
28
28
  var styles = styler(AccessDenied_default);
29
+ var copy = {
30
+ root: {
31
+ title: "No root access",
32
+ message: "Your current roles do not grant permission to read any root."
33
+ },
34
+ users: {
35
+ title: "No user management access",
36
+ message: "Your current roles do not grant permission to manage users."
37
+ },
38
+ workspace: {
39
+ title: "No workspace access",
40
+ message: "Your current roles do not grant permission to read any workspace."
41
+ }
42
+ };
29
43
  function AccessDenied({ canManageMembers, scope }) {
30
44
  const setRoute = useSetAtom(routeAtom);
31
- const title = scope === "workspace" ? "No workspace access" : "No root access";
32
- const target = scope === "workspace" ? "workspace" : "root";
45
+ const { title, message } = copy[scope];
33
46
  return /* @__PURE__ */ jsx(AppShell, { children: /* @__PURE__ */ jsx(AppShellInner, { children: /* @__PURE__ */ jsx(AppShellContent, { children: /* @__PURE__ */ jsx("div", { className: styles.AccessDenied(), children: /* @__PURE__ */ jsxs(Surface, { className: styles.AccessDenied.card(), children: [
34
47
  /* @__PURE__ */ jsx("h1", { className: styles.AccessDenied.title(), children: title }),
35
- /* @__PURE__ */ jsxs("p", { className: styles.AccessDenied.message(), children: [
36
- "Your current roles do not grant permission to read any ",
37
- target,
38
- "."
39
- ] }),
48
+ /* @__PURE__ */ jsx("p", { className: styles.AccessDenied.message(), children: message }),
40
49
  canManageMembers && /* @__PURE__ */ jsx(
41
50
  Button,
42
51
  {
@@ -1,8 +1,8 @@
1
1
  import {
2
- useAtomValue,
2
+ useAtomValueRaw,
3
3
  useSetAtom
4
- } from "../../chunks/chunk-U4VOHNR2.js";
5
- import "../../chunks/chunk-Y7XOMJOC.js";
4
+ } from "../../chunks/chunk-D6UJHBJJ.js";
5
+ import "../../chunks/chunk-CFNRVI3Y.js";
6
6
  import {
7
7
  dist_default
8
8
  } from "../../chunks/chunk-I4OYYAX5.js";
@@ -42,29 +42,29 @@ import { IcRoundCheck, IcRoundHistory, IcRoundWarning } from "../icons.js";
42
42
 
43
43
  // src/dashboard/app/ActivityStatus.module.css
44
44
  var ActivityStatus_default = {
45
- "ActivityStatus-popover-actions": "alinea-ActivityStatus-popover-actions",
46
- "ActivityStatusPopoverActions": "alinea-ActivityStatus-popover-actions",
45
+ "is-syncing": "alinea-is-syncing",
46
+ "isSyncing": "alinea-is-syncing",
47
47
  "is-failed": "alinea-is-failed",
48
48
  "isFailed": "alinea-is-failed",
49
- "ActivityStatus-popover-header": "alinea-ActivityStatus-popover-header",
50
- "ActivityStatusPopoverHeader": "alinea-ActivityStatus-popover-header",
51
- "ActivityStatus-popover-surface": "alinea-ActivityStatus-popover-surface",
52
- "ActivityStatusPopoverSurface": "alinea-ActivityStatus-popover-surface",
53
- "ActivityStatus": "alinea-ActivityStatus",
54
49
  "ActivityStatus-label": "alinea-ActivityStatus-label",
55
50
  "ActivityStatusLabel": "alinea-ActivityStatus-label",
56
51
  "ActivityStatus-popover": "alinea-ActivityStatus-popover",
57
52
  "ActivityStatusPopover": "alinea-ActivityStatus-popover",
58
- "is-syncing": "alinea-is-syncing",
59
- "isSyncing": "alinea-is-syncing",
60
- "ActivityStatus-popover-title": "alinea-ActivityStatus-popover-title",
61
- "ActivityStatusPopoverTitle": "alinea-ActivityStatus-popover-title",
53
+ "ActivityStatus-popover-header": "alinea-ActivityStatus-popover-header",
54
+ "ActivityStatusPopoverHeader": "alinea-ActivityStatus-popover-header",
55
+ "ActivityStatus": "alinea-ActivityStatus",
56
+ "ActivityStatus-popover-surface": "alinea-ActivityStatus-popover-surface",
57
+ "ActivityStatusPopoverSurface": "alinea-ActivityStatus-popover-surface",
62
58
  "ActivityStatus-popover-list": "alinea-ActivityStatus-popover-list",
63
59
  "ActivityStatusPopoverList": "alinea-ActivityStatus-popover-list",
60
+ "ActivityStatus-popover-item-error": "alinea-ActivityStatus-popover-item-error",
61
+ "ActivityStatusPopoverItemError": "alinea-ActivityStatus-popover-item-error",
64
62
  "ActivityStatus-icon": "alinea-ActivityStatus-icon",
65
63
  "ActivityStatusIcon": "alinea-ActivityStatus-icon",
66
- "ActivityStatus-popover-item-error": "alinea-ActivityStatus-popover-item-error",
67
- "ActivityStatusPopoverItemError": "alinea-ActivityStatus-popover-item-error"
64
+ "ActivityStatus-popover-title": "alinea-ActivityStatus-popover-title",
65
+ "ActivityStatusPopoverTitle": "alinea-ActivityStatus-popover-title",
66
+ "ActivityStatus-popover-actions": "alinea-ActivityStatus-popover-actions",
67
+ "ActivityStatusPopoverActions": "alinea-ActivityStatus-popover-actions"
68
68
  };
69
69
 
70
70
  // src/dashboard/app/ActivityStatus.tsx
@@ -95,8 +95,8 @@ function ActivityStatus({
95
95
  openOnFail = false,
96
96
  placement = "right"
97
97
  }) {
98
- const [appPending] = useAtomValue(appAtom);
99
- const activity = useAtomValue(activityAtom);
98
+ const [appPending] = useAtomValueRaw(appAtom);
99
+ const activity = useAtomValueRaw(activityAtom);
100
100
  const retry = useSetAtom(retryActivityAtom);
101
101
  const discard = useSetAtom(discardActivityAtom);
102
102
  const [isOpen, setIsOpen] = useState(false);
@@ -112,7 +112,7 @@ function ActivityStatus({
112
112
  appPending,
113
113
  activity.isMutating
114
114
  );
115
- const showSpinner = useAtomValue(activityPendingAtom);
115
+ const showSpinner = useAtomValueRaw(activityPendingAtom);
116
116
  if (activityLabel !== void 0) lastActivityLabel.current = activityLabel;
117
117
  const visibleActivityLabel = activityLabel ?? (showSpinner ? lastActivityLabel.current : void 0);
118
118
  const label = getStatusLabel(
@@ -0,0 +1 @@
1
+ export declare function AppearanceToggle(): import("react").JSX.Element;
@@ -0,0 +1,43 @@
1
+ import {
2
+ useAtom
3
+ } from "../../chunks/chunk-D6UJHBJJ.js";
4
+ import "../../chunks/chunk-CFNRVI3Y.js";
5
+ import "../../chunks/chunk-CQ52GEHY.js";
6
+
7
+ // src/dashboard/app/AppearanceToggle.tsx
8
+ import { ToggleButton, ToggleButtonGroup } from "alinea/components";
9
+ import { themeAtom } from "alinea/dashboard/atoms/dashboard";
10
+ import {
11
+ IcRoundBrightness2,
12
+ IcRoundDesktopWindows,
13
+ IcRoundWbSunny
14
+ } from "../icons.js";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
+ function AppearanceToggle() {
17
+ const [theme, setTheme] = useAtom(themeAtom);
18
+ return /* @__PURE__ */ jsxs(
19
+ ToggleButtonGroup,
20
+ {
21
+ "aria-label": "Appearance",
22
+ disallowEmptySelection: true,
23
+ selectedKeys: [theme],
24
+ selectionMode: "single",
25
+ variant: "icon-small",
26
+ onSelectionChange: (keys) => {
27
+ const selectedTheme = [...keys].at(0);
28
+ if (isDashboardTheme(selectedTheme)) setTheme(selectedTheme);
29
+ },
30
+ children: [
31
+ /* @__PURE__ */ jsx(ToggleButton, { id: "system", "aria-label": "Use system theme", children: /* @__PURE__ */ jsx(IcRoundDesktopWindows, { "aria-hidden": true, "data-slot": "icon" }) }),
32
+ /* @__PURE__ */ jsx(ToggleButton, { id: "light", "aria-label": "Use light theme", children: /* @__PURE__ */ jsx(IcRoundWbSunny, { "aria-hidden": true, "data-slot": "icon" }) }),
33
+ /* @__PURE__ */ jsx(ToggleButton, { id: "dark", "aria-label": "Use dark theme", children: /* @__PURE__ */ jsx(IcRoundBrightness2, { "aria-hidden": true, "data-slot": "icon" }) })
34
+ ]
35
+ }
36
+ );
37
+ }
38
+ function isDashboardTheme(value) {
39
+ return value === "system" || value === "light" || value === "dark";
40
+ }
41
+ export {
42
+ AppearanceToggle
43
+ };