@protobase/schema 0.23.7 → 0.23.8

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.
@@ -19,6 +19,8 @@ export declare const addressWords: {
19
19
  readonly map: "map";
20
20
  /** The month or week a list's calendar display shows: `month,YYYY-MM-DD` or `week,YYYY-MM-DD`. */
21
21
  readonly calendar: "calendar";
22
+ /** The period a list's timeline display shows: `week,YYYY-MM-DD`, `month,YYYY-MM-DD` or `quarter,YYYY-MM-DD`. */
23
+ readonly timeline: "timeline";
22
24
  /** The saved search a list was opened from, by its key. */
23
25
  readonly savedSearch: "saved_search";
24
26
  /** The second path segment that opens a resource's create form instead of a record. */
@@ -19,6 +19,8 @@ const addressWords = {
19
19
  map: "map",
20
20
  /** The month or week a list's calendar display shows: `month,YYYY-MM-DD` or `week,YYYY-MM-DD`. */
21
21
  calendar: "calendar",
22
+ /** The period a list's timeline display shows: `week,YYYY-MM-DD`, `month,YYYY-MM-DD` or `quarter,YYYY-MM-DD`. */
23
+ timeline: "timeline",
22
24
  /** The saved search a list was opened from, by its key. */
23
25
  savedSearch: "saved_search",
24
26
  /** The second path segment that opens a resource's create form instead of a record. */
@@ -50,7 +52,7 @@ const readMap = (text) => {
50
52
  zoom
51
53
  } : void 0;
52
54
  };
53
- const calendarText = (view) => `${view.scale},${view.day}`;
55
+ const periodText = (view) => `${view.scale},${view.day}`;
54
56
  const isDay = (text) => {
55
57
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text);
56
58
  if (!match) return false;
@@ -58,11 +60,11 @@ const isDay = (text) => {
58
60
  const date = new Date(Date.UTC(year, month - 1, day));
59
61
  return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
60
62
  };
61
- const readCalendar = (text) => {
63
+ const readPeriod = (text, scales) => {
62
64
  const parts = text?.split(",");
63
65
  if (parts?.length !== 2) return void 0;
64
66
  const [scale, day] = parts;
65
- return (scale === "month" || scale === "week") && isDay(day) ? {
67
+ return scales.includes(scale) && isDay(day) ? {
66
68
  scale,
67
69
  day
68
70
  } : void 0;
@@ -75,7 +77,8 @@ const listQuery = (address) => {
75
77
  query.set(addressWords[name], value);
76
78
  }
77
79
  if (address.map) query.set(addressWords.map, mapText(address.map));
78
- if (address.calendar) query.set(addressWords.calendar, calendarText(address.calendar));
80
+ if (address.calendar) query.set(addressWords.calendar, periodText(address.calendar));
81
+ if (address.timeline) query.set(addressWords.timeline, periodText(address.timeline));
79
82
  const text = query.toString();
80
83
  return text ? `?${text}` : "";
81
84
  };
@@ -150,7 +153,12 @@ const readAppPath = (pathAndQuery, pages) => {
150
153
  const orderBy = params.get(addressWords.orderBy) || void 0;
151
154
  const layout = filterLayout(params.get(addressWords.filterLayout));
152
155
  const map = readMap(params.get(addressWords.map));
153
- const calendar = readCalendar(params.get(addressWords.calendar));
156
+ const calendar = readPeriod(params.get(addressWords.calendar), ["month", "week"]);
157
+ const timeline = readPeriod(params.get(addressWords.timeline), [
158
+ "week",
159
+ "month",
160
+ "quarter"
161
+ ]);
154
162
  const savedSearch = params.get(addressWords.savedSearch) || void 0;
155
163
  return {
156
164
  kind: "list",
@@ -162,6 +170,7 @@ const readAppPath = (pathAndQuery, pages) => {
162
170
  ...layout && { filterLayout: layout },
163
171
  ...map && { map },
164
172
  ...calendar && { calendar },
173
+ ...timeline && { timeline },
165
174
  ...savedSearch && { savedSearch }
166
175
  };
167
176
  };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Rollup, RollupCount, RollupFn, RollupSource, RollupValue } from "./computed/rollup.js";
2
2
  import { FileOptions, FileProcessor, FileProcessorInput, ImageFormat, ImageVariant, ImageVariantOptions, imageFormats } from "./files/file-options.js";
3
- import { ActionInputKind, ActionInputModel, ActionModel, ActionRun, AppAddress, BadgeShape, BottomBarItemModel, BottomBarModel, CalendarView, CardFavoriteModel, CardPhotosModel, ChartGranularity, ChartModel, ChartRange, CheckedFilter, CommentsSectionModel, CompareOp, CreateModel, CustomSectionModel, DatePreset, DurationLiteral, DurationUnit, EventModel, EventOperation, ExportModel, FieldFormat, FieldModel, FieldPath, FieldType, FieldViewModel, FieldWidgetModel, FileFieldModel, FilterError, FilterErrorCode, FilterExpr, FilterLayout, FilterOf, FilterValue, FilterWidgetModel, FormModel, GalleryModel, GroupChartModel, GroupItemModel, GroupModel, HelpWhen, HistorySectionModel, JsonValue, KeyValue, LayoutItemModel, ListDisplayModel, ListModel, ListQuery, Literal, MapSectionModel, MapView, NamedListModel, NavModel, NavRecentModel, NowValue, OrderByItem, PeriodChartModel, RecordMode, RecordWhen, RelatedColumnModel, RelatedModel, ResourceModel, SaveFeedback, SaveSearchModel, SearchMatch, SearchResultModel, SearchesOfModel, SectionModel, SectionPresentation, ShowWhen, SignInPromptModel, SignInViewModel, SortSpec, Span, StatusTone, TabItemModel, TabModel, UserMenuItemModel, UserMenuModel, ViewModel } from "./model.js";
3
+ import { ActionInputKind, ActionInputModel, ActionModel, ActionRun, AppAddress, BadgeShape, BottomBarItemModel, BottomBarModel, CalendarView, CardFavoriteModel, CardPhotosModel, ChartGranularity, ChartModel, ChartRange, CheckedFilter, CommentsSectionModel, CompareOp, CreateModel, CustomSectionModel, DatePreset, DurationLiteral, DurationUnit, EventModel, EventOperation, ExportModel, FieldFormat, FieldModel, FieldPath, FieldType, FieldViewModel, FieldWidgetModel, FileFieldModel, FilterError, FilterErrorCode, FilterExpr, FilterLayout, FilterOf, FilterValue, FilterWidgetModel, FormModel, GalleryModel, GroupChartModel, GroupItemModel, GroupModel, HelpWhen, HistorySectionModel, JsonValue, KeyValue, LayoutItemModel, ListDisplayModel, ListModel, ListQuery, Literal, MapSectionModel, MapView, NamedListModel, NavModel, NavRecentModel, NowValue, OrderByItem, PeriodChartModel, RecordMode, RecordWhen, RelatedColumnModel, RelatedModel, ResourceModel, SaveFeedback, SaveSearchModel, SearchMatch, SearchResultModel, SearchesOfModel, SectionModel, SectionPresentation, ShowWhen, SignInPromptModel, SignInViewModel, SortSpec, Span, StatusTone, TabItemModel, TabModel, TimelineView, UserMenuItemModel, UserMenuModel, ViewModel } from "./model.js";
4
4
  import { AccessAction, AccessContext, AccessFn, AccessResult, AccessUser, FieldAccess, FieldRule } from "./access/types.js";
5
5
  import { AnyField, Constraint, Field, FieldMeta, FieldTypeDef } from "./field.js";
6
6
  import { RelationField } from "./relation-field.js";
@@ -43,4 +43,4 @@ import { AccessSource, ResolveOptions, ResolvedAccess, RowFilterOperation, acces
43
43
  import { restrictModel } from "./access/restrict.js";
44
44
  import "./access/index.js";
45
45
  import { AssistantAction, AssistantActionRequest, AssistantCardPart, AssistantDiff, AssistantEvent, AssistantMessage, AssistantMessageRequest, AssistantPart, AssistantState, AssistantStep, AssistantStepState, AssistantTablePart, AssistantTextPart, AssistantTone, AssistantWidgetPart } from "./assistant/protocol.js";
46
- export { type Access, type AccessAction, type AccessContext, type AccessFn, type AccessResult, type AccessSource, type AccessUser, type ActionInputKind, type ActionInputModel, type ActionModel, type ActionRun, type AnyField, type AppAddress, type AssistantAction, type AssistantActionRequest, type AssistantCardPart, type AssistantDiff, type AssistantEvent, type AssistantMessage, type AssistantMessageRequest, type AssistantPart, type AssistantState, type AssistantStep, type AssistantStepState, type AssistantTablePart, type AssistantTextPart, type AssistantTone, type AssistantWidgetPart, type BadgeShape, type BottomBarItemModel, type BottomBarModel, type BottomBarNames, type BottomBarSource, type CalendarView, type Capability, type CapabilityAction, type CapabilityLimit, type CapabilityScope, type CardFavoriteModel, type CardPhotosModel, type ChartGranularity, type ChartInput, type ChartModel, type ChartRange, type CheckResult, type CheckedFilter, type CommentsSectionModel, type CompareOp, type ComponentRef, type Constraint, type CreateModel, type CreatedOptions, type CustomSectionModel, type DatePreset, type DeletedOptions, type DurationLiteral, type DurationUnit, type EvaluateOptions, type EventActor, type EventContext, type EventHelpers, type EventMatch, type EventModel, type EventOperation, type EventSpec, type ExportModel, type Field, type FieldAccess, type FieldFormat, type FieldMeta, type FieldModel, type FieldPath, type FieldRefValue, type FieldRefs, type FieldRule, type FieldType, type FieldTypeDef, type FieldView, type FieldViewModel, type FieldViews, type FieldWidgetModel, type FieldsInput, type FileField, type FileFieldModel, type FileOptions, type FileProcessor, type FileProcessorInput, type FilterError, type FilterErrorCode, type FilterExpr, type FilterLayout, type FilterLimits, type FilterOf, type FilterParse, type FilterValue, type FilterWidgetModel, type FormAddress, type FormInput, type FormModel, type GalleryModel, type Grant, type GroupChartInput, type GroupChartModel, type GroupItemModel, type GroupModel, type HeldCapability, type HelpWhen, type HistorySectionModel, type ImageFormat, type ImageVariant, type ImageVariantOptions, type InferRecord, type Issue, type JsonValue, type KeyOf, type KeyRefs, type KeyType, type KeyValue, type LayoutItemModel, type ListColumn, type ListDisplayModel, type ListModel, type ListQuery, type Literal, type MapSectionModel, type MapView, type NamedListModel, type NavModel, type NavRecentModel, type NowValue, type OrderByCheck, type OrderByItem, type OrderByParse, type PeriodChartInput, type PeriodChartModel, type RecordKey, type RecordMode, type RecordOf, type RecordWhen, type Ref, type Refs, type RelatedColumnModel, type RelatedModel, type RelationField, type ResolveOptions, type ResolvedAccess, type ResourceBuilder, type ResourceModel, type RoleEntry, type RoleLimit, type Roles, type RolesOptions, type Rollup, type RollupCount, type RollupFn, type RollupSource, type RollupValue, type RowFilterOperation, type Rule, type SaveFeedback, type SaveSearchModel, type SearchMatch, type SearchRef, type SearchRefs, type SearchResultModel, type SearchesOfModel, type SectionModel, type SectionPresentation, type ShowWhen, type SignInAddress, type SignInPromptModel, type SignInStep, type SignInViewModel, type SortSpec, type Span, type StatusTone, type TabItemModel, type TabModel, type UndeletedOptions, type UpdatedOptions, type UserMenuItemModel, type UserMenuModel, type UserMenuSource, type Validator, type ViewBuilder, type ViewModel, type ViewProps, accessWarnings, addressWords, anonymousRole, appPath, bottomBar, bottomBarErrors, checkFilter, checkOrderBy, checkRecord, createWhere, defineRoles, enumLabel, evaluateFilter, f, fieldRef, fieldsUsedBy, fitsKeyType, formPath, formRoute, imageFormats, isRecordCondition, keyTypes, layout as l, maxBottomBarItems, parseFilter, parseOrderBy, pickView, printFilter, printOrderBy, readAppPath, readFormAddress, readSignInAddress, resolveAccess, resource, restrictModel, rule, signInParams, signInPath, signInRoute, signInSteps, userMenu, view, where };
46
+ export { type Access, type AccessAction, type AccessContext, type AccessFn, type AccessResult, type AccessSource, type AccessUser, type ActionInputKind, type ActionInputModel, type ActionModel, type ActionRun, type AnyField, type AppAddress, type AssistantAction, type AssistantActionRequest, type AssistantCardPart, type AssistantDiff, type AssistantEvent, type AssistantMessage, type AssistantMessageRequest, type AssistantPart, type AssistantState, type AssistantStep, type AssistantStepState, type AssistantTablePart, type AssistantTextPart, type AssistantTone, type AssistantWidgetPart, type BadgeShape, type BottomBarItemModel, type BottomBarModel, type BottomBarNames, type BottomBarSource, type CalendarView, type Capability, type CapabilityAction, type CapabilityLimit, type CapabilityScope, type CardFavoriteModel, type CardPhotosModel, type ChartGranularity, type ChartInput, type ChartModel, type ChartRange, type CheckResult, type CheckedFilter, type CommentsSectionModel, type CompareOp, type ComponentRef, type Constraint, type CreateModel, type CreatedOptions, type CustomSectionModel, type DatePreset, type DeletedOptions, type DurationLiteral, type DurationUnit, type EvaluateOptions, type EventActor, type EventContext, type EventHelpers, type EventMatch, type EventModel, type EventOperation, type EventSpec, type ExportModel, type Field, type FieldAccess, type FieldFormat, type FieldMeta, type FieldModel, type FieldPath, type FieldRefValue, type FieldRefs, type FieldRule, type FieldType, type FieldTypeDef, type FieldView, type FieldViewModel, type FieldViews, type FieldWidgetModel, type FieldsInput, type FileField, type FileFieldModel, type FileOptions, type FileProcessor, type FileProcessorInput, type FilterError, type FilterErrorCode, type FilterExpr, type FilterLayout, type FilterLimits, type FilterOf, type FilterParse, type FilterValue, type FilterWidgetModel, type FormAddress, type FormInput, type FormModel, type GalleryModel, type Grant, type GroupChartInput, type GroupChartModel, type GroupItemModel, type GroupModel, type HeldCapability, type HelpWhen, type HistorySectionModel, type ImageFormat, type ImageVariant, type ImageVariantOptions, type InferRecord, type Issue, type JsonValue, type KeyOf, type KeyRefs, type KeyType, type KeyValue, type LayoutItemModel, type ListColumn, type ListDisplayModel, type ListModel, type ListQuery, type Literal, type MapSectionModel, type MapView, type NamedListModel, type NavModel, type NavRecentModel, type NowValue, type OrderByCheck, type OrderByItem, type OrderByParse, type PeriodChartInput, type PeriodChartModel, type RecordKey, type RecordMode, type RecordOf, type RecordWhen, type Ref, type Refs, type RelatedColumnModel, type RelatedModel, type RelationField, type ResolveOptions, type ResolvedAccess, type ResourceBuilder, type ResourceModel, type RoleEntry, type RoleLimit, type Roles, type RolesOptions, type Rollup, type RollupCount, type RollupFn, type RollupSource, type RollupValue, type RowFilterOperation, type Rule, type SaveFeedback, type SaveSearchModel, type SearchMatch, type SearchRef, type SearchRefs, type SearchResultModel, type SearchesOfModel, type SectionModel, type SectionPresentation, type ShowWhen, type SignInAddress, type SignInPromptModel, type SignInStep, type SignInViewModel, type SortSpec, type Span, type StatusTone, type TabItemModel, type TabModel, type TimelineView, type UndeletedOptions, type UpdatedOptions, type UserMenuItemModel, type UserMenuModel, type UserMenuSource, type Validator, type ViewBuilder, type ViewModel, type ViewProps, accessWarnings, addressWords, anonymousRole, appPath, bottomBar, bottomBarErrors, checkFilter, checkOrderBy, checkRecord, createWhere, defineRoles, enumLabel, evaluateFilter, f, fieldRef, fieldsUsedBy, fitsKeyType, formPath, formRoute, imageFormats, isRecordCondition, keyTypes, layout as l, maxBottomBarItems, parseFilter, parseOrderBy, pickView, printFilter, printOrderBy, readAppPath, readFormAddress, readSignInAddress, resolveAccess, resource, restrictModel, rule, signInParams, signInPath, signInRoute, signInSteps, userMenu, view, where };
@@ -1,7 +1,7 @@
1
1
  import { checkedAccept, checkedProvider, parseSize } from "./files/file-options.js";
2
2
  import { actionInputErrors, shownInputs } from "./action-inputs.js";
3
3
  import { chartFields, isGroupChart } from "./view-chart.js";
4
- import { boardErrors, calendarErrors, cardPhotoLimit, displayFields, tableDisplay } from "./view-displays.js";
4
+ import { boardErrors, cardPhotoLimit, datesErrors, displayFields, tableDisplay } from "./view-displays.js";
5
5
  import { fieldRefsIn, isFieldRef, markFieldRefs, unmarkFieldRefs } from "./field-ref.js";
6
6
  import { bottomBarFor } from "./bottom-bar.js";
7
7
  import { decodeKey, encodeKey } from "./keys.js";
@@ -22,4 +22,4 @@ import { readEventStream } from "./assistant/event-stream.js";
22
22
  import { layoutItems } from "./layout-items.js";
23
23
  import { viewOfList } from "./named-list.js";
24
24
  import { Locale, isLocale, locales, pickLocale } from "./locale.js";
25
- export { type AddressCheck, type FormulaNode, type Locale, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseFormula, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
25
+ export { type AddressCheck, type FormulaNode, type Locale, type PluginHost, type PluginRequirement, type PropShapes, type RefShape, type SearchTerm, actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, datesErrors, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseFormula, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
package/dist/internal.js CHANGED
@@ -11,7 +11,7 @@ import { actionInputErrors, shownInputs } from "./action-inputs.js";
11
11
  import { updateSetErrors, updateValues } from "./update-set.js";
12
12
  import { chartFields, isGroupChart } from "./view-chart.js";
13
13
  import { fieldRefsIn, isFieldRef, markFieldRefs, unmarkFieldRefs } from "./field-ref.js";
14
- import { boardErrors, calendarErrors, cardPhotoLimit, displayFields, tableDisplay } from "./view-displays.js";
14
+ import { boardErrors, cardPhotoLimit, datesErrors, displayFields, tableDisplay } from "./view-displays.js";
15
15
  import { bottomBarFor } from "./bottom-bar.js";
16
16
  import { decodeKey, encodeKey } from "./keys.js";
17
17
  import { webhookResources } from "./webhooks/webhook-resources.js";
@@ -22,4 +22,4 @@ import { addressErrors } from "./address-errors.js";
22
22
  import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
23
23
  import { readEventStream } from "./assistant/event-stream.js";
24
24
  import { isLocale, locales, pickLocale } from "./locale.js";
25
- export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, calendarErrors, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseFormula, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
25
+ export { actionInputErrors, addressErrors, addressPlaceholders, appHrefError, applyAssistantEvent, boardErrors, bottomBarFor, cardPhotoLimit, chartFields, checkEventFilter, checkedAccept, checkedProvider, datesErrors, decodeKey, defaultRecentLimit, displayFields, emptyAssistantState, encodeKey, fieldRefsIn, fillAddress, hrefField, hrefPlaceholders, inRange, isFieldRef, isGroupChart, isLocale, layoutItems, leavesApp, linkActionError, locales, markFieldRefs, matchedSearchField, matchesSearch, navRecentErrors, parseFormula, parseSize, pickLocale, pluginProblem, promptError, promptFields, pruneByShape, readEventStream, redactSecrets, renderPrompt, searchTerms, shapes, shownInputs, statusTones, tableDisplay, termMatches, unmarkFieldRefs, updateSetErrors, updateValues, viewOfList, webhookResources };
package/dist/model.d.ts CHANGED
@@ -192,11 +192,18 @@ export type CalendarView = {
192
192
  /** A day in the month or week, as `YYYY-MM-DD`. */
193
193
  day: string;
194
194
  };
195
+ /** Which week, month or quarter a list's timeline display shows: its `scale`, and a day (`YYYY-MM-DD`) in it. */
196
+ export type TimelineView = {
197
+ /** A week from Monday, a month, or a quarter from January, April, July or October. */
198
+ scale: 'week' | 'month' | 'quarter';
199
+ /** A day in the week, month or quarter, as `YYYY-MM-DD`. */
200
+ day: string;
201
+ };
195
202
  /**
196
203
  * A place in the app: a resource's list, one of its records, its create form, or a composed page. A record's `key` is
197
204
  * its one value or its parts, as the record API takes them; `readAppPath` gives it back as the API's text form. A create
198
205
  * form's `values` fill in fields of the new record by name, as text (`{ listing_id: '42' }`). A list's `map` is where its
199
- * map display looks, and its `calendar` the month or week its calendar display shows. See [Addresses](website/src/content/docs/reference/layouts.md#addresses).
206
+ * map display looks, its `calendar` the month or week its calendar display shows, and its `timeline` the period its timeline display shows. See [Addresses](website/src/content/docs/reference/layouts.md#addresses).
200
207
  */
201
208
  export type AppAddress = {
202
209
  /** A resource's list. */
@@ -217,6 +224,8 @@ export type AppAddress = {
217
224
  map?: MapView;
218
225
  /** The month or week its calendar display shows. */
219
226
  calendar?: CalendarView;
227
+ /** The week, month or quarter its timeline display shows. */
228
+ timeline?: TimelineView;
220
229
  /**
221
230
  * The saved search the list was opened from, by its key in the text form the record API takes: while the list's
222
231
  * filter differs from the search's, the list offers to update the search.
@@ -419,6 +428,23 @@ export type ListDisplayModel = {
419
428
  end?: string;
420
429
  /** The event's text; the view's title when omitted. */
421
430
  title?: string;
431
+ } | {
432
+ /** The records as bars from their start day to their end day over a week, month or quarter, in lanes by a field, moved by dragging. */
433
+ kind: 'timeline';
434
+ /** What the address names (`?display=timeline`). */
435
+ name: string;
436
+ /** The display's name in the switch. */
437
+ label?: string;
438
+ /** The display's icon in the switch. */
439
+ icon?: string;
440
+ /** The filterable date or timestamp field a record starts on. */
441
+ start: string;
442
+ /** The filterable field of `start`'s type a record ends on; a record's bar is its start day alone when omitted. */
443
+ end?: string;
444
+ /** The field whose values are the lanes; one lane when omitted. */
445
+ group?: string;
446
+ /** The bar's text; the view's title when omitted. */
447
+ title?: string;
422
448
  } | {
423
449
  /** The rows drawn by a project component. */
424
450
  kind: 'custom';
@@ -107,6 +107,22 @@ export declare const displays: {
107
107
  end?: Ref;
108
108
  title?: Ref;
109
109
  }, o?: Naming) => ListDisplayModel;
110
+ /**
111
+ * The records as bars from the day of `start` to the day of `end` (or their start day alone), one row each, over a
112
+ * week, a month or a quarter, in lanes by the values of `group`, with weeks from Monday. It loads only the days shown
113
+ * through the list API, with the list's filter and search, in start order, as a calendar does. A bar shows `title`
114
+ * (default: the view's title) and opens the record. Dragging a bar along its row, or picking it up with Space and
115
+ * moving it with the arrow keys, saves the record with `start` and `end` moved by the same days, as one update with
116
+ * its ETag, so the resource's access rules and `validate` decide, and a refusal puts the bar back and says why.
117
+ * `start` must be a filterable date or timestamp field and `end` a filterable field of the same type. Named
118
+ * `timeline` unless `name` says otherwise. See [Timelines](website/src/content/docs/reference/ui-config.mdx#timelines).
119
+ */
120
+ timeline: (fields: {
121
+ start: Ref;
122
+ end?: Ref;
123
+ group?: Ref;
124
+ title?: Ref;
125
+ }, o?: Naming) => ListDisplayModel;
110
126
  /**
111
127
  * The list drawn by a component of the project, registered in `protobase.ui.tsx` under its name. It gets `props` and
112
128
  * reads the rows with `useListDisplay()`; `fields` are the fields it shows, fetched with relation names.
@@ -122,10 +138,10 @@ export declare const displays: {
122
138
  export declare const boardErrors: (display: Extract<ListDisplayModel, {
123
139
  kind: "board";
124
140
  }>, model: ResourceModel) => string[];
125
- /** What makes a calendar unable to place the records on days: a `start` that is no filterable date or timestamp, or an `end` that is no filterable field of its type. */
126
- export declare const calendarErrors: (display: Extract<ListDisplayModel, {
127
- kind: "calendar";
141
+ /** What makes a calendar or a timeline unable to place the records on days: a `start` that is no filterable date or timestamp, or an `end` that is no filterable field of its type. */
142
+ export declare const datesErrors: (display: Extract<ListDisplayModel, {
143
+ kind: "calendar" | "timeline";
128
144
  }>, model: ResourceModel) => string[];
129
- /** Every field a display names: what it shows, a map's position and the fields saying how exact it is, a board's columns, a calendar's dates, and the field references in a custom display's props. */
145
+ /** Every field a display names: what it shows, a map's position and the fields saying how exact it is, a board's columns, a calendar's dates, a timeline's dates and lanes, and the field references in a custom display's props. */
130
146
  export declare const displayFields: (display: ListDisplayModel) => string[];
131
147
  //#endregion
@@ -110,6 +110,25 @@ const displays = {
110
110
  ...fields.title && { title: fields.title.name }
111
111
  }),
112
112
  /**
113
+ * The records as bars from the day of `start` to the day of `end` (or their start day alone), one row each, over a
114
+ * week, a month or a quarter, in lanes by the values of `group`, with weeks from Monday. It loads only the days shown
115
+ * through the list API, with the list's filter and search, in start order, as a calendar does. A bar shows `title`
116
+ * (default: the view's title) and opens the record. Dragging a bar along its row, or picking it up with Space and
117
+ * moving it with the arrow keys, saves the record with `start` and `end` moved by the same days, as one update with
118
+ * its ETag, so the resource's access rules and `validate` decide, and a refusal puts the bar back and says why.
119
+ * `start` must be a filterable date or timestamp field and `end` a filterable field of the same type. Named
120
+ * `timeline` unless `name` says otherwise. See [Timelines](website/src/content/docs/reference/ui-config.mdx#timelines).
121
+ */
122
+ timeline: (fields, o = {}) => ({
123
+ kind: "timeline",
124
+ name: o.name ?? "timeline",
125
+ ...naming(o),
126
+ start: fields.start.name,
127
+ ...fields.end && { end: fields.end.name },
128
+ ...fields.group && { group: fields.group.name },
129
+ ...fields.title && { title: fields.title.name }
130
+ }),
131
+ /**
113
132
  * The list drawn by a component of the project, registered in `protobase.ui.tsx` under its name. It gets `props` and
114
133
  * reads the rows with `useListDisplay()`; `fields` are the fields it shows, fetched with relation names.
115
134
  */
@@ -149,21 +168,21 @@ const boardErrors = (display, model) => {
149
168
  if (field.type !== "enum") return [`"${display.by}" on ${model.name} is ${field.type}, not an enum, whose values are the board's columns`];
150
169
  return field.filterable ? [] : [`"${display.by}" on ${model.name} is not filterable, and each column of the board filters by its value`];
151
170
  };
152
- /** What makes a calendar unable to place the records on days: a `start` that is no filterable date or timestamp, or an `end` that is no filterable field of its type. */
153
- const calendarErrors = (display, model) => {
171
+ /** What makes a calendar or a timeline unable to place the records on days: a `start` that is no filterable date or timestamp, or an `end` that is no filterable field of its type. */
172
+ const datesErrors = (display, model) => {
154
173
  const known = (name) => Object.hasOwn(model.fields, name) ? model.fields[name] : void 0;
155
174
  const start = known(display.start);
156
175
  const end = display.end === void 0 ? void 0 : known(display.end);
157
176
  if (!start) return [];
158
177
  if (start.type !== "date" && start.type !== "timestamp") return [`start "${display.start}" on ${model.name} is ${start.type}, not a date or timestamp`];
159
- const unfilterable = (name) => `${name === display.start ? "start" : "end"} "${name}" on ${model.name} is not filterable, and the calendar filters by it for the days it shows`;
178
+ const unfilterable = (name) => `${name === display.start ? "start" : "end"} "${name}" on ${model.name} is not filterable, and the ${display.kind} filters by it for the days it shows`;
160
179
  return [
161
180
  ...start.filterable ? [] : [unfilterable(display.start)],
162
181
  ...end && end.type !== start.type ? [`end "${display.end}" on ${model.name} is ${end.type}, not ${start.type} like start "${display.start}"`] : [],
163
182
  ...end && end.type === start.type && !end.filterable ? [unfilterable(display.end)] : []
164
183
  ];
165
184
  };
166
- /** Every field a display names: what it shows, a map's position and the fields saying how exact it is, a board's columns, a calendar's dates, and the field references in a custom display's props. */
185
+ /** Every field a display names: what it shows, a map's position and the fields saying how exact it is, a board's columns, a calendar's dates, a timeline's dates and lanes, and the field references in a custom display's props. */
167
186
  const displayFields = (display) => {
168
187
  if (display.kind === "map") return [
169
188
  display.latitude,
@@ -186,6 +205,12 @@ const displayFields = (display) => {
186
205
  display.end,
187
206
  display.title
188
207
  ].filter((name) => name !== void 0);
208
+ if (display.kind === "timeline") return [
209
+ display.start,
210
+ display.end,
211
+ display.group,
212
+ display.title
213
+ ].filter((name) => name !== void 0);
189
214
  return [
190
215
  display.image,
191
216
  display.title,
@@ -198,4 +223,4 @@ const displayFields = (display) => {
198
223
  ].filter((name) => name !== void 0);
199
224
  };
200
225
  //#endregion
201
- export { boardErrors, calendarErrors, cardPhotoLimit, customComponent, displayErrors, displayFields, displays, tableDisplay };
226
+ export { boardErrors, cardPhotoLimit, customComponent, datesErrors, displayErrors, displayFields, displays, tableDisplay };
package/dist/view.d.ts CHANGED
@@ -69,7 +69,7 @@ export declare class ViewBuilder<R extends {
69
69
  fields(build: (r: FieldViews<R>) => Record<string, FieldView>): ViewBuilder<R>;
70
70
  /**
71
71
  * The list: its table's `columns`, fields or columns of related records (`c.related`), `sort`, `search` and a `filter` it opens with, the
72
- * columns that are `editable` in their cell, and other `displays` to switch to (`d.cards`, `d.map`, `d.board`, `d.calendar`, `d.custom`), one of which
72
+ * columns that are `editable` in their cell, and other `displays` to switch to (`d.cards`, `d.map`, `d.board`, `d.calendar`, `d.timeline`, `d.custom`), one of which
73
73
  * may be the `default` the list opens in. Throws when display or column names collide, `default` names none or an
74
74
  * editable field is not among the columns. See
75
75
  * [Editing in the list](website/src/content/docs/reference/ui-config.mdx#editing-in-the-list).
package/dist/view.js CHANGED
@@ -8,7 +8,7 @@ import { actions } from "./view-actions.js";
8
8
  import { chartModel } from "./view-chart.js";
9
9
  import { formModel } from "./view-form.js";
10
10
  import { columns, isListColumn } from "./view-columns.js";
11
- import { boardErrors, calendarErrors, displayErrors, displayFields, displays } from "./view-displays.js";
11
+ import { boardErrors, datesErrors, displayErrors, displayFields, displays } from "./view-displays.js";
12
12
  import { FieldView } from "./view-field.js";
13
13
  import { widgets } from "./view-widgets.js";
14
14
  //#region src/view.ts
@@ -88,7 +88,7 @@ var ViewBuilder = class ViewBuilder {
88
88
  }
89
89
  /**
90
90
  * The list: its table's `columns`, fields or columns of related records (`c.related`), `sort`, `search` and a `filter` it opens with, the
91
- * columns that are `editable` in their cell, and other `displays` to switch to (`d.cards`, `d.map`, `d.board`, `d.calendar`, `d.custom`), one of which
91
+ * columns that are `editable` in their cell, and other `displays` to switch to (`d.cards`, `d.map`, `d.board`, `d.calendar`, `d.timeline`, `d.custom`), one of which
92
92
  * may be the `default` the list opens in. Throws when display or column names collide, `default` names none or an
93
93
  * editable field is not among the columns. See
94
94
  * [Editing in the list](website/src/content/docs/reference/ui-config.mdx#editing-in-the-list).
@@ -296,8 +296,8 @@ var ViewBuilder = class ViewBuilder {
296
296
  if (flag !== void 0) throw new Error(`View "${this.state.resource}": display "${display.name}" shows "${flag}" as a flag, which is not a boolean field`);
297
297
  const board = display.kind === "board" ? boardErrors(display, resource) : [];
298
298
  if (board.length > 0) throw new Error(`View "${this.state.resource}": display "${display.name}": ${board.join("; ")}`);
299
- const calendar = display.kind === "calendar" ? calendarErrors(display, resource) : [];
300
- if (calendar.length > 0) throw new Error(`View "${this.state.resource}": display "${display.name}": ${calendar.join("; ")}`);
299
+ const dates = display.kind === "calendar" || display.kind === "timeline" ? datesErrors(display, resource) : [];
300
+ if (dates.length > 0) throw new Error(`View "${this.state.resource}": display "${display.name}": ${dates.join("; ")}`);
301
301
  }
302
302
  const clash = resource ? list?.relatedColumns?.find((column) => Object.hasOwn(resource.fields, column.name)) : void 0;
303
303
  if (clash) throw new Error(`View "${this.state.resource}": related column "${clash.name}" has the name of a field of the resource`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/schema",
3
- "version": "0.23.7",
3
+ "version": "0.23.8",
4
4
  "description": "Resource, field, view and access definitions for Protobase configs.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {