@protobase/ui 0.63.3 → 0.63.5

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 (113) hide show
  1. package/dist/account/devices-section.js +1 -1
  2. package/dist/account/passkeys-section.js +1 -1
  3. package/dist/account/staff-sign-in-log.js +1 -1
  4. package/dist/activity-chart/activity-chart.js +2 -2
  5. package/dist/activity-chart/activity-tooltip.js +1 -1
  6. package/dist/app/app.js +1 -1
  7. package/dist/app/change-confirm/use-change-confirm.js +15 -18
  8. package/dist/app/charts/chart-view.js +1 -1
  9. package/dist/app/comments/comment-composer.js +1 -1
  10. package/dist/app/comments/comments-section.js +2 -2
  11. package/dist/app/create/create-record-form.js +1 -1
  12. package/dist/app/custom-section.js +1 -1
  13. package/dist/app/delete/use-delete-flow.js +1 -1
  14. package/dist/app/displays/board-column.js +1 -1
  15. package/dist/app/displays/calendar-display.js +1 -1
  16. package/dist/app/displays/cards-display.js +1 -1
  17. package/dist/app/displays/list-cards.js +1 -1
  18. package/dist/app/displays/timeline-display.js +1 -1
  19. package/dist/app/displays/use-board-move.js +1 -1
  20. package/dist/app/displays/use-calendar-move.js +1 -1
  21. package/dist/app/embedded-list/embedded-list.js +1 -1
  22. package/dist/app/field-editor.js +2 -2
  23. package/dist/app/gallery/gallery-section.js +1 -1
  24. package/dist/app/gallery/photo-details.js +1 -1
  25. package/dist/app/hand-order/hand-sorted-list.js +1 -1
  26. package/dist/app/hand-order/use-hand-order.js +1 -1
  27. package/dist/app/history/history-section.js +1 -1
  28. package/dist/app/incoming-card.js +1 -1
  29. package/dist/app/lines-plan.js +116 -0
  30. package/dist/app/list-edit/use-list-edits.js +1 -1
  31. package/dist/app/list-order.js +7 -1
  32. package/dist/app/new-version/new-version-toast.js +1 -1
  33. package/dist/app/pages/blocks/field.js +1 -1
  34. package/dist/app/pages/blocks/modal-form.js +2 -2
  35. package/dist/app/pages/blocks/settings.js +2 -2
  36. package/dist/app/pages/record-actions.js +1 -1
  37. package/dist/app/pages/use-run-action.js +1 -1
  38. package/dist/app/picker/picker-combobox.js +1 -1
  39. package/dist/app/record-chart/record-chart-section.js +2 -2
  40. package/dist/app/record-lines-cell.js +47 -0
  41. package/dist/app/record-lines.js +103 -26
  42. package/dist/app/record-messages.js +8 -2
  43. package/dist/app/record-page.js +18 -20
  44. package/dist/app/record-row/record-row-body.js +1 -1
  45. package/dist/app/record-row/record-row.js +1 -1
  46. package/dist/app/record-row/saved-record-row.js +1 -1
  47. package/dist/app/related-cards/related-card.js +1 -1
  48. package/dist/app/related-cards/related-cards.js +1 -1
  49. package/dist/app/related-section.js +1 -1
  50. package/dist/app/saved/saved-list.js +1 -1
  51. package/dist/app/searches/saved-search-rows.js +1 -1
  52. package/dist/app/searches/saved-search-section.js +1 -1
  53. package/dist/app/searches/saved-searches.js +1 -1
  54. package/dist/app/searches/search-controls.js +1 -1
  55. package/dist/app/searches/update-search-dialog.js +1 -1
  56. package/dist/app/searches/use-save-search.js +1 -1
  57. package/dist/app/sensitive-field.js +1 -1
  58. package/dist/app/use-lines-draft.js +94 -35
  59. package/dist/app/use-lines.js +21 -7
  60. package/dist/app/use-record-editor.js +15 -10
  61. package/dist/app/use-record-lines.js +47 -0
  62. package/dist/app-shell/profile-menu.js +2 -2
  63. package/dist/auth/forgot-password-form.js +1 -1
  64. package/dist/auth/sign-in-form.js +1 -1
  65. package/dist/calls/call-guests-panel.js +1 -1
  66. package/dist/calls/call-rings.js +1 -1
  67. package/dist/chat/chat-message.js +1 -1
  68. package/dist/data/use-list.d.ts +27 -1
  69. package/dist/data/use-list.js +10 -3
  70. package/dist/data-grid/cell-text.js +3 -3
  71. package/dist/data-grid/cells.js +3 -3
  72. package/dist/data-grid/grid-row.js +1 -1
  73. package/dist/forms/public-form-page.js +1 -1
  74. package/dist/index.js +3 -3
  75. package/dist/inline-child-table/columns.js +7 -2
  76. package/dist/inline-child-table/inline-child-table.js +29 -48
  77. package/dist/inline-child-table/line-row.js +16 -44
  78. package/dist/inline-child-table/messages.js +4 -18
  79. package/dist/notifications/bell/notification-item.js +1 -1
  80. package/dist/organizations/invitation-page.js +1 -1
  81. package/dist/package.js +1 -1
  82. package/dist/primitives/dialog.d.ts +7 -2
  83. package/dist/primitives/dialog.js +9 -4
  84. package/dist/record-view/field.js +1 -1
  85. package/dist/record-view/messages.js +0 -4
  86. package/dist/record-view/record-header.js +2 -2
  87. package/dist/shell/assets/app-BPv_SjnU.js +9 -0
  88. package/dist/shell/assets/{calls-CEW8hdPi.js → calls-CPiQcC70.js} +2 -2
  89. package/dist/shell/assets/index-Or2wt-ck.css +2 -0
  90. package/dist/shell/assets/{index-D7O0sMwH.js → index-_ZpZ2ro0.js} +2 -2
  91. package/dist/shell/assets/{records-map-BIDl1ull.js → records-map-DU29d6QK.js} +2 -2
  92. package/dist/shell/assets/shared-protobase-ui-Cab5nqST.js +2 -0
  93. package/dist/shell/assets/{vendor-xNCj9Gc_.js → vendor-iwLB0x-s.js} +39 -39
  94. package/dist/shell/index.html +5 -5
  95. package/dist/shell/protobase.shell.json +2 -2
  96. package/dist/shell/protobase.sw.js +2 -2
  97. package/dist/shell-source-maps/assets/app-BPv_SjnU.js.map +1 -0
  98. package/dist/shell-source-maps/assets/{calls-CEW8hdPi.js.map → calls-CPiQcC70.js.map} +1 -1
  99. package/dist/shell-source-maps/assets/{index-D7O0sMwH.js.map → index-_ZpZ2ro0.js.map} +1 -1
  100. package/dist/shell-source-maps/assets/{records-map-BIDl1ull.js.map → records-map-DU29d6QK.js.map} +1 -1
  101. package/dist/shell-source-maps/assets/{shared-protobase-ui-F5elmh4N.js.map → shared-protobase-ui-Cab5nqST.js.map} +1 -1
  102. package/dist/shell-source-maps/assets/vendor-iwLB0x-s.js.map +1 -0
  103. package/dist/status/status-dialog.js +1 -1
  104. package/package.json +4 -4
  105. package/dist/inline-child-table/number-cell.js +0 -25
  106. package/dist/inline-child-table/totals-footer.js +0 -39
  107. package/dist/mocks/invoices.js +0 -13
  108. package/dist/mocks/products.js +0 -167
  109. package/dist/shell/assets/app-Bm6h0l5D.js +0 -9
  110. package/dist/shell/assets/index-Be8nCyRW.css +0 -2
  111. package/dist/shell/assets/shared-protobase-ui-F5elmh4N.js +0 -2
  112. package/dist/shell-source-maps/assets/app-Bm6h0l5D.js.map +0 -1
  113. package/dist/shell-source-maps/assets/vendor-xNCj9Gc_.js.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { text } from "./messages.js";
2
2
  import { Button } from "../primitives/button.js";
3
3
  import { Dialog } from "../primitives/dialog.js";
4
- import { formatDateTime } from "../format/date.js";
5
4
  import { Badge } from "../primitives/badge.js";
5
+ import { formatDateTime } from "../format/date.js";
6
6
  import { AccountSection, SectionError } from "./account-section.js";
7
7
  import { authMessage } from "../auth/auth-messages.js";
8
8
  import { deviceOf } from "./device-name.js";
@@ -1,9 +1,9 @@
1
1
  import { text } from "./messages.js";
2
2
  import { Button } from "../primitives/button.js";
3
3
  import { Dialog } from "../primitives/dialog.js";
4
+ import { Badge } from "../primitives/badge.js";
4
5
  import { formatDate } from "../format/date.js";
5
6
  import { Input } from "../primitives/input.js";
6
- import { Badge } from "../primitives/badge.js";
7
7
  import { AccountSection, SectionError } from "./account-section.js";
8
8
  import { authMessage } from "../auth/auth-messages.js";
9
9
  import { useState } from "react";
@@ -1,6 +1,6 @@
1
1
  import { text } from "./messages.js";
2
- import { formatDateTime } from "../format/date.js";
3
2
  import { Badge } from "../primitives/badge.js";
3
+ import { formatDateTime } from "../format/date.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,8 +1,8 @@
1
1
  import { cn } from "../lib/cn.js";
2
2
  import { useMediaQuery } from "../lib/use-media-query.js";
3
- import { activitySeries } from "../mocks/activity.js";
4
- import { formatInt } from "../format/number.js";
5
3
  import { formatDayShort } from "../format/date.js";
4
+ import { formatInt } from "../format/number.js";
5
+ import { activitySeries } from "../mocks/activity.js";
6
6
  import { Segmented } from "../primitives/segmented.js";
7
7
  import { halfOverHalfDelta, totalCount } from "./activity-math.js";
8
8
  import { ActivityTooltip } from "./activity-tooltip.js";
@@ -1,5 +1,5 @@
1
- import { formatInt } from "../format/number.js";
2
1
  import { formatDate } from "../format/date.js";
2
+ import { formatInt } from "../format/number.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/activity-chart/activity-tooltip.tsx
5
5
  const ActivityTooltip = ({ active, payload, noun }) => {
package/dist/app/app.js CHANGED
@@ -5,7 +5,6 @@ import { ApiProvider } from "../data/api-provider.js";
5
5
  import { sourceStatusOf } from "../data/with-sources.js";
6
6
  import { MetaGate, Notice, useAdminMeta } from "./meta-gate.js";
7
7
  import { pageTabs, shownPageTab } from "./pages/page-tabs.js";
8
- import { ToastProvider } from "../toasts/toast-provider.js";
9
8
  import { humanize } from "../live/naming.js";
10
9
  import { text } from "./messages.js";
11
10
  import { Router, useRouter } from "./router.js";
@@ -17,6 +16,7 @@ import { isAdmin, userToShell } from "../auth/user-to-shell.js";
17
16
  import { startErrorReporting } from "./error-reporting.js";
18
17
  import { slotted } from "../locale/slotted.js";
19
18
  import { CustomBoundary } from "./pages/custom-boundary.js";
19
+ import { ToastProvider } from "../toasts/toast-provider.js";
20
20
  import { useSidebarNoticeShown } from "../app-shell/sidebar-notice.js";
21
21
  import { AppShell } from "../app-shell/app-shell.js";
22
22
  import { useSignInAddress } from "../auth/use-sign-in-address.js";
@@ -5,13 +5,12 @@ import { asksToConfirm } from "./asks-to-confirm.js";
5
5
  import { text } from "./messages.js";
6
6
  import { useState } from "react";
7
7
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
8
- import { createPortal } from "react-dom";
9
8
  //#region src/app/change-confirm/use-change-confirm.tsx
10
9
  /**
11
10
  * Whether `node` sits in the question a change asks. The dialog is portalled to the body, so a list cell does not clip
12
11
  * it, while its events still bubble through the editor that asked it.
13
12
  */
14
- const inChangeConfirm = (node) => node instanceof Element && node.closest("[data-change-confirm]") !== null;
13
+ const inChangeConfirm = (node) => node instanceof Element && node.closest("[data-dialog=\"change-confirm\"]") !== null;
15
14
  /**
16
15
  * The field's `onChange`, asking the view's `.confirm()` question before it hands on a change that `asksToConfirm`
17
16
  * picks out, and the dialog that asks it. Cancelling drops the change, so the field keeps its value.
@@ -29,22 +28,20 @@ const useChangeConfirm = ({ field, hints, value, stored, onChange }) => {
29
28
  };
30
29
  return {
31
30
  onChange: change,
32
- dialog: pending && createPortal(/* @__PURE__ */ jsx("div", {
33
- "data-change-confirm": "",
34
- children: /* @__PURE__ */ jsx(Dialog, {
35
- title: text("title", hints?.label ?? humanize(field.name)),
36
- description: hints?.confirm,
37
- onClose: cancel,
38
- actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
39
- onClick: cancel,
40
- children: text("cancel")
41
- }), /* @__PURE__ */ jsx(Button, {
42
- variant: "primary",
43
- onClick: confirm,
44
- children: text("change")
45
- })] })
46
- })
47
- }), document.body)
31
+ dialog: pending && /* @__PURE__ */ jsx(Dialog, {
32
+ name: "change-confirm",
33
+ title: text("title", hints?.label ?? humanize(field.name)),
34
+ description: hints?.confirm,
35
+ onClose: cancel,
36
+ actions: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Button, {
37
+ onClick: cancel,
38
+ children: text("cancel")
39
+ }), /* @__PURE__ */ jsx(Button, {
40
+ variant: "primary",
41
+ onClick: confirm,
42
+ children: text("change")
43
+ })] })
44
+ })
48
45
  };
49
46
  };
50
47
  //#endregion
@@ -1,7 +1,7 @@
1
1
  import { useAdminMeta } from "../meta-gate.js";
2
2
  import { viewerZone } from "../../format/zone.js";
3
- import { Skeleton } from "../../primitives/skeleton.js";
4
3
  import { labelFieldOf } from "../../live/model-helpers.js";
4
+ import { Skeleton } from "../../primitives/skeleton.js";
5
5
  import { useAggregate } from "../../data/use-aggregates.js";
6
6
  import { text } from "./messages.js";
7
7
  import { periodPoints, valueSlices } from "./chart-groups.js";
@@ -1,8 +1,8 @@
1
1
  import { useClient } from "../../data/api-provider.js";
2
2
  import { Button } from "../../primitives/button.js";
3
- import { useToast } from "../../toasts/toast-provider.js";
4
3
  import { refusalReason } from "../displays/board-columns.js";
5
4
  import { useNavigationGuard } from "../router.js";
5
+ import { useToast } from "../../toasts/toast-provider.js";
6
6
  import { mentionedIds } from "../../mentions/mention-text.js";
7
7
  import { MentionBox, emptyDraft } from "../../mentions/mention-box.js";
8
8
  import { usePostComment } from "./use-post-comment.js";
@@ -1,8 +1,8 @@
1
1
  import { Button } from "../../primitives/button.js";
2
- import { formatDateTime, formatRelativeTime } from "../../format/date.js";
3
- import { Skeleton } from "../../primitives/skeleton.js";
4
2
  import { Avatar } from "../../primitives/avatar.js";
5
3
  import { Section } from "../../record-view/section.js";
4
+ import { formatDateTime, formatRelativeTime } from "../../format/date.js";
5
+ import { Skeleton } from "../../primitives/skeleton.js";
6
6
  import { ErrorBanner } from "../error-banner.js";
7
7
  import { hueOf, initialsOf } from "../../auth/user-to-shell.js";
8
8
  import { CommentBody } from "./comment-body.js";
@@ -1,5 +1,5 @@
1
- import { Field } from "../../record-view/field.js";
2
1
  import { Section } from "../../record-view/section.js";
2
+ import { Field } from "../../record-view/field.js";
3
3
  import { text } from "./messages.js";
4
4
  import { Form } from "./form.js";
5
5
  import { jsx } from "react/jsx-runtime";
@@ -1,6 +1,6 @@
1
1
  import { Section } from "../record-view/section.js";
2
- import { SidebarCard } from "../record-view/record-sidebar.js";
3
2
  import { text } from "./messages.js";
3
+ import { SidebarCard } from "../record-view/record-sidebar.js";
4
4
  import { useProjectUi } from "./pages/project-ui.js";
5
5
  import { Problem } from "./pages/problem.js";
6
6
  import { slotted } from "../locale/slotted.js";
@@ -1,8 +1,8 @@
1
1
  import { useClient } from "../../data/api-provider.js";
2
2
  import { useAdminMeta } from "../meta-gate.js";
3
- import { useToast } from "../../toasts/toast-provider.js";
4
3
  import { humanize } from "../../live/naming.js";
5
4
  import { useAppAddress } from "../use-app-address.js";
5
+ import { useToast } from "../../toasts/toast-provider.js";
6
6
  import { text } from "./messages.js";
7
7
  import { blockedDelete } from "./blocked-delete.js";
8
8
  import { BulkDeleteDialog, ConfirmDeleteDialog, ConflictDialog } from "./dialogs.js";
@@ -1,10 +1,10 @@
1
1
  import { formatTag } from "../../locale/active-locale.js";
2
2
  import { cn } from "../../lib/cn.js";
3
3
  import { Button } from "../../primitives/button.js";
4
- import { Skeleton } from "../../primitives/skeleton.js";
5
4
  import { humanize } from "../../live/naming.js";
6
5
  import { text } from "./messages.js";
7
6
  import { boardCard } from "./board-columns.js";
7
+ import { Skeleton } from "../../primitives/skeleton.js";
8
8
  import { ErrorBanner } from "../error-banner.js";
9
9
  import { rowAllows } from "../permissions.js";
10
10
  import { ValueBadge } from "../value-badge.js";
@@ -2,8 +2,8 @@ import { cn } from "../../lib/cn.js";
2
2
  import { usePermissions } from "../meta-gate.js";
3
3
  import { dayIn, viewerZone } from "../../format/zone.js";
4
4
  import { formatDate, formatWeekday } from "../../format/date.js";
5
- import { Skeleton } from "../../primitives/skeleton.js";
6
5
  import { text } from "./messages.js";
6
+ import { Skeleton } from "../../primitives/skeleton.js";
7
7
  import { AppLink } from "../use-app-address.js";
8
8
  import { ErrorBanner } from "../error-banner.js";
9
9
  import { can, rowAllows } from "../permissions.js";
@@ -1,7 +1,7 @@
1
1
  import { cn } from "../../lib/cn.js";
2
- import { Skeleton } from "../../primitives/skeleton.js";
3
2
  import { humanize } from "../../live/naming.js";
4
3
  import { text } from "./messages.js";
4
+ import { Skeleton } from "../../primitives/skeleton.js";
5
5
  import { RecordCard } from "./record-card.js";
6
6
  import { DisplayFooter, DisplayState } from "./display-frame.js";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -1,7 +1,7 @@
1
- import { Skeleton } from "../../primitives/skeleton.js";
2
1
  import { humanize } from "../../live/naming.js";
3
2
  import { text } from "./messages.js";
4
3
  import { displayRow } from "./list-displays.js";
4
+ import { Skeleton } from "../../primitives/skeleton.js";
5
5
  import { ErrorBanner } from "../error-banner.js";
6
6
  import { RecordCard } from "./record-card.js";
7
7
  import { VirtualCards } from "./virtual-cards.js";
@@ -1,9 +1,9 @@
1
1
  import { usePermissions } from "../meta-gate.js";
2
2
  import { dayIn, viewerZone } from "../../format/zone.js";
3
3
  import { formatDate } from "../../format/date.js";
4
- import { Skeleton } from "../../primitives/skeleton.js";
5
4
  import { humanize } from "../../live/naming.js";
6
5
  import { text } from "./messages.js";
6
+ import { Skeleton } from "../../primitives/skeleton.js";
7
7
  import { ErrorBanner } from "../error-banner.js";
8
8
  import { can, rowAllows } from "../permissions.js";
9
9
  import { addDays, inStartOrder, recordDays } from "./calendar-range.js";
@@ -1,8 +1,8 @@
1
1
  import { useClient } from "../../data/api-provider.js";
2
- import { useToast } from "../../toasts/toast-provider.js";
3
2
  import { recordKey } from "../../live/model-helpers.js";
4
3
  import { text } from "./messages.js";
5
4
  import { refusalReason } from "./board-columns.js";
5
+ import { useToast } from "../../toasts/toast-provider.js";
6
6
  import { useRefreshResource } from "../pages/use-layout-data.js";
7
7
  import { dropWrite } from "./board-drop.js";
8
8
  import { text as text$1 } from "../hand-order/messages.js";
@@ -1,9 +1,9 @@
1
1
  import { useClient } from "../../data/api-provider.js";
2
2
  import { formatDate } from "../../format/date.js";
3
- import { useToast } from "../../toasts/toast-provider.js";
4
3
  import { recordKey } from "../../live/model-helpers.js";
5
4
  import { text } from "./messages.js";
6
5
  import { refusalReason } from "./board-columns.js";
6
+ import { useToast } from "../../toasts/toast-provider.js";
7
7
  import { useRefreshResource } from "../pages/use-layout-data.js";
8
8
  import { movedPatch } from "./calendar-range.js";
9
9
  import { useState } from "react";
@@ -1,10 +1,10 @@
1
1
  import { useAdminMeta, usePermissions } from "../meta-gate.js";
2
2
  import { useIsDesktop, useIsXs } from "../../lib/use-media-query.js";
3
- import { Skeleton } from "../../primitives/skeleton.js";
4
3
  import { humanize } from "../../live/naming.js";
5
4
  import { listColumnNames } from "../../live/columns-from-model.js";
6
5
  import { displayRow, loadedFields, shownDisplay } from "../displays/list-displays.js";
7
6
  import { defaultOrderBy, parseSort, sortToOrderBy } from "../list-order.js";
7
+ import { Skeleton } from "../../primitives/skeleton.js";
8
8
  import { AppLink, useAppAddress } from "../use-app-address.js";
9
9
  import { ErrorBanner } from "../error-banner.js";
10
10
  import { useProjectUi } from "../pages/project-ui.js";
@@ -1,13 +1,13 @@
1
1
  import { cn } from "../lib/cn.js";
2
2
  import { buttonClass } from "../primitives/button.js";
3
- import { useFieldControl } from "../primitives/field-control.js";
4
- import { Input } from "../primitives/input.js";
5
3
  import { humanize } from "../live/naming.js";
6
4
  import { isMarkdown } from "../markdown/markdown-hint.js";
7
5
  import { contactFormat, contactInputProps } from "../live/contact-links.js";
8
6
  import { displayValue, valueTitle } from "../live/display-value.js";
9
7
  import { text } from "./messages.js";
10
8
  import { AppLink } from "./use-app-address.js";
9
+ import { useFieldControl } from "../primitives/field-control.js";
10
+ import { Input } from "../primitives/input.js";
11
11
  import { fromDraft, isEditable, toFieldDraft } from "../live/field-values.js";
12
12
  import { Switch } from "../primitives/switch.js";
13
13
  import { Textarea } from "../primitives/textarea.js";
@@ -1,9 +1,9 @@
1
1
  import { cn } from "../../lib/cn.js";
2
2
  import { useAdminMeta, usePermissions } from "../meta-gate.js";
3
- import { Skeleton } from "../../primitives/skeleton.js";
4
3
  import { Section } from "../../record-view/section.js";
5
4
  import { shownImage } from "../../live/file-values.js";
6
5
  import { humanize } from "../../live/naming.js";
6
+ import { Skeleton } from "../../primitives/skeleton.js";
7
7
  import { ErrorBanner } from "../error-banner.js";
8
8
  import { FileImage } from "../../live/file-image.js";
9
9
  import { galleryTiles } from "./gallery-layout.js";
@@ -1,5 +1,5 @@
1
- import { Skeleton } from "../../primitives/skeleton.js";
2
1
  import { humanize } from "../../live/naming.js";
2
+ import { Skeleton } from "../../primitives/skeleton.js";
3
3
  import { AppLink } from "../use-app-address.js";
4
4
  import { SpecTable } from "../../record-view/spec-table.js";
5
5
  import { ErrorBanner } from "../error-banner.js";
@@ -1,7 +1,7 @@
1
1
  import { useAdminMeta } from "../meta-gate.js";
2
- import { Skeleton } from "../../primitives/skeleton.js";
3
2
  import { recordKey, recordTitle } from "../../live/model-helpers.js";
4
3
  import { loadedFields } from "../displays/list-displays.js";
4
+ import { Skeleton } from "../../primitives/skeleton.js";
5
5
  import { useAppAddress } from "../use-app-address.js";
6
6
  import { ErrorBanner } from "../error-banner.js";
7
7
  import { useProjectUi } from "../pages/project-ui.js";
@@ -1,10 +1,10 @@
1
1
  import { keys } from "../../data/query-keys.js";
2
2
  import { useClient } from "../../data/api-provider.js";
3
3
  import { useAdminMeta } from "../meta-gate.js";
4
- import { useToast } from "../../toasts/toast-provider.js";
5
4
  import { recordId, recordKey, recordTitle } from "../../live/model-helpers.js";
6
5
  import { refusalReason } from "../displays/board-columns.js";
7
6
  import { displayRow } from "../displays/list-displays.js";
7
+ import { useToast } from "../../toasts/toast-provider.js";
8
8
  import { useRefreshResource } from "../pages/use-layout-data.js";
9
9
  import { listLabels, withLabels } from "../../live/relation-labels.js";
10
10
  import { text } from "./messages.js";
@@ -1,7 +1,7 @@
1
1
  import { Button } from "../../primitives/button.js";
2
+ import { Section } from "../../record-view/section.js";
2
3
  import { formatDateTime, formatRelativeTime } from "../../format/date.js";
3
4
  import { Skeleton } from "../../primitives/skeleton.js";
4
- import { Section } from "../../record-view/section.js";
5
5
  import { ErrorBanner } from "../error-banner.js";
6
6
  import { describeChange } from "./describe-change.js";
7
7
  import { useRecordHistory } from "./use-record-history.js";
@@ -1,8 +1,8 @@
1
1
  import { useAdminMeta } from "./meta-gate.js";
2
2
  import { formatInt } from "../format/number.js";
3
3
  import { Skeleton } from "../primitives/skeleton.js";
4
- import { SidebarCard } from "../record-view/record-sidebar.js";
5
4
  import { AppLink } from "./use-app-address.js";
5
+ import { SidebarCard } from "../record-view/record-sidebar.js";
6
6
  import { text } from "./record-messages.js";
7
7
  import { incomingAddress, incomingRelations } from "./incoming-relations.js";
8
8
  import { useIncomingCounts } from "./use-incoming-counts.js";
@@ -0,0 +1,116 @@
1
+ import { recordId, recordKey } from "../live/model-helpers.js";
2
+ import { differs, toPatchValue } from "../live/field-values.js";
3
+ import { encodeKey } from "@protobase/schema/internal";
4
+ //#region src/app/lines-plan.ts
5
+ const emptyLinesState = {
6
+ added: [],
7
+ edits: {},
8
+ removed: []
9
+ };
10
+ /** The ids on screen, in order: the stored lines that are kept, then the new ones, as far as `order` does not say otherwise. */
11
+ const shownIds = (storedIds, state) => {
12
+ const kept = [...storedIds.filter((id) => !state.removed.includes(id)), ...state.added];
13
+ if (!state.order) return kept;
14
+ return [...state.order.filter((id) => kept.includes(id)), ...kept.filter((id) => !state.order.includes(id))];
15
+ };
16
+ /** The edited fields that differ from the stored line, as the API takes them. */
17
+ const changedData = (model, edits, line) => Object.fromEntries(Object.entries(edits).flatMap(([name, draft]) => {
18
+ const field = model.fields[name];
19
+ return field && differs(field, draft, line[name]) ? [[name, toPatchValue(field, draft)]] : [];
20
+ }));
21
+ /** The fields filled in on a new line; the database's defaults fill the rest. */
22
+ const filledData = (model, edits) => Object.fromEntries(Object.entries(edits).flatMap(([name, draft]) => {
23
+ const field = model.fields[name];
24
+ if (!field || field.type !== "boolean" && String(draft ?? "").trim() === "") return [];
25
+ return [[name, toPatchValue(field, draft)]];
26
+ }));
27
+ /**
28
+ * The batch that writes the lines as they are on screen: removed lines are deleted, edited ones updated with the ETag
29
+ * they were read with, and new ones created with the parent's key and their place. New lines after the kept ones are
30
+ * numbered on from them; new lines between kept ones need the kept ones out of the way first, so those are moved above
31
+ * every position in use, the new lines created at their places, and the kept ones moved to theirs. A kept line the batch
32
+ * wrote before is moved with `*`, as its ETag was checked by that earlier operation of the same transaction.
33
+ */
34
+ const planLinesOps = ({ model, position, link, stored, state }) => {
35
+ const plan = {
36
+ ops: [],
37
+ rows: []
38
+ };
39
+ const push = (op, row) => {
40
+ plan.ops.push(op);
41
+ plan.rows.push(row);
42
+ };
43
+ const byId = new Map(stored.map((line) => [recordId(model, line), line]));
44
+ const storedIds = [...byId.keys()];
45
+ const final = shownIds(storedIds, state);
46
+ const keyOf = (id) => recordKey(model, byId.get(id));
47
+ const etagOf = (id) => {
48
+ const etag = byId.get(id).etag;
49
+ return typeof etag === "string" ? etag : void 0;
50
+ };
51
+ for (const id of state.removed) {
52
+ if (!byId.has(id)) continue;
53
+ const etag = etagOf(id);
54
+ push({
55
+ op: "delete",
56
+ resource: model.name,
57
+ key: keyOf(id),
58
+ ...etag && { etag }
59
+ }, id);
60
+ }
61
+ const written = /* @__PURE__ */ new Set();
62
+ for (const [id, edits] of Object.entries(state.edits)) {
63
+ if (!byId.has(id) || state.removed.includes(id)) continue;
64
+ const data = changedData(model, edits, byId.get(id));
65
+ if (Object.keys(data).length === 0) continue;
66
+ const etag = etagOf(id);
67
+ push({
68
+ op: "update",
69
+ resource: model.name,
70
+ key: keyOf(id),
71
+ data,
72
+ ...etag && { etag }
73
+ }, id);
74
+ written.add(id);
75
+ }
76
+ const kept = final.filter((id) => byId.has(id));
77
+ const added = final.filter((id) => !byId.has(id));
78
+ const etags = (ids, wildcard) => Object.fromEntries(ids.flatMap((id) => {
79
+ const etag = wildcard || written.has(id) ? "*" : etagOf(id);
80
+ return etag ? [[encodeKey(keyOf(id)), etag]] : [];
81
+ }));
82
+ const reorder = (keys, start, tags) => ({
83
+ op: "reorder",
84
+ resource: model.name,
85
+ field: position,
86
+ keys,
87
+ ...start !== 1 && { start },
88
+ etags: tags
89
+ });
90
+ const create = (id, place, ref) => ({
91
+ op: "create",
92
+ resource: model.name,
93
+ data: {
94
+ ...filledData(model, state.edits[id] ?? {}),
95
+ [link.field]: link.value,
96
+ [position]: place
97
+ },
98
+ ...ref && { ref }
99
+ });
100
+ const placeOf = (line) => Number(line[position]) || 0;
101
+ const moved = kept.some((id, index) => id !== storedIds.filter((each) => kept.includes(each))[index]);
102
+ if (added.every((id) => final.indexOf(id) >= kept.length)) {
103
+ if (moved) push(reorder(kept.map(keyOf), 1, etags(kept, false)));
104
+ const last = moved ? kept.length : Math.max(0, ...kept.map((id) => placeOf(byId.get(id))));
105
+ added.forEach((id, index) => push(create(id, last + 1 + index), id));
106
+ return plan;
107
+ }
108
+ const above = Math.max(final.length, ...stored.map(placeOf)) + 1;
109
+ if (kept.length > 0) push(reorder(kept.map(keyOf), above, etags(kept, false)));
110
+ const refOf = (id) => `line${added.indexOf(id) + 1}`;
111
+ for (const id of added) push(create(id, final.indexOf(id) + 1, refOf(id)), id);
112
+ push(reorder(final.map((id) => byId.has(id) ? keyOf(id) : { $ref: refOf(id) }), 1, etags(kept, true)));
113
+ return plan;
114
+ };
115
+ //#endregion
116
+ export { emptyLinesState, planLinesOps, shownIds };
@@ -1,7 +1,7 @@
1
1
  import { keys } from "../../data/query-keys.js";
2
2
  import { useClient } from "../../data/api-provider.js";
3
- import { useToast } from "../../toasts/toast-provider.js";
4
3
  import { recordKey } from "../../live/model-helpers.js";
4
+ import { useToast } from "../../toasts/toast-provider.js";
5
5
  import { text } from "./messages.js";
6
6
  import { useRef, useState } from "react";
7
7
  import { encodeKey } from "@protobase/schema/internal";
@@ -1,7 +1,13 @@
1
1
  //#region src/app/list-order.ts
2
+ /**
3
+ * The order a list opens in: the view's sort, else the primary key's when it is sortable. Otherwise none, as the API
4
+ * refuses a sort by a field that is not sortable and orders a list without one by its key anyway.
5
+ */
2
6
  const defaultOrderBy = (model, view) => {
3
7
  const sort = view?.list?.sort?.[0];
4
- return sort ? `${sort[0]} ${sort[1]}` : `${model.primaryKey[0]} asc`;
8
+ if (sort) return `${sort[0]} ${sort[1]}`;
9
+ const key = model.primaryKey[0];
10
+ return model.fields[key]?.sortable ? `${key} asc` : "";
5
11
  };
6
12
  const parseSort = (orderBy) => {
7
13
  const [columnId = "", direction] = orderBy.trim().split(/\s+/);
@@ -1,6 +1,6 @@
1
1
  import { useAdminMeta } from "../meta-gate.js";
2
- import { useToast } from "../../toasts/toast-provider.js";
3
2
  import { useRouter } from "../router.js";
3
+ import { useToast } from "../../toasts/toast-provider.js";
4
4
  import { text } from "./messages.js";
5
5
  import { useModalOpen } from "./use-modal-open.js";
6
6
  import { useEffect, useState } from "react";
@@ -1,6 +1,6 @@
1
1
  import { useAdminMeta } from "../../meta-gate.js";
2
- import { Skeleton } from "../../../primitives/skeleton.js";
3
2
  import { humanize } from "../../../live/naming.js";
3
+ import { Skeleton } from "../../../primitives/skeleton.js";
4
4
  import { useLayoutRecord } from "../record-scope.js";
5
5
  import { propsOf } from "./block-props.js";
6
6
  import { FieldValue } from "../field-value.js";
@@ -2,15 +2,15 @@ import { useClient } from "../../../data/api-provider.js";
2
2
  import { useAdminMeta, usePermissions } from "../../meta-gate.js";
3
3
  import { Button } from "../../../primitives/button.js";
4
4
  import { Dialog } from "../../../primitives/dialog.js";
5
- import { useToast } from "../../../toasts/toast-provider.js";
6
- import { Field } from "../../../record-view/field.js";
7
5
  import { humanize } from "../../../live/naming.js";
8
6
  import { useNavigationGuard } from "../../router.js";
7
+ import { Field } from "../../../record-view/field.js";
9
8
  import { createBody, isChosen } from "../../create/create-values.js";
10
9
  import { ErrorBanner } from "../../error-banner.js";
11
10
  import { text } from "../messages.js";
12
11
  import { FieldEditor } from "../../field-editor.js";
13
12
  import { useLayoutRecord } from "../record-scope.js";
13
+ import { useToast } from "../../../toasts/toast-provider.js";
14
14
  import { can } from "../../permissions.js";
15
15
  import { useFirstRecord, useRefreshResource } from "../use-layout-data.js";
16
16
  import { propsOf } from "./block-props.js";
@@ -1,15 +1,15 @@
1
1
  import { useClient } from "../../../data/api-provider.js";
2
2
  import { useAdminMeta, usePermissions } from "../../meta-gate.js";
3
3
  import { Button } from "../../../primitives/button.js";
4
+ import { humanize } from "../../../live/naming.js";
4
5
  import { Skeleton } from "../../../primitives/skeleton.js";
5
- import { useToast } from "../../../toasts/toast-provider.js";
6
6
  import { Field } from "../../../record-view/field.js";
7
- import { humanize } from "../../../live/naming.js";
8
7
  import { differs } from "../../../live/field-values.js";
9
8
  import { createBody } from "../../create/create-values.js";
10
9
  import { ErrorBanner } from "../../error-banner.js";
11
10
  import { text } from "../messages.js";
12
11
  import { FieldEditor } from "../../field-editor.js";
12
+ import { useToast } from "../../../toasts/toast-provider.js";
13
13
  import { can } from "../../permissions.js";
14
14
  import { scopeOf, useFirstRecord, useRefreshResource } from "../use-layout-data.js";
15
15
  import { propsOf } from "./block-props.js";
@@ -1,6 +1,6 @@
1
- import { ActionRail } from "../../record-view/action-rail.js";
2
1
  import { RouteLink } from "../../primitives/route-link.js";
3
2
  import { AppLink, useAppAddress } from "../use-app-address.js";
3
+ import { ActionRail } from "../../record-view/action-rail.js";
4
4
  import { ActionMenu } from "../../record-view/action-menu.js";
5
5
  import { ActionPrompt, asksFirst, isDanger } from "./action-prompt.js";
6
6
  import { useActionRunner } from "./use-run-action.js";
@@ -1,9 +1,9 @@
1
1
  import { useClient, useResourceClient } from "../../data/api-provider.js";
2
2
  import { useAdminMeta, usePermissions } from "../meta-gate.js";
3
- import { useToast } from "../../toasts/toast-provider.js";
4
3
  import { useAppAddress } from "../use-app-address.js";
5
4
  import { useProjectUi } from "./project-ui.js";
6
5
  import { text } from "./messages.js";
6
+ import { useToast } from "../../toasts/toast-provider.js";
7
7
  import { can } from "../permissions.js";
8
8
  import { actionApplies } from "./action-when.js";
9
9
  import { actionFor, linkTarget, openLink } from "./action-href.js";
@@ -1,6 +1,6 @@
1
1
  import { cn } from "../../lib/cn.js";
2
- import { Input } from "../../primitives/input.js";
3
2
  import { text } from "../messages.js";
3
+ import { Input } from "../../primitives/input.js";
4
4
  import { useEffect, useId, useRef, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/app/picker/picker-combobox.tsx
@@ -1,8 +1,8 @@
1
1
  import { useAdminMeta } from "../meta-gate.js";
2
- import { viewerZone } from "../../format/zone.js";
3
- import { Skeleton } from "../../primitives/skeleton.js";
4
2
  import { Section } from "../../record-view/section.js";
3
+ import { viewerZone } from "../../format/zone.js";
5
4
  import { humanize } from "../../live/naming.js";
5
+ import { Skeleton } from "../../primitives/skeleton.js";
6
6
  import { Segmented } from "../../primitives/segmented.js";
7
7
  import { useAggregates } from "../../data/use-aggregates.js";
8
8
  import { PeriodChart } from "../charts/period-chart.js";