react-semaphor 0.1.549 → 0.1.550
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/brand-studio/index.js +1 -1
- package/dist/chunks/{assistant-chat-CUSvuESS.js → assistant-chat-ClAvjeNe.js} +104 -104
- package/dist/chunks/{dashboard-Cm7WkARH.js → dashboard-DDQgKoss.js} +1 -1
- package/dist/chunks/{dashboard-briefing-launcher-X0HzNpS8.js → dashboard-briefing-launcher-CCYs8E4j.js} +1440 -1328
- package/dist/chunks/{dashboard-controls-BuX6TMNK.js → dashboard-controls-DfSkQBsk.js} +976 -929
- package/dist/chunks/{dashboard-json-Cc4u2xvy.js → dashboard-json-BPhyn9pl.js} +2 -2
- package/dist/chunks/{edit-dashboard-visual-DX2CzibK.js → edit-dashboard-visual-G7EmLuR0.js} +355 -355
- package/dist/chunks/{filter-reach-copy-Bc-Gei83.js → filter-reach-copy-8vnDYToV.js} +94 -92
- package/dist/chunks/{report-preferences-dialog-B9oYQ6OJ.js → report-preferences-dialog-D_fEDaS4.js} +849 -768
- package/dist/chunks/{semaphor-ready-indicator-wWkPH4ue.js → semaphor-ready-indicator-Bz5BxITW.js} +25706 -25429
- package/dist/chunks/{shelf-drop-preview-context-B86d8IZO.js → shelf-drop-preview-context-B8kNwpWQ.js} +2 -2
- package/dist/chunks/{switch-CEBOR4n7.js → switch-wJP6O7ZT.js} +2 -2
- package/dist/chunks/{use-create-flow-overlay-state-DPNjYyi3.js → use-create-flow-overlay-state-RzJa7G8S.js} +2 -2
- package/dist/dashboard/index.js +1 -1
- package/dist/dashboard-authoring/index.js +2 -2
- package/dist/index.js +184 -169
- package/dist/style.css +1 -1
- package/dist/surfboard/index.js +1 -1
- package/dist/types/components/assistant/assistant-entry-points.d.ts +4 -1
- package/dist/types/components/dashboard/favorites/dashboard-favorite-toggle.d.ts +11 -0
- package/dist/types/components/dashboard/favorites/favorite-star-button.d.ts +16 -0
- package/dist/types/components/index.d.ts +8 -0
- package/dist/types/components/sharing-and-management/hooks/use-resource-management.d.ts +16 -0
- package/dist/types/components/surfboard/toolbar/toolbar-context.d.ts +86 -0
- package/dist/types/components/surfboard/toolbar/toolbar-overflow.d.ts +14 -0
- package/dist/types/lib/dashboard-viewer/viewer-store-state.d.ts +7 -0
- package/dist/types/lib/hooks/use-dashboard-favorite.d.ts +24 -0
- package/dist/types/lib/hooks/use-dashboard-query.d.ts +2 -0
- package/dist/types/lib/hooks/use-default-dashboard-toggle.d.ts +12 -0
- package/dist/types/shared/dashboard-viewer/viewer-contract.d.ts +18 -0
- package/package.json +1 -1
package/dist/surfboard/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a, R as s, D as o } from "../chunks/report-preferences-dialog-
|
|
1
|
+
import { a, R as s, D as o } from "../chunks/report-preferences-dialog-D_fEDaS4.js";
|
|
2
2
|
import { C as f, E as D } from "../chunks/table-settings-WysCBj62.js";
|
|
3
3
|
export {
|
|
4
4
|
f as CONTROL_CARD_DEFAULT_VALUE,
|
|
@@ -3,7 +3,10 @@ import { AssistantLayout } from '../../shared/assistant-protocol/conversation.js
|
|
|
3
3
|
export type AssistantPanelSurface = 'dashboard' | 'none';
|
|
4
4
|
/** Where the panel shows now: the viewer's layout, or beside the asked-about card (Phase 10, D10-1). */
|
|
5
5
|
export type AssistantPlacement = AssistantLayout | 'beside-card';
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Opens and closes the panel. Named after the assistant; no other wording.
|
|
8
|
+
* Below a wide toolbar it keeps its place as an icon (responsive toolbars).
|
|
9
|
+
*/
|
|
7
10
|
export declare function AssistantToolbarButton(): import("react").JSX.Element | null;
|
|
8
11
|
/**
|
|
9
12
|
* The panel. Beside a dashboard (`surface="dashboard"`), the chat mounts on
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The open dashboard's favorite star for a toolbar (dashboard favorites,
|
|
3
|
+
* FAV-D14, FAV-D17). Access and the server's `isFavorite` come from the
|
|
4
|
+
* dashboard's viewer state; this viewer's own writes win over it (the
|
|
5
|
+
* favorites store, ledger R-05). Nothing for a session that saves nothing (no
|
|
6
|
+
* person in the token, or a PDF render), a read-only star while signed in as
|
|
7
|
+
* someone else. Mounted in this package's toolbar and in the app's own toolbar.
|
|
8
|
+
*/
|
|
9
|
+
export declare function DashboardFavoriteToggle({ dashboardId }: {
|
|
10
|
+
dashboardId: string;
|
|
11
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Shown on a read-only star: the session is signed in as someone else (FAV-D3). */
|
|
2
|
+
export declare const FAVORITES_READ_ONLY_MESSAGE = "Favorites can't be changed while you're signed in as someone else.";
|
|
3
|
+
/**
|
|
4
|
+
* The one favorite star (dashboard favorites, FAV-D13): monochrome, an outline
|
|
5
|
+
* in muted ink when off, filled with foreground ink when on. On rows it shows
|
|
6
|
+
* on hover or keyboard focus and stays visible once on.
|
|
7
|
+
*/
|
|
8
|
+
export declare function FavoriteStarButton({ isFavorite, onToggle, readOnly, pending, variant, className, }: {
|
|
9
|
+
isFavorite: boolean;
|
|
10
|
+
onToggle: () => void;
|
|
11
|
+
readOnly?: boolean;
|
|
12
|
+
pending?: boolean;
|
|
13
|
+
/** `row`: hub and list rows, revealed on hover. `toolbar`: always shown. */
|
|
14
|
+
variant?: 'row' | 'toolbar';
|
|
15
|
+
className?: string;
|
|
16
|
+
}): import("react").JSX.Element;
|
|
@@ -37,6 +37,14 @@ export { AssistantProvider } from './assistant/assistant-provider.js';
|
|
|
37
37
|
export { AssistantPanel, AssistantToolbarButton } from './assistant/assistant-entry-points.js';
|
|
38
38
|
export { ArrangeLayoutButton } from './surfboard/arrange-layout-button.js';
|
|
39
39
|
export { ScreenSizePreviewButton } from './surfboard/screen-size-preview-button.js';
|
|
40
|
+
export { DashboardFavoriteToggle } from './dashboard/favorites/dashboard-favorite-toggle.js';
|
|
41
|
+
export { FavoriteStarButton, FAVORITES_READ_ONLY_MESSAGE, } from './dashboard/favorites/favorite-star-button.js';
|
|
42
|
+
export { ToolbarOverflowAnchorSlot, ToolbarProvider } from './surfboard/toolbar/toolbar-overflow.js';
|
|
43
|
+
export { TOOLBAR_LG_MIN, TOOLBAR_MD_MIN, fitsToolbar, toolbarWidthFor, useMeasuredToolbarWidth, useToolbarItem, useToolbarOverflowItems, useToolbarWidth, } from './surfboard/toolbar/toolbar-context.js';
|
|
44
|
+
export type { ToolbarOverflowItem, ToolbarTier, ToolbarWidth, } from './surfboard/toolbar/toolbar-context.js';
|
|
45
|
+
export { useDefaultDashboardToggle } from '../lib/hooks/use-default-dashboard-toggle.js';
|
|
46
|
+
export { useDashboardFavorite } from '../lib/hooks/use-dashboard-favorite.js';
|
|
47
|
+
export type { DashboardFavorites } from '../lib/hooks/use-dashboard-favorite.js';
|
|
40
48
|
export type { AssistantPanelSurface } from './assistant/assistant-entry-points.js';
|
|
41
49
|
export { useAssistant } from './assistant/use-assistant.js';
|
|
42
50
|
export * from '../lib/types/common-types.js';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ResourceType, ShareRole, ShareScope } from '../utils/types.js';
|
|
2
2
|
import { TDashboard, TFrame } from '../../../lib/types/index.js';
|
|
3
3
|
import { AppearanceSpec } from '../../../lib/appearance/index.js';
|
|
4
|
+
import { DashboardListViewer } from '../../../shared/dashboard-viewer/index.js';
|
|
4
5
|
export interface ResourceListItem {
|
|
5
6
|
id: string;
|
|
6
7
|
title: string;
|
|
@@ -38,6 +39,9 @@ export interface ResourceListItem {
|
|
|
38
39
|
email: string;
|
|
39
40
|
};
|
|
40
41
|
};
|
|
42
|
+
/** Dashboard lists only (dashboard favorites, FAV-D5); absent from older servers, read as false. */
|
|
43
|
+
isFavorite?: boolean;
|
|
44
|
+
favoritedAt?: string | null;
|
|
41
45
|
}
|
|
42
46
|
export interface CreateResourceRequest {
|
|
43
47
|
title: string;
|
|
@@ -115,6 +119,10 @@ export declare function useResourceUpdateState(): {
|
|
|
115
119
|
export declare function useResourceManagement(resourceType: ResourceType, onDeleteSuccess?: () => void, onCreateSuccess?: (data?: any) => void): {
|
|
116
120
|
resources: any;
|
|
117
121
|
organizationAppearance: AppearanceSpec | null;
|
|
122
|
+
/** When the list arrived (client clock, ms); favorites resolve against it (FAV-D20). */
|
|
123
|
+
listFetchedAt: number;
|
|
124
|
+
/** Dashboard lists: whether this session can change favorites (FAV-D18). */
|
|
125
|
+
listViewer: DashboardListViewer | null;
|
|
118
126
|
isLoading: boolean;
|
|
119
127
|
isError: boolean;
|
|
120
128
|
isFetching: boolean;
|
|
@@ -152,6 +160,10 @@ export declare function useResourceManagement(resourceType: ResourceType, onDele
|
|
|
152
160
|
export declare function useDashboardManagement(onDeleteSuccess?: () => void, onCreateSuccess?: (data?: any) => void): {
|
|
153
161
|
resources: any;
|
|
154
162
|
organizationAppearance: AppearanceSpec | null;
|
|
163
|
+
/** When the list arrived (client clock, ms); favorites resolve against it (FAV-D20). */
|
|
164
|
+
listFetchedAt: number;
|
|
165
|
+
/** Dashboard lists: whether this session can change favorites (FAV-D18). */
|
|
166
|
+
listViewer: DashboardListViewer | null;
|
|
155
167
|
isLoading: boolean;
|
|
156
168
|
isError: boolean;
|
|
157
169
|
isFetching: boolean;
|
|
@@ -189,6 +201,10 @@ export declare function useDashboardManagement(onDeleteSuccess?: () => void, onC
|
|
|
189
201
|
export declare function useVisualManagement(onDeleteSuccess?: () => void, onCreateSuccess?: (data?: any) => void): {
|
|
190
202
|
resources: any;
|
|
191
203
|
organizationAppearance: AppearanceSpec | null;
|
|
204
|
+
/** When the list arrived (client clock, ms); favorites resolve against it (FAV-D20). */
|
|
205
|
+
listFetchedAt: number;
|
|
206
|
+
/** Dashboard lists: whether this session can change favorites (FAV-D18). */
|
|
207
|
+
listViewer: DashboardListViewer | null;
|
|
192
208
|
isLoading: boolean;
|
|
193
209
|
isError: boolean;
|
|
194
210
|
isFetching: boolean;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Responsive dashboard toolbars (design: semaphor-app `/design/responsive-toolbars`).
|
|
4
|
+
*
|
|
5
|
+
* Both toolbars, this package's and the app's navbar, follow one rule set. A
|
|
6
|
+
* toolbar measures its own width (an embed lives in a host column of any
|
|
7
|
+
* size, so the viewport says nothing). Every item has a tier: `always`, `md`
|
|
8
|
+
* (shown from 640px of toolbar) or `lg` (from 960px). As the toolbar narrows,
|
|
9
|
+
* labels collapse to icons first, then an item below its tier stops rendering
|
|
10
|
+
* its button and registers its menu form here, which the toolbar's existing
|
|
11
|
+
* ⋯ menu renders in toolbar order. A `menu` item lives in ⋯ at every width.
|
|
12
|
+
* Editing controls cannot move, so their group scrolls when it still does not
|
|
13
|
+
* fit, and ⋯ stays in view.
|
|
14
|
+
*
|
|
15
|
+
* Outside a toolbar (for example the Activity bell on the Briefings page) the
|
|
16
|
+
* context reads as `lg` with no menu, so every control renders as before.
|
|
17
|
+
*/
|
|
18
|
+
export type ToolbarWidth = 'sm' | 'md' | 'lg';
|
|
19
|
+
export type ToolbarTier = 'always' | 'md' | 'lg' | 'menu';
|
|
20
|
+
/** Toolbar widths (px) where the `md` and `lg` tiers start. */
|
|
21
|
+
export declare const TOOLBAR_MD_MIN = 640;
|
|
22
|
+
export declare const TOOLBAR_LG_MIN = 960;
|
|
23
|
+
export declare function toolbarWidthFor(px: number): ToolbarWidth;
|
|
24
|
+
/** Whether an item of `tier` shows its button at `width`. */
|
|
25
|
+
export declare function fitsToolbar(tier: ToolbarTier, width: ToolbarWidth): boolean;
|
|
26
|
+
/** The menu form an item registers while its button does not fit. */
|
|
27
|
+
export type ToolbarOverflowItem = {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly label: string;
|
|
30
|
+
readonly icon?: ReactNode;
|
|
31
|
+
/** A short right-aligned note: a count, a current value. */
|
|
32
|
+
readonly hint?: string;
|
|
33
|
+
/** Shown as a check, for a toggle. */
|
|
34
|
+
readonly checked?: boolean;
|
|
35
|
+
/** Toolbar order, so the menu lists moved items as the toolbar did. */
|
|
36
|
+
readonly order: number;
|
|
37
|
+
readonly onSelect: () => void;
|
|
38
|
+
};
|
|
39
|
+
export type ToolbarContextValue = {
|
|
40
|
+
readonly width: ToolbarWidth;
|
|
41
|
+
/** Inside a toolbar that has a ⋯ menu for moved items. */
|
|
42
|
+
readonly hasOverflowMenu: boolean;
|
|
43
|
+
readonly overflowItems: readonly ToolbarOverflowItem[];
|
|
44
|
+
register(item: ToolbarOverflowItem): () => void;
|
|
45
|
+
/** Which moved control's popover is open from the menu. */
|
|
46
|
+
readonly openOverflowId: string | null;
|
|
47
|
+
setOpenOverflowId(id: string | null): void;
|
|
48
|
+
/** Beside the ⋯ button: where a moved control anchors its popover. */
|
|
49
|
+
readonly anchorSlot: HTMLElement | null;
|
|
50
|
+
setAnchorSlot(element: HTMLElement | null): void;
|
|
51
|
+
};
|
|
52
|
+
export declare const ToolbarContext: import('react').Context<ToolbarContextValue>;
|
|
53
|
+
/**
|
|
54
|
+
* Measures an element's width: pass `measure` as the element's `ref`. Starts
|
|
55
|
+
* at `lg` so a wide first paint never jumps.
|
|
56
|
+
*/
|
|
57
|
+
export declare function useMeasuredToolbarWidth<T extends HTMLElement>(): {
|
|
58
|
+
measure: (element: T | null) => void;
|
|
59
|
+
width: ToolbarWidth;
|
|
60
|
+
};
|
|
61
|
+
/** The toolbar's width (`lg` outside a toolbar). */
|
|
62
|
+
export declare function useToolbarWidth(): ToolbarWidth;
|
|
63
|
+
/** The moved items, for a toolbar's ⋯ menu. */
|
|
64
|
+
export declare function useToolbarOverflowItems(): readonly ToolbarOverflowItem[];
|
|
65
|
+
/**
|
|
66
|
+
* One toolbar item. `collapsed` means it should not render its button. While
|
|
67
|
+
* collapsed and `menu` is given, its menu form is registered. Popover controls
|
|
68
|
+
* use `popoverOpen` and `setPopoverOpen`: from the menu they open anchored at
|
|
69
|
+
* the ⋯ menu, which is where the item now lives.
|
|
70
|
+
*/
|
|
71
|
+
export declare function useToolbarItem(id: string, tier: ToolbarTier, menu?: Omit<ToolbarOverflowItem, 'id' | 'onSelect'> & {
|
|
72
|
+
/** Defaults to opening the item's popover from the menu. */
|
|
73
|
+
readonly onSelect?: () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Runs when the menu opens the item's popover. Radix calls `onOpenChange`
|
|
76
|
+
* only for its own trigger, not when the `open` prop changes, so work a
|
|
77
|
+
* control does on open (Activity marks finished work seen) goes here too.
|
|
78
|
+
*/
|
|
79
|
+
readonly onOpen?: () => void;
|
|
80
|
+
}): {
|
|
81
|
+
collapsed: boolean;
|
|
82
|
+
popoverOpen: boolean;
|
|
83
|
+
setPopoverOpen(open: boolean): void;
|
|
84
|
+
/** Where to portal a collapsed popover's anchor (`null` outside a toolbar). */
|
|
85
|
+
anchorSlot: HTMLElement | null;
|
|
86
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ToolbarWidth } from './toolbar-context.js';
|
|
3
|
+
/** Wraps one toolbar: its width, and the moved items its ⋯ menu renders. */
|
|
4
|
+
export declare function ToolbarProvider({ width, hasOverflowMenu, children, }: {
|
|
5
|
+
width: ToolbarWidth;
|
|
6
|
+
/** False while the toolbar shows no ⋯ menu: then nothing moves into one. */
|
|
7
|
+
hasOverflowMenu?: boolean;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
}): import("react").JSX.Element;
|
|
10
|
+
/**
|
|
11
|
+
* Place right before the toolbar's ⋯ button: a moved control's popover
|
|
12
|
+
* anchors here, so it opens under the menu it was chosen from.
|
|
13
|
+
*/
|
|
14
|
+
export declare function ToolbarOverflowAnchorSlot(): import("react").JSX.Element;
|
|
@@ -18,6 +18,13 @@ export type DashboardViewerState = {
|
|
|
18
18
|
/** Live table settings per card. Never written into `card.config` or `tablePrefs`. */
|
|
19
19
|
readonly tableSettings: Readonly<Record<string, ViewerTableSettings>>;
|
|
20
20
|
readonly notices: readonly ViewerNotice[];
|
|
21
|
+
/**
|
|
22
|
+
* The server's answer from the dashboard's viewer payload (FAV-D17). Read
|
|
23
|
+
* through the favorites store, where this viewer's later writes win.
|
|
24
|
+
*/
|
|
25
|
+
readonly isFavorite: boolean;
|
|
26
|
+
/** When the dashboard response this state came from arrived (client clock, ms; 0 when unknown). */
|
|
27
|
+
readonly fetchedAt: number;
|
|
21
28
|
};
|
|
22
29
|
/** Session-only until the dashboard load says otherwise (TECH-SPEC 7). */
|
|
23
30
|
export declare const INITIAL_DASHBOARD_VIEWER_STATE: DashboardViewerState;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type SetDashboardFavoriteInput = {
|
|
2
|
+
readonly dashboardId: string;
|
|
3
|
+
readonly isFavorite: boolean;
|
|
4
|
+
};
|
|
5
|
+
export type DashboardFavorites = {
|
|
6
|
+
/**
|
|
7
|
+
* What to show: this viewer's write while in flight or newer than the
|
|
8
|
+
* server data, else the server's value. `serverFetchedAt` is when that data
|
|
9
|
+
* arrived (client clock, ms).
|
|
10
|
+
*/
|
|
11
|
+
isFavorite(dashboardId: string, serverIsFavorite: boolean, serverFetchedAt?: number): boolean;
|
|
12
|
+
/** A write for this dashboard is waiting for the server. */
|
|
13
|
+
isPending(dashboardId: string): boolean;
|
|
14
|
+
/** Resolves true when the server saved it; false after it was put back. */
|
|
15
|
+
setFavorite(input: SetDashboardFavoriteInput): Promise<boolean>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Dashboard favorites for the viewer the token names (FAV-D15). Reads and
|
|
19
|
+
* writes go through one viewer-scoped store (`dashboard-favorites-store.ts`);
|
|
20
|
+
* server responses are read as they are and never edited, so a cached list or
|
|
21
|
+
* dashboard response cannot disagree with a write made since (ledger R-01,
|
|
22
|
+
* R-02, R-05).
|
|
23
|
+
*/
|
|
24
|
+
export declare function useDashboardFavorite(): DashboardFavorites;
|
|
@@ -6,6 +6,8 @@ export declare function useDashboardQuery(): {
|
|
|
6
6
|
organizationAppearance?: import('../types/index.js').AppearanceSpec | null;
|
|
7
7
|
viewer?: import('../types/index.js').DashboardViewerPayload;
|
|
8
8
|
} | null | undefined;
|
|
9
|
+
/** When `data` arrived (client clock, ms); dashboard favorites read it (FAV-D20). */
|
|
10
|
+
dataUpdatedAt: number;
|
|
9
11
|
isLoading: boolean;
|
|
10
12
|
isFetching: boolean;
|
|
11
13
|
isError: boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The viewer's default dashboard, as one ⋯ menu item in both dashboard
|
|
3
|
+
* toolbars (responsive toolbars: the DEFAULT chip and house button left the
|
|
4
|
+
* toolbar). The hub list keeps its Default chip.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useDefaultDashboardToggle(dashboardId: string | null | undefined): {
|
|
7
|
+
available: boolean;
|
|
8
|
+
isDefault: boolean;
|
|
9
|
+
/** True until the preference has loaded, and while a change is saving. */
|
|
10
|
+
disabled: boolean;
|
|
11
|
+
toggle(): void;
|
|
12
|
+
};
|
|
@@ -63,6 +63,24 @@ export type DashboardViewerPayload = {
|
|
|
63
63
|
readonly teamScope?: 'tenant' | 'organization';
|
|
64
64
|
readonly canPublish: boolean;
|
|
65
65
|
};
|
|
66
|
+
/**
|
|
67
|
+
* Whether the person has favorited this dashboard (dashboard favorites,
|
|
68
|
+
* FAV-D17). Read with the rest of the preference row; `false` for
|
|
69
|
+
* session-only access.
|
|
70
|
+
*/
|
|
71
|
+
readonly isFavorite: boolean;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* The dashboard list's top-level `viewer` (`GET /api/management/v1/dashboards`,
|
|
75
|
+
* FAV-D18): whether the person the token names can change favorites.
|
|
76
|
+
*/
|
|
77
|
+
export type DashboardListViewer = Pick<DashboardViewerPayload, 'access' | 'accessReason'>;
|
|
78
|
+
/** `PUT` and `DELETE /api/management/v1/dashboards/{id}/favorite` (FAV-D4). */
|
|
79
|
+
export type DashboardFavoriteState = {
|
|
80
|
+
readonly dashboardId: string;
|
|
81
|
+
readonly isFavorite: boolean;
|
|
82
|
+
/** ISO 8601; `null` when not a favorite. */
|
|
83
|
+
readonly favoritedAt: string | null;
|
|
66
84
|
};
|
|
67
85
|
/**
|
|
68
86
|
* How many saved bookmarks and remembered table settings reference each part
|