@adminide-stack/yantra-mobile 12.0.141-alpha.1 → 12.0.142-alpha.0
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/lib/features/agent-chat/NativeAgentChat.js +21 -4
- package/lib/features/agent-chat/NativeAgentChat.js.map +1 -1
- package/lib/features/chat/ApprovalCard.js +353 -0
- package/lib/features/chat/ApprovalCard.js.map +1 -0
- package/lib/features/chat/AskUserCard.js +9 -2
- package/lib/features/chat/AskUserCard.js.map +1 -1
- package/lib/features/chat/askUser.js +25 -3
- package/lib/features/chat/askUser.js.map +1 -1
- package/lib/features/chat/queuedFollowUpRows.js +13 -0
- package/lib/features/chat/queuedFollowUpRows.js.map +1 -0
- package/lib/features/dictate/DictateExperience.js +59 -7
- package/lib/features/dictate/DictateExperience.js.map +1 -1
- package/lib/features/dictate/components/NoteView.js +227 -12
- package/lib/features/dictate/components/NoteView.js.map +1 -1
- package/lib/features/dictate/dictateClient.js +93 -23
- package/lib/features/dictate/dictateClient.js.map +1 -1
- package/lib/features/dictate/dictatePreference.js +19 -0
- package/lib/features/dictate/dictatePreference.js.map +1 -0
- package/lib/features/dictate/noteText.js +17 -2
- package/lib/features/dictate/noteText.js.map +1 -1
- package/lib/features/dictate/privacy.js +96 -0
- package/lib/features/dictate/privacy.js.map +1 -0
- package/lib/features/dictate/shownNote.js +24 -0
- package/lib/features/dictate/shownNote.js.map +1 -0
- package/lib/features/discover/DiscoverArticle.js +105 -92
- package/lib/features/discover/DiscoverArticle.js.map +1 -1
- package/lib/features/discover/DiscoverFeed.js +97 -48
- package/lib/features/discover/DiscoverFeed.js.map +1 -1
- package/lib/features/discover/DiscoverFollowUp.js +135 -0
- package/lib/features/discover/DiscoverFollowUp.js.map +1 -0
- package/lib/features/discover/DiscoverSidebar.js +555 -0
- package/lib/features/discover/DiscoverSidebar.js.map +1 -0
- package/lib/features/discover/DiscoverSkeletons.js +123 -0
- package/lib/features/discover/DiscoverSkeletons.js.map +1 -0
- package/lib/features/discover/DiscoverStoryCards.js +193 -87
- package/lib/features/discover/DiscoverStoryCards.js.map +1 -1
- package/lib/features/discover/followUpQuery.js +42 -0
- package/lib/features/discover/followUpQuery.js.map +1 -0
- package/lib/features/discover/markets.js +37 -0
- package/lib/features/discover/markets.js.map +1 -0
- package/lib/features/discover/useDiscoverSidebar.js +148 -0
- package/lib/features/discover/useDiscoverSidebar.js.map +1 -0
- package/lib/features/discover/weather.js +42 -0
- package/lib/features/discover/weather.js.map +1 -0
- package/lib/features/expenses/ExpensesAgentChatPane.js +1 -1
- package/lib/features/expenses/ExpensesAgentChatPane.js.map +1 -1
- package/lib/features/inbox/InboxAgentChatPane.js +1 -1
- package/lib/features/inbox/InboxAgentChatPane.js.map +1 -1
- package/lib/features/job-search/JobSearchAgentChatPane.js +1 -0
- package/lib/features/job-search/JobSearchAgentChatPane.js.map +1 -1
- package/lib/features/local-services/LocalServicesAgentChatPane.js +1 -1
- package/lib/features/local-services/LocalServicesAgentChatPane.js.map +1 -1
- package/lib/features/movies/MoviesAgentChatPane.js +1 -1
- package/lib/features/movies/MoviesAgentChatPane.js.map +1 -1
- package/lib/features/notion/NotionBlockSheets.js +206 -0
- package/lib/features/notion/NotionBlockSheets.js.map +1 -0
- package/lib/features/notion/NotionBlockView.js +36 -0
- package/lib/features/notion/NotionBlockView.js.map +1 -0
- package/lib/features/notion/NotionCommentsSheet.js +461 -0
- package/lib/features/notion/NotionCommentsSheet.js.map +1 -0
- package/lib/features/notion/NotionConnectionsSheet.js +244 -0
- package/lib/features/notion/NotionConnectionsSheet.js.map +1 -0
- package/lib/features/notion/NotionHistorySheet.js +439 -0
- package/lib/features/notion/NotionHistorySheet.js.map +1 -0
- package/lib/features/notion/NotionMediaBlocks.js +803 -0
- package/lib/features/notion/NotionMediaBlocks.js.map +1 -0
- package/lib/features/notion/NotionMentionSheet.js +279 -0
- package/lib/features/notion/NotionMentionSheet.js.map +1 -0
- package/lib/features/notion/NotionPageMenu.js +585 -0
- package/lib/features/notion/NotionPageMenu.js.map +1 -0
- package/lib/features/notion/NotionPageTree.js +220 -0
- package/lib/features/notion/NotionPageTree.js.map +1 -0
- package/lib/features/notion/NotionPageView.js +1253 -152
- package/lib/features/notion/NotionPageView.js.map +1 -1
- package/lib/features/notion/NotionShareSheet.js +606 -0
- package/lib/features/notion/NotionShareSheet.js.map +1 -0
- package/lib/features/notion/NotionSheets.js +87 -15
- package/lib/features/notion/NotionSheets.js.map +1 -1
- package/lib/features/notion/NotionSidebarSections.js +492 -0
- package/lib/features/notion/NotionSidebarSections.js.map +1 -0
- package/lib/features/notion/NotionWorkspaceAdmin.js +659 -0
- package/lib/features/notion/NotionWorkspaceAdmin.js.map +1 -0
- package/lib/features/notion/NotionWorkspaceView.js +257 -45
- package/lib/features/notion/NotionWorkspaceView.js.map +1 -1
- package/lib/features/notion/database/DatabaseCells.js +554 -0
- package/lib/features/notion/database/DatabaseCells.js.map +1 -0
- package/lib/features/notion/database/DatabaseDateLayouts.js +792 -0
- package/lib/features/notion/database/DatabaseDateLayouts.js.map +1 -0
- package/lib/features/notion/database/DatabaseLayouts.js +461 -0
- package/lib/features/notion/database/DatabaseLayouts.js.map +1 -0
- package/lib/features/notion/database/DatabaseSheets.js +791 -0
- package/lib/features/notion/database/DatabaseSheets.js.map +1 -0
- package/lib/features/notion/database/NotionDatabaseView.js +817 -0
- package/lib/features/notion/database/NotionDatabaseView.js.map +1 -0
- package/lib/features/notion/database/RowPropertiesPanel.js +162 -0
- package/lib/features/notion/database/RowPropertiesPanel.js.map +1 -0
- package/lib/features/notion/database/chartData.js +89 -0
- package/lib/features/notion/database/chartData.js.map +1 -0
- package/lib/features/notion/database/chartView.js +112 -0
- package/lib/features/notion/database/chartView.js.map +1 -0
- package/lib/features/notion/database/connectorButton.js +33 -0
- package/lib/features/notion/database/connectorButton.js.map +1 -0
- package/lib/features/notion/database/databaseCalc.js +208 -0
- package/lib/features/notion/database/databaseCalc.js.map +1 -0
- package/lib/features/notion/database/databaseCalendar.js +157 -0
- package/lib/features/notion/database/databaseCalendar.js.map +1 -0
- package/lib/features/notion/database/databaseCsv.js +98 -0
- package/lib/features/notion/database/databaseCsv.js.map +1 -0
- package/lib/features/notion/database/databaseCsvActions.js +58 -0
- package/lib/features/notion/database/databaseCsvActions.js.map +1 -0
- package/lib/features/notion/database/databaseFilter.js +473 -0
- package/lib/features/notion/database/databaseFilter.js.map +1 -0
- package/lib/features/notion/database/databaseFormula.js +1072 -0
- package/lib/features/notion/database/databaseFormula.js.map +1 -0
- package/lib/features/notion/database/databaseGroup.js +151 -0
- package/lib/features/notion/database/databaseGroup.js.map +1 -0
- package/lib/features/notion/database/databaseRollup.js +58 -0
- package/lib/features/notion/database/databaseRollup.js.map +1 -0
- package/lib/features/notion/database/databaseTimeline.js +156 -0
- package/lib/features/notion/database/databaseTimeline.js.map +1 -0
- package/lib/features/notion/database/databaseView.js +1188 -0
- package/lib/features/notion/database/databaseView.js.map +1 -0
- package/lib/features/notion/database/databaseViews.js +310 -0
- package/lib/features/notion/database/databaseViews.js.map +1 -0
- package/lib/features/notion/database/relationSource.js +92 -0
- package/lib/features/notion/database/relationSource.js.map +1 -0
- package/lib/features/notion/database/uniqueId.js +17 -0
- package/lib/features/notion/database/uniqueId.js.map +1 -0
- package/lib/features/notion/database/useNotionDatabase.js +617 -0
- package/lib/features/notion/database/useNotionDatabase.js.map +1 -0
- package/lib/features/notion/notionAgentRunStatus.js +39 -0
- package/lib/features/notion/notionAgentRunStatus.js.map +1 -0
- package/lib/features/notion/notionCodeLanguages.js +112 -0
- package/lib/features/notion/notionCodeLanguages.js.map +1 -0
- package/lib/features/notion/notionComments.js +86 -0
- package/lib/features/notion/notionComments.js.map +1 -0
- package/lib/features/notion/notionConnections.js +74 -0
- package/lib/features/notion/notionConnections.js.map +1 -0
- package/lib/features/notion/notionDocuments.js +453 -1
- package/lib/features/notion/notionDocuments.js.map +1 -1
- package/lib/features/notion/notionEditorModel.js +142 -7
- package/lib/features/notion/notionEditorModel.js.map +1 -1
- package/lib/features/notion/notionMarkdownShortcuts.js +51 -0
- package/lib/features/notion/notionMarkdownShortcuts.js.map +1 -0
- package/lib/features/notion/notionMedia.js +119 -0
- package/lib/features/notion/notionMedia.js.map +1 -0
- package/lib/features/notion/notionMentionDate.js +32 -0
- package/lib/features/notion/notionMentionDate.js.map +1 -0
- package/lib/features/notion/notionMentionOptions.js +162 -0
- package/lib/features/notion/notionMentionOptions.js.map +1 -0
- package/lib/features/notion/notionNotesAgent.js +445 -0
- package/lib/features/notion/notionNotesAgent.js.map +1 -0
- package/lib/features/notion/notionPageAccess.js +168 -0
- package/lib/features/notion/notionPageAccess.js.map +1 -0
- package/lib/features/notion/notionPageActions.js +138 -0
- package/lib/features/notion/notionPageActions.js.map +1 -0
- package/lib/features/notion/notionPageHistory.js +154 -0
- package/lib/features/notion/notionPageHistory.js.map +1 -0
- package/lib/features/notion/notionPageKinds.js +200 -0
- package/lib/features/notion/notionPageKinds.js.map +1 -0
- package/lib/features/notion/notionRecents.js +48 -0
- package/lib/features/notion/notionRecents.js.map +1 -0
- package/lib/features/notion/notionRichText.js +177 -0
- package/lib/features/notion/notionRichText.js.map +1 -0
- package/lib/features/notion/notionRichTitle.js +336 -0
- package/lib/features/notion/notionRichTitle.js.map +1 -0
- package/lib/features/notion/useNotionWorkspace.js +272 -13
- package/lib/features/notion/useNotionWorkspace.js.map +1 -1
- package/lib/features/notion/usePageActions.js +155 -0
- package/lib/features/notion/usePageActions.js.map +1 -0
- package/lib/features/resume/ResumeAgentChatPane.js +1 -1
- package/lib/features/resume/ResumeAgentChatPane.js.map +1 -1
- package/lib/features/shopping/ShoppingAgentChatPane.js +1 -1
- package/lib/features/shopping/ShoppingAgentChatPane.js.map +1 -1
- package/lib/features/study/StudyAgentChatPane.js +1 -1
- package/lib/features/study/StudyAgentChatPane.js.map +1 -1
- package/lib/features/travel/TravelAgentChatPane.js +1 -1
- package/lib/features/travel/TravelAgentChatPane.js.map +1 -1
- package/lib/features/webbuilder/WebBuilderExperience.js +40 -8
- package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
- package/lib/features/webbuilder/buildFragments.js +1 -1
- package/lib/features/webbuilder/buildFragments.js.map +1 -1
- package/lib/features/webbuilder/codeFiles.js +302 -0
- package/lib/features/webbuilder/codeFiles.js.map +1 -0
- package/lib/features/webbuilder/codeHighlight.js +209 -0
- package/lib/features/webbuilder/codeHighlight.js.map +1 -0
- package/lib/features/webbuilder/components/CodeView.js +682 -52
- package/lib/features/webbuilder/components/CodeView.js.map +1 -1
- package/lib/features/webbuilder/components/PreviewScreen.js +59 -38
- package/lib/features/webbuilder/components/PreviewScreen.js.map +1 -1
- package/lib/features/webbuilder/components/ProjectChat.js +3 -3
- package/lib/features/webbuilder/components/ProjectChat.js.map +1 -1
- package/lib/features/webbuilder/stepLabels.js +68 -0
- package/lib/features/webbuilder/stepLabels.js.map +1 -0
- package/lib/hooks/useHostChatSteering.js +45 -0
- package/lib/hooks/useHostChatSteering.js.map +1 -0
- package/lib/screens/Chat/index.js +2 -12
- package/lib/screens/Chat/index.js.map +1 -1
- package/lib/screens/ExpensesNative/useExpensesHostChat.js +25 -5
- package/lib/screens/ExpensesNative/useExpensesHostChat.js.map +1 -1
- package/lib/screens/InboxNative/useInboxHostChat.js +25 -5
- package/lib/screens/InboxNative/useInboxHostChat.js.map +1 -1
- package/lib/screens/JobSearchNative/useJobSearchHostChat.js +25 -5
- package/lib/screens/JobSearchNative/useJobSearchHostChat.js.map +1 -1
- package/lib/screens/LocalServicesNative/useLocalServicesHostChat.js +25 -5
- package/lib/screens/LocalServicesNative/useLocalServicesHostChat.js.map +1 -1
- package/lib/screens/MoviesNative/useMoviesHostChat.js +25 -5
- package/lib/screens/MoviesNative/useMoviesHostChat.js.map +1 -1
- package/lib/screens/NotionPage/index.js +2 -2
- package/lib/screens/NotionPage/index.js.map +1 -1
- package/lib/screens/ResumeNative/useResumeHostChat.js +25 -5
- package/lib/screens/ResumeNative/useResumeHostChat.js.map +1 -1
- package/lib/screens/ShoppingNative/useShoppingHostChat.js +25 -5
- package/lib/screens/ShoppingNative/useShoppingHostChat.js.map +1 -1
- package/lib/screens/StudyNative/useStudyHostChat.js +25 -5
- package/lib/screens/StudyNative/useStudyHostChat.js.map +1 -1
- package/lib/screens/TravelNative/useTravelHostChat.js +25 -5
- package/lib/screens/TravelNative/useTravelHostChat.js.map +1 -1
- package/lib/screens/WebBuilderNative/codeWorkspaceApi.js +222 -0
- package/lib/screens/WebBuilderNative/codeWorkspaceApi.js.map +1 -0
- package/lib/screens/WebBuilderNative/index.js +1 -1
- package/lib/screens/WebBuilderNative/index.js.map +1 -1
- package/lib/screens/WebBuilderNative/sandboxProxyApi.js +126 -4
- package/lib/screens/WebBuilderNative/sandboxProxyApi.js.map +1 -1
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js +120 -11
- package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {aggregateRows}from'./chartData.js';var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
const CHART_VIEW_KINDS = [{
|
|
18
|
+
kind: "column",
|
|
19
|
+
label: "Vertical bar"
|
|
20
|
+
}, {
|
|
21
|
+
kind: "bar",
|
|
22
|
+
label: "Horizontal bar"
|
|
23
|
+
}, {
|
|
24
|
+
kind: "donut",
|
|
25
|
+
label: "Donut"
|
|
26
|
+
}];
|
|
27
|
+
const CHART_VIEW_SORTS = [{
|
|
28
|
+
sort: "default",
|
|
29
|
+
label: "Property order"
|
|
30
|
+
}, {
|
|
31
|
+
sort: "value_desc",
|
|
32
|
+
label: "Value: high \u2192 low"
|
|
33
|
+
}, {
|
|
34
|
+
sort: "value_asc",
|
|
35
|
+
label: "Value: low \u2192 high"
|
|
36
|
+
}, {
|
|
37
|
+
sort: "label",
|
|
38
|
+
label: "Alphabetical"
|
|
39
|
+
}];
|
|
40
|
+
const GROUP_TYPES = /* @__PURE__ */ new Set(["select", "status", "multi_select", "person", "checkbox", "created_by", "last_edited_by", "text", "title", "url", "email", "phone", "formula", "rollup"]);
|
|
41
|
+
const NUMERIC_TYPES = /* @__PURE__ */ new Set(["number", "formula", "rollup", "unique_id"]);
|
|
42
|
+
function chartGroupColumns(columns) {
|
|
43
|
+
const ok = columns.filter((c) => GROUP_TYPES.has(c.type));
|
|
44
|
+
const rank = (c) => c.type === "status" || c.type === "select" ? 0 : c.type === "multi_select" ? 1 : 2;
|
|
45
|
+
return ok.slice().sort((a, b) => rank(a) - rank(b));
|
|
46
|
+
}
|
|
47
|
+
function chartValueColumns(columns) {
|
|
48
|
+
return columns.filter((c) => NUMERIC_TYPES.has(c.type));
|
|
49
|
+
}
|
|
50
|
+
function readChartViewSettings(settings, columns) {
|
|
51
|
+
var _a, _b, _c, _d;
|
|
52
|
+
const raw = (_a = settings && typeof settings === "object" ? settings.chart : void 0) != null ? _a : {};
|
|
53
|
+
const groups = chartGroupColumns(columns);
|
|
54
|
+
const values = chartValueColumns(columns);
|
|
55
|
+
const kind = CHART_VIEW_KINDS.some((k) => k.kind === raw.kind) ? raw.kind : "column";
|
|
56
|
+
const groupBy = groups.some((c) => c.name === raw.groupBy) ? raw.groupBy : (_c = (_b = groups[0]) == null ? void 0 : _b.name) != null ? _c : "";
|
|
57
|
+
const valueProperty = values.some((c) => c.name === raw.valueProperty) ? raw.valueProperty : (_d = values[0]) == null ? void 0 : _d.name;
|
|
58
|
+
const aggregate = raw.aggregate === "sum" && valueProperty ? "sum" : "count";
|
|
59
|
+
const sort = CHART_VIEW_SORTS.some((s) => s.sort === raw.sort) ? raw.sort : "default";
|
|
60
|
+
return {
|
|
61
|
+
kind,
|
|
62
|
+
groupBy,
|
|
63
|
+
aggregate,
|
|
64
|
+
valueProperty,
|
|
65
|
+
sort
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function chartViewItems(rows, columns, getValue, s, nameOf) {
|
|
69
|
+
const group = columns.find((c) => c.name === s.groupBy);
|
|
70
|
+
if (!group) return [];
|
|
71
|
+
const value = s.aggregate === "sum" ? columns.find((c) => c.name === s.valueProperty) : void 0;
|
|
72
|
+
const byUser = group.type === "created_by" || group.type === "last_edited_by";
|
|
73
|
+
const groupValue = (r) => {
|
|
74
|
+
const v = getValue(r, group);
|
|
75
|
+
return v;
|
|
76
|
+
};
|
|
77
|
+
const projected = rows.map((r) => ({
|
|
78
|
+
properties: __spreadValues({
|
|
79
|
+
[group.name]: groupValue(r)
|
|
80
|
+
}, value ? {
|
|
81
|
+
[value.name]: getValue(r, value)
|
|
82
|
+
} : {})
|
|
83
|
+
}));
|
|
84
|
+
const groupType = byUser ? "text" : group.type;
|
|
85
|
+
const schema = __spreadValues({
|
|
86
|
+
[group.name]: {
|
|
87
|
+
type: groupType,
|
|
88
|
+
options: group.options
|
|
89
|
+
}
|
|
90
|
+
}, value ? {
|
|
91
|
+
[value.name]: {
|
|
92
|
+
type: "number"
|
|
93
|
+
}
|
|
94
|
+
} : {});
|
|
95
|
+
const items = aggregateRows(projected, schema, {
|
|
96
|
+
groupByProperty: group.name,
|
|
97
|
+
aggregate: value ? "sum" : "count",
|
|
98
|
+
valueProperty: value == null ? void 0 : value.name
|
|
99
|
+
});
|
|
100
|
+
switch (s.sort) {
|
|
101
|
+
case "value_desc":
|
|
102
|
+
return items.slice().sort((a, b) => b.value - a.value);
|
|
103
|
+
case "value_asc":
|
|
104
|
+
return items.slice().sort((a, b) => a.value - b.value);
|
|
105
|
+
case "label":
|
|
106
|
+
return items.slice().sort((a, b) => a.label.localeCompare(b.label, void 0, {
|
|
107
|
+
numeric: true
|
|
108
|
+
}));
|
|
109
|
+
default:
|
|
110
|
+
return items;
|
|
111
|
+
}
|
|
112
|
+
}export{CHART_VIEW_KINDS,CHART_VIEW_SORTS,chartGroupColumns,chartValueColumns,chartViewItems,readChartViewSettings};//# sourceMappingURL=chartView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chartView.js","sources":["../../../../src/features/notion/database/chartView.ts"],"sourcesContent":["/**\n * Chart database view (Notion's \"Chart\" layout): one bar / column / slice per group of rows.\n *\n * Settings live on the view as `settings.chart`:\n * { kind: 'bar' | 'column' | 'donut', groupBy: <property>, aggregate: 'count' | 'sum', valueProperty?, sort? }\n *\n * readChartViewSettings(settings, columns) → settings with defaults filled from the columns\n * chartGroupColumns(columns) → properties a chart can group by\n * chartViewItems(rows, columns, getValue, s) → [{label, value, color}] (computed values included)\n */\nimport { aggregateRows, type ChartItem, type ChartSchemaProp } from './chartData';\nimport type { CellGetter, RowLike, ColumnLike } from './databaseView';\n\nexport type ChartViewKind = 'bar' | 'column' | 'donut';\nexport type ChartViewSort = 'default' | 'value_desc' | 'value_asc' | 'label';\n\nexport interface ChartViewSettings {\n kind: ChartViewKind;\n groupBy: string;\n aggregate: 'count' | 'sum';\n valueProperty?: string;\n sort: ChartViewSort;\n}\n\nexport const CHART_VIEW_KINDS: Array<{ kind: ChartViewKind; label: string }> = [\n { kind: 'column', label: 'Vertical bar' },\n { kind: 'bar', label: 'Horizontal bar' },\n { kind: 'donut', label: 'Donut' },\n];\n\nexport const CHART_VIEW_SORTS: Array<{ sort: ChartViewSort; label: string }> = [\n { sort: 'default', label: 'Property order' },\n { sort: 'value_desc', label: 'Value: high → low' },\n { sort: 'value_asc', label: 'Value: low → high' },\n { sort: 'label', label: 'Alphabetical' },\n];\n\ntype Col = ColumnLike & { options?: Array<{ name: string; color?: string }> };\n\nconst GROUP_TYPES = new Set([\n 'select',\n 'status',\n 'multi_select',\n 'person',\n 'checkbox',\n 'created_by',\n 'last_edited_by',\n 'text',\n 'title',\n 'url',\n 'email',\n 'phone',\n 'formula',\n 'rollup',\n]);\nconst NUMERIC_TYPES = new Set(['number', 'formula', 'rollup', 'unique_id']);\n\n/** Preferred first: select / status, then the rest in schema order. */\nexport function chartGroupColumns<C extends Col>(columns: C[]): C[] {\n const ok = columns.filter((c) => GROUP_TYPES.has(c.type));\n const rank = (c: C) => (c.type === 'status' || c.type === 'select' ? 0 : c.type === 'multi_select' ? 1 : 2);\n return ok.slice().sort((a, b) => rank(a) - rank(b));\n}\n\nexport function chartValueColumns<C extends Col>(columns: C[]): C[] {\n return columns.filter((c) => NUMERIC_TYPES.has(c.type));\n}\n\nexport function readChartViewSettings(settings: unknown, columns: Col[]): ChartViewSettings {\n const raw = (settings && typeof settings === 'object' ? (settings as any).chart : undefined) ?? {};\n const groups = chartGroupColumns(columns);\n const values = chartValueColumns(columns);\n const kind: ChartViewKind = CHART_VIEW_KINDS.some((k) => k.kind === raw.kind) ? raw.kind : 'column';\n const groupBy = groups.some((c) => c.name === raw.groupBy) ? raw.groupBy : (groups[0]?.name ?? '');\n const valueProperty = values.some((c) => c.name === raw.valueProperty) ? raw.valueProperty : values[0]?.name;\n const aggregate = raw.aggregate === 'sum' && valueProperty ? 'sum' : 'count';\n const sort: ChartViewSort = CHART_VIEW_SORTS.some((s) => s.sort === raw.sort) ? raw.sort : 'default';\n return { kind, groupBy, aggregate, valueProperty, sort };\n}\n\n/**\n * Rows → one item per group. Values go through `getValue` so formulas, rollups and\n * created-by work like in the table.\n */\nexport function chartViewItems(\n rows: RowLike[],\n columns: Col[],\n getValue: CellGetter,\n s: ChartViewSettings,\n nameOf?: (userId: string) => string,\n): ChartItem[] {\n const group = columns.find((c) => c.name === s.groupBy);\n if (!group) return [];\n const value = s.aggregate === 'sum' ? columns.find((c) => c.name === s.valueProperty) : undefined;\n const byUser = group.type === 'created_by' || group.type === 'last_edited_by';\n const groupValue = (r: RowLike) => {\n const v = getValue(r, group);\n return byUser && typeof v === 'string' && nameOf ? nameOf(v) : v;\n };\n const projected = rows.map((r) => ({\n properties: {\n [group.name]: groupValue(r),\n ...(value ? { [value.name]: getValue(r, value) } : {}),\n },\n }));\n // created_by / formula etc. group like text; person-like \"by\" values are plain names.\n const groupType = byUser ? 'text' : group.type;\n const schema: Record<string, ChartSchemaProp> = {\n [group.name]: { type: groupType, options: group.options },\n ...(value ? { [value.name]: { type: 'number' } } : {}),\n };\n const items = aggregateRows(projected, schema, {\n groupByProperty: group.name,\n aggregate: value ? 'sum' : 'count',\n valueProperty: value?.name,\n });\n switch (s.sort) {\n case 'value_desc':\n return items.slice().sort((a, b) => b.value - a.value);\n case 'value_asc':\n return items.slice().sort((a, b) => a.value - b.value);\n case 'label':\n return items.slice().sort((a, b) => a.label.localeCompare(b.label, undefined, { numeric: true }));\n default:\n return items;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __spreadValues = (a, b) => {
|
|
7
|
+
for (var prop in b || (b = {}))
|
|
8
|
+
if (__hasOwnProp.call(b, prop))
|
|
9
|
+
__defNormalProp(a, prop, b[prop]);
|
|
10
|
+
if (__getOwnPropSymbols)
|
|
11
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
12
|
+
if (__propIsEnum.call(b, prop))
|
|
13
|
+
__defNormalProp(a, prop, b[prop]);
|
|
14
|
+
}
|
|
15
|
+
return a;
|
|
16
|
+
};
|
|
17
|
+
const isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
|
|
18
|
+
function readButtonCell(raw) {
|
|
19
|
+
if (!isObj(raw) || typeof raw.at !== "string") return null;
|
|
20
|
+
return __spreadValues(__spreadValues({
|
|
21
|
+
at: raw.at,
|
|
22
|
+
ok: raw.ok === true
|
|
23
|
+
}, typeof raw.summary === "string" ? {
|
|
24
|
+
summary: raw.summary
|
|
25
|
+
} : {}), typeof raw.error === "string" ? {
|
|
26
|
+
error: raw.error
|
|
27
|
+
} : {});
|
|
28
|
+
}
|
|
29
|
+
function buttonCellText(raw) {
|
|
30
|
+
const run = readButtonCell(raw);
|
|
31
|
+
if (!run) return "";
|
|
32
|
+
return run.ok ? run.summary || "Done" : "Failed";
|
|
33
|
+
}export{buttonCellText,readButtonCell};//# sourceMappingURL=connectorButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectorButton.js","sources":["../../../../src/features/notion/database/connectorButton.ts"],"sourcesContent":["/**\n * Button block (`type:'embed'`, `properties.embedType:'button'`): a labelled button on a page\n * that runs one connector action — \"Sync PRs\", \"Post standup to Slack\", \"Create an issue\".\n * It runs in the signed-in project with the vault credential (ConnectorRunScopeProvider), asks\n * before an action that changes data (unless the button says not to), and keeps its last run.\n *\n * buttonLabel / buttonIcon\n * buttonAction { connector, action, actionTitle?, params, inputSchema? }\n * buttonConfirm 'auto' (ask before changes — default) | 'never'\n * buttonLastRun { at, ok, summary?, error?, itemCount? }\n */\n/** The outcome of one connector run (web: connectorProperty.ts). */\nexport interface ConnectorRunOutcome {\n /** The action result `data` (successful runs). */\n data?: unknown;\n ok: boolean;\n error?: string;\n needsCredentials?: boolean;\n}\n\nexport const BUTTON_EMBED_TYPE = 'button';\n\nexport interface ConnectorButtonAction {\n connector: string;\n action: string;\n actionTitle?: string;\n params: Record<string, unknown>;\n inputSchema?: unknown;\n}\n\nexport type ConnectorButtonConfirm = 'auto' | 'never';\n\nexport interface ConnectorButtonLastRun {\n at: string;\n ok: boolean;\n summary?: string;\n error?: string;\n}\n\nexport interface ConnectorButtonBlock {\n label: string;\n icon?: string;\n action?: ConnectorButtonAction;\n confirm: ConnectorButtonConfirm;\n lastRun?: ConnectorButtonLastRun;\n}\n\nconst isObj = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v);\n\nexport function readButtonBlock(props: Record<string, unknown> | undefined): ConnectorButtonBlock {\n const p = props ?? {};\n const a = isObj(p.buttonAction) ? p.buttonAction : null;\n const action =\n a && typeof a.connector === 'string' && a.connector && typeof a.action === 'string' && a.action\n ? {\n connector: a.connector,\n action: a.action,\n ...(typeof a.actionTitle === 'string' && a.actionTitle ? { actionTitle: a.actionTitle } : {}),\n params: isObj(a.params) ? a.params : {},\n ...(isObj(a.inputSchema) ? { inputSchema: a.inputSchema } : {}),\n }\n : undefined;\n const lr = isObj(p.buttonLastRun) ? p.buttonLastRun : null;\n return {\n label: typeof p.buttonLabel === 'string' && p.buttonLabel.trim() ? p.buttonLabel.trim() : '',\n ...(typeof p.buttonIcon === 'string' && p.buttonIcon ? { icon: p.buttonIcon } : {}),\n ...(action ? { action } : {}),\n confirm: p.buttonConfirm === 'never' ? 'never' : 'auto',\n ...(lr && typeof lr.at === 'string'\n ? {\n lastRun: {\n at: lr.at,\n ok: lr.ok === true,\n ...(typeof lr.summary === 'string' ? { summary: lr.summary } : {}),\n ...(typeof lr.error === 'string' ? { error: lr.error } : {}),\n },\n }\n : {}),\n };\n}\n\n/** The label shown when none was given: the action's title. */\nexport function buttonDisplayLabel(b: ConnectorButtonBlock): string {\n return b.label || b.action?.actionTitle || 'New button';\n}\n\nfunction firstString(o: Record<string, unknown>, keys: string[]): string | undefined {\n for (const k of keys) {\n const v = o[k];\n if (typeof v === 'string' && v.trim()) return v.trim();\n if (typeof v === 'number') return `#${v}`;\n }\n return undefined;\n}\n\n/** A short line for the toast / status: \"6 items\", \"#425 Offline banner\", \"Done\". */\nexport function summarizeRunData(data: unknown): string {\n const inner =\n isObj(data) && 'data' in data && Object.keys(data).length <= 3 ? (data as { data: unknown }).data : data;\n if (Array.isArray(inner)) return `${inner.length} item${inner.length === 1 ? '' : 's'}`;\n if (isObj(inner)) {\n const id = firstString(inner, ['number', 'key', 'id']);\n const title = firstString(inner, ['title', 'name', 'subject', 'summary', 'text']);\n const parts = [id && id.startsWith('#') ? id : undefined, title].filter(Boolean);\n if (parts.length) return parts.join(' ').slice(0, 80);\n }\n return 'Done';\n}\n\nexport function lastRunFromOutcome(outcome: ConnectorRunOutcome, at = new Date()): ConnectorButtonLastRun {\n return outcome.ok\n ? { at: at.toISOString(), ok: true, summary: summarizeRunData(outcome.data) }\n : {\n at: at.toISOString(),\n ok: false,\n error: outcome.error || (outcome.needsCredentials ? 'Credentials required' : 'The run failed'),\n };\n}\n\n// ============================================================================\n// BUTTON PROPERTY (a database column of per-row buttons)\n// ============================================================================\n\n/**\n * A `type:'button'` database property: each row gets a button that runs the action with params\n * resolved from that row (`{{prop:PR URL}}`). The row's cell keeps the last run\n * (`{ at, ok, summary?, error? }`). Stored flat on the schema property like a connector property:\n * `connector`, `action`, `actionTitle`, `params`, `buttonLabel`, `buttonConfirm`.\n */\nexport interface ButtonColumnDef {\n connector: string;\n action: string;\n actionTitle?: string;\n params: Record<string, unknown>;\n label: string;\n confirm: ConnectorButtonConfirm;\n /** Row properties written after a successful run (e.g. Status → Done), so the row matches at once. */\n set?: Record<string, unknown>;\n}\n\n/** `{{me.id}}` in a button param: the account of whoever clicks (a shared column can't store one). */\nexport const ME_ID_TOKEN = '{{me.id}}';\n\n/** Replace `{{me.id}}` in string params; null when the token is used but nobody is signed in. */\nexport function withMeToken(\n params: Record<string, unknown>,\n meId: string | null | undefined,\n): Record<string, unknown> | null {\n let missing = false;\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(params)) {\n if (typeof v === 'string' && v.includes(ME_ID_TOKEN)) {\n if (!meId) missing = true;\n out[k] = v.split(ME_ID_TOKEN).join(meId ?? '');\n } else out[k] = v;\n }\n return missing ? null : out;\n}\n\nexport function readButtonColumnDef(raw: unknown): ButtonColumnDef | null {\n if (!isObj(raw)) return null;\n const src = isObj(raw.button) ? raw.button : raw;\n const connector = typeof src.connector === 'string' ? src.connector.trim() : '';\n const action = typeof src.action === 'string' ? src.action.trim() : '';\n if (!connector || !action) return null;\n return {\n connector,\n action,\n ...(typeof src.actionTitle === 'string' && src.actionTitle ? { actionTitle: src.actionTitle } : {}),\n params: isObj(src.params) ? src.params : {},\n label:\n (typeof src.buttonLabel === 'string' && src.buttonLabel.trim()) ||\n (typeof src.label === 'string' && src.label.trim()) ||\n '',\n confirm: src.buttonConfirm === 'never' || src.confirm === 'never' ? 'never' : 'auto',\n ...(isObj(src.buttonSet) ? { set: src.buttonSet } : {}),\n };\n}\n\nexport function readButtonCell(raw: unknown): ConnectorButtonLastRun | null {\n if (!isObj(raw) || typeof raw.at !== 'string') return null;\n return {\n at: raw.at,\n ok: raw.ok === true,\n ...(typeof raw.summary === 'string' ? { summary: raw.summary } : {}),\n ...(typeof raw.error === 'string' ? { error: raw.error } : {}),\n };\n}\n\n/** Text of a button cell for lists / sorting / exports: \"Done · #425\", \"Failed\", \"\". */\nexport function buttonCellText(raw: unknown): string {\n const run = readButtonCell(raw);\n if (!run) return '';\n return run.ok ? run.summary || 'Done' : 'Failed';\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAyCA,MAAM,KAAQ,GAAA,CAAC,CAA6C,KAAA,CAAC,CAAC,CAAA,IAAK,OAAO,CAAA,KAAM,QAAY,IAAA,CAAC,KAAM,CAAA,OAAA,CAAQ,CAAC,CAAA;AAuIrG,SAAS,eAAe,GAA6C,EAAA;AAC1E,EAAI,IAAA,CAAC,MAAM,GAAG,CAAA,IAAK,OAAO,GAAI,CAAA,EAAA,KAAO,UAAiB,OAAA,IAAA;AACtD,EAAO,OAAA,cAAA,CAAA,cAAA,CAAA;AAAA,IACL,IAAI,GAAI,CAAA,EAAA;AAAA,IACR,EAAA,EAAI,IAAI,EAAO,KAAA;AAAA,GACX,EAAA,OAAO,GAAI,CAAA,OAAA,KAAY,QAAW,GAAA;AAAA,IACpC,SAAS,GAAI,CAAA;AAAA,MACX,EAAC,CAAA,EACD,OAAO,GAAA,CAAI,UAAU,QAAW,GAAA;AAAA,IAClC,OAAO,GAAI,CAAA;AAAA,MACT,EAAC,CAAA;AAET;AAGO,SAAS,eAAe,GAAsB,EAAA;AACnD,EAAM,MAAA,GAAA,GAAM,eAAe,GAAG,CAAA;AAC9B,EAAI,IAAA,CAAC,KAAY,OAAA,EAAA;AACjB,EAAA,OAAO,GAAI,CAAA,EAAA,GAAK,GAAI,CAAA,OAAA,IAAW,MAAS,GAAA,QAAA;AAC1C"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import {isEmptyCell,numberValue,dateRangeValue,cellDisplayText,relationIds,personEntries,multiSelectNames}from'./databaseView.js';const CALC_LABELS = {
|
|
2
|
+
none: {
|
|
3
|
+
menu: "None",
|
|
4
|
+
short: ""
|
|
5
|
+
},
|
|
6
|
+
count_all: {
|
|
7
|
+
menu: "Count all",
|
|
8
|
+
short: "Count"
|
|
9
|
+
},
|
|
10
|
+
count_values: {
|
|
11
|
+
menu: "Count values",
|
|
12
|
+
short: "Values"
|
|
13
|
+
},
|
|
14
|
+
count_unique: {
|
|
15
|
+
menu: "Count unique values",
|
|
16
|
+
short: "Unique"
|
|
17
|
+
},
|
|
18
|
+
count_empty: {
|
|
19
|
+
menu: "Count empty",
|
|
20
|
+
short: "Empty"
|
|
21
|
+
},
|
|
22
|
+
count_not_empty: {
|
|
23
|
+
menu: "Count not empty",
|
|
24
|
+
short: "Not empty"
|
|
25
|
+
},
|
|
26
|
+
percent_empty: {
|
|
27
|
+
menu: "Percent empty",
|
|
28
|
+
short: "Empty"
|
|
29
|
+
},
|
|
30
|
+
percent_not_empty: {
|
|
31
|
+
menu: "Percent not empty",
|
|
32
|
+
short: "Not empty"
|
|
33
|
+
},
|
|
34
|
+
sum: {
|
|
35
|
+
menu: "Sum",
|
|
36
|
+
short: "Sum"
|
|
37
|
+
},
|
|
38
|
+
average: {
|
|
39
|
+
menu: "Average",
|
|
40
|
+
short: "Average"
|
|
41
|
+
},
|
|
42
|
+
median: {
|
|
43
|
+
menu: "Median",
|
|
44
|
+
short: "Median"
|
|
45
|
+
},
|
|
46
|
+
min: {
|
|
47
|
+
menu: "Min",
|
|
48
|
+
short: "Min"
|
|
49
|
+
},
|
|
50
|
+
max: {
|
|
51
|
+
menu: "Max",
|
|
52
|
+
short: "Max"
|
|
53
|
+
},
|
|
54
|
+
range: {
|
|
55
|
+
menu: "Range",
|
|
56
|
+
short: "Range"
|
|
57
|
+
},
|
|
58
|
+
checked: {
|
|
59
|
+
menu: "Checked",
|
|
60
|
+
short: "Checked"
|
|
61
|
+
},
|
|
62
|
+
unchecked: {
|
|
63
|
+
menu: "Unchecked",
|
|
64
|
+
short: "Unchecked"
|
|
65
|
+
},
|
|
66
|
+
percent_checked: {
|
|
67
|
+
menu: "Percent checked",
|
|
68
|
+
short: "Checked"
|
|
69
|
+
},
|
|
70
|
+
percent_unchecked: {
|
|
71
|
+
menu: "Percent unchecked",
|
|
72
|
+
short: "Unchecked"
|
|
73
|
+
},
|
|
74
|
+
earliest: {
|
|
75
|
+
menu: "Earliest date",
|
|
76
|
+
short: "Earliest"
|
|
77
|
+
},
|
|
78
|
+
latest: {
|
|
79
|
+
menu: "Latest date",
|
|
80
|
+
short: "Latest"
|
|
81
|
+
},
|
|
82
|
+
date_range: {
|
|
83
|
+
menu: "Date range",
|
|
84
|
+
short: "Range"
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const COUNT_KINDS = ["count_all", "count_values", "count_unique", "count_empty", "count_not_empty", "percent_empty", "percent_not_empty"];
|
|
88
|
+
const NUMBER_KINDS = ["sum", "average", "median", "min", "max", "range"];
|
|
89
|
+
const CHECKBOX_KINDS = ["count_all", "checked", "unchecked", "percent_checked", "percent_unchecked"];
|
|
90
|
+
const DATE_TYPES = /* @__PURE__ */ new Set(["date", "created_time", "last_edited_time"]);
|
|
91
|
+
function kindsFor(type) {
|
|
92
|
+
if (type === "checkbox") return ["none", ...CHECKBOX_KINDS];
|
|
93
|
+
if (type === "number" || type === "formula" || type === "rollup") return ["none", ...COUNT_KINDS, ...NUMBER_KINDS];
|
|
94
|
+
if (DATE_TYPES.has(type)) return ["none", ...COUNT_KINDS, "earliest", "latest", "date_range"];
|
|
95
|
+
if (type === "button") return ["none", "count_all"];
|
|
96
|
+
return ["none", ...COUNT_KINDS];
|
|
97
|
+
}
|
|
98
|
+
function valueTokens(value, type) {
|
|
99
|
+
if (isEmptyCell(value, type)) return [];
|
|
100
|
+
switch (type) {
|
|
101
|
+
case "multi_select":
|
|
102
|
+
return multiSelectNames(value);
|
|
103
|
+
case "person":
|
|
104
|
+
return personEntries(value).map((p) => p.name);
|
|
105
|
+
case "relation":
|
|
106
|
+
return relationIds(value);
|
|
107
|
+
case "files":
|
|
108
|
+
return cellDisplayText(value, type).split(",").map((s) => s.trim()).filter(Boolean);
|
|
109
|
+
default: {
|
|
110
|
+
const text = cellDisplayText(value, type).trim();
|
|
111
|
+
return text ? [text] : [];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function isChecked(value) {
|
|
116
|
+
return value === true || value === "true";
|
|
117
|
+
}
|
|
118
|
+
function dayOf(value) {
|
|
119
|
+
var _a;
|
|
120
|
+
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)) return value.slice(0, 10);
|
|
121
|
+
const range = dateRangeValue(value);
|
|
122
|
+
return (_a = range == null ? void 0 : range.start) != null ? _a : null;
|
|
123
|
+
}
|
|
124
|
+
function formatCalcNumber(n) {
|
|
125
|
+
if (!Number.isFinite(n)) return "\u2014";
|
|
126
|
+
return n.toLocaleString(void 0, {
|
|
127
|
+
maximumFractionDigits: 2
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function pct(part, total) {
|
|
131
|
+
if (!total) return "0%";
|
|
132
|
+
return `${formatCalcNumber(part / total * 100)}%`;
|
|
133
|
+
}
|
|
134
|
+
function shortDate(day) {
|
|
135
|
+
return (/* @__PURE__ */ new Date(`${day}T00:00:00Z`)).toLocaleDateString(void 0, {
|
|
136
|
+
day: "numeric",
|
|
137
|
+
month: "short",
|
|
138
|
+
year: "numeric",
|
|
139
|
+
timeZone: "UTC"
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function computeCalculation(values, type, kind) {
|
|
143
|
+
var _a, _b;
|
|
144
|
+
if (!kind || kind === "none") return null;
|
|
145
|
+
const label = (_b = (_a = CALC_LABELS[kind]) == null ? void 0 : _a.short) != null ? _b : kind;
|
|
146
|
+
const total = values.length;
|
|
147
|
+
const empty = values.filter((v) => isEmptyCell(v, type)).length;
|
|
148
|
+
const filled = total - empty;
|
|
149
|
+
const out = (value) => ({
|
|
150
|
+
label,
|
|
151
|
+
value
|
|
152
|
+
});
|
|
153
|
+
switch (kind) {
|
|
154
|
+
case "count_all":
|
|
155
|
+
return out(formatCalcNumber(total));
|
|
156
|
+
case "count_values":
|
|
157
|
+
return out(formatCalcNumber(values.reduce((n, v) => n + valueTokens(v, type).length, 0)));
|
|
158
|
+
case "count_unique":
|
|
159
|
+
return out(formatCalcNumber(new Set(values.flatMap((v) => valueTokens(v, type))).size));
|
|
160
|
+
case "count_empty":
|
|
161
|
+
return out(formatCalcNumber(empty));
|
|
162
|
+
case "count_not_empty":
|
|
163
|
+
return out(formatCalcNumber(filled));
|
|
164
|
+
case "percent_empty":
|
|
165
|
+
return out(pct(empty, total));
|
|
166
|
+
case "percent_not_empty":
|
|
167
|
+
return out(pct(filled, total));
|
|
168
|
+
case "checked":
|
|
169
|
+
return out(formatCalcNumber(values.filter(isChecked).length));
|
|
170
|
+
case "unchecked":
|
|
171
|
+
return out(formatCalcNumber(total - values.filter(isChecked).length));
|
|
172
|
+
case "percent_checked":
|
|
173
|
+
return out(pct(values.filter(isChecked).length, total));
|
|
174
|
+
case "percent_unchecked":
|
|
175
|
+
return out(pct(total - values.filter(isChecked).length, total));
|
|
176
|
+
case "sum":
|
|
177
|
+
case "average":
|
|
178
|
+
case "median":
|
|
179
|
+
case "min":
|
|
180
|
+
case "max":
|
|
181
|
+
case "range": {
|
|
182
|
+
const nums = values.map((v) => numberValue(v)).filter((n) => n !== null);
|
|
183
|
+
if (!nums.length) return out("\u2014");
|
|
184
|
+
const sorted = [...nums].sort((a, b) => a - b);
|
|
185
|
+
const sum = nums.reduce((a, b) => a + b, 0);
|
|
186
|
+
const mid = Math.floor(sorted.length / 2);
|
|
187
|
+
const value = kind === "sum" ? sum : kind === "average" ? sum / nums.length : kind === "median" ? sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2 : kind === "min" ? sorted[0] : kind === "max" ? sorted[sorted.length - 1] : sorted[sorted.length - 1] - sorted[0];
|
|
188
|
+
return out(formatCalcNumber(value));
|
|
189
|
+
}
|
|
190
|
+
case "earliest":
|
|
191
|
+
case "latest":
|
|
192
|
+
case "date_range": {
|
|
193
|
+
const days = values.map(dayOf).filter((d2) => !!d2).sort();
|
|
194
|
+
if (!days.length) return out("\u2014");
|
|
195
|
+
if (kind === "earliest") return out(shortDate(days[0]));
|
|
196
|
+
if (kind === "latest") return out(shortDate(days[days.length - 1]));
|
|
197
|
+
const ms = Date.parse(`${days[days.length - 1]}T00:00:00Z`) - Date.parse(`${days[0]}T00:00:00Z`);
|
|
198
|
+
const d = Math.round(ms / 864e5);
|
|
199
|
+
return out(`${d} day${d === 1 ? "" : "s"}`);
|
|
200
|
+
}
|
|
201
|
+
default:
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function calcKindFor(saved, type) {
|
|
206
|
+
const kind = typeof saved === "string" ? saved : "none";
|
|
207
|
+
return kindsFor(type).includes(kind) ? kind : "none";
|
|
208
|
+
}export{CALC_LABELS,calcKindFor,computeCalculation,formatCalcNumber,kindsFor};//# sourceMappingURL=databaseCalc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"databaseCalc.js","sources":["../../../../src/features/notion/database/databaseCalc.ts"],"sourcesContent":["/**\n * Footer calculations (Notion's \"Calculate\" row under each table column).\n *\n * kindsFor('number') → which calculations a column offers (grouped like Notion's menu)\n * computeCalculation(values, …) → the footer text, e.g. \"Sum 42\", \"Empty 3\", \"Checked 60%\"\n *\n * Values are the raw cells of the rows the view shows (after filter and search), so the footer\n * always describes what is on screen. Saved per view in `settings.calculations[property]`.\n */\nimport {\n cellDisplayText,\n dateRangeValue,\n isEmptyCell,\n multiSelectNames,\n numberValue,\n personEntries,\n relationIds,\n} from './databaseView';\n\nexport type CalcKind =\n | 'none'\n | 'count_all'\n | 'count_values'\n | 'count_unique'\n | 'count_empty'\n | 'count_not_empty'\n | 'percent_empty'\n | 'percent_not_empty'\n | 'sum'\n | 'average'\n | 'median'\n | 'min'\n | 'max'\n | 'range'\n | 'checked'\n | 'unchecked'\n | 'percent_checked'\n | 'percent_unchecked'\n | 'earliest'\n | 'latest'\n | 'date_range';\n\nexport const CALC_LABELS: Record<CalcKind, { menu: string; short: string }> = {\n none: { menu: 'None', short: '' },\n count_all: { menu: 'Count all', short: 'Count' },\n count_values: { menu: 'Count values', short: 'Values' },\n count_unique: { menu: 'Count unique values', short: 'Unique' },\n count_empty: { menu: 'Count empty', short: 'Empty' },\n count_not_empty: { menu: 'Count not empty', short: 'Not empty' },\n percent_empty: { menu: 'Percent empty', short: 'Empty' },\n percent_not_empty: { menu: 'Percent not empty', short: 'Not empty' },\n sum: { menu: 'Sum', short: 'Sum' },\n average: { menu: 'Average', short: 'Average' },\n median: { menu: 'Median', short: 'Median' },\n min: { menu: 'Min', short: 'Min' },\n max: { menu: 'Max', short: 'Max' },\n range: { menu: 'Range', short: 'Range' },\n checked: { menu: 'Checked', short: 'Checked' },\n unchecked: { menu: 'Unchecked', short: 'Unchecked' },\n percent_checked: { menu: 'Percent checked', short: 'Checked' },\n percent_unchecked: { menu: 'Percent unchecked', short: 'Unchecked' },\n earliest: { menu: 'Earliest date', short: 'Earliest' },\n latest: { menu: 'Latest date', short: 'Latest' },\n date_range: { menu: 'Date range', short: 'Range' },\n};\n\nconst COUNT_KINDS: CalcKind[] = [\n 'count_all',\n 'count_values',\n 'count_unique',\n 'count_empty',\n 'count_not_empty',\n 'percent_empty',\n 'percent_not_empty',\n];\nconst NUMBER_KINDS: CalcKind[] = ['sum', 'average', 'median', 'min', 'max', 'range'];\nconst CHECKBOX_KINDS: CalcKind[] = ['count_all', 'checked', 'unchecked', 'percent_checked', 'percent_unchecked'];\nconst DATE_TYPES = new Set(['date', 'created_time', 'last_edited_time']);\n\n/** Calculations offered for a column type, in menu order (groups: count, percent, number/date). */\nexport function kindsFor(type: string): CalcKind[] {\n if (type === 'checkbox') return ['none', ...CHECKBOX_KINDS];\n if (type === 'number' || type === 'formula' || type === 'rollup') return ['none', ...COUNT_KINDS, ...NUMBER_KINDS];\n if (DATE_TYPES.has(type)) return ['none', ...COUNT_KINDS, 'earliest', 'latest', 'date_range'];\n if (type === 'button') return ['none', 'count_all'];\n return ['none', ...COUNT_KINDS];\n}\n\n/** Values a column holds for \"count values\" / \"unique\" (multi-select counts each option). */\nfunction valueTokens(value: unknown, type: string): string[] {\n if (isEmptyCell(value, type)) return [];\n switch (type) {\n case 'multi_select':\n return multiSelectNames(value);\n case 'person':\n return personEntries(value).map((p) => p.name);\n case 'relation':\n return relationIds(value);\n case 'files':\n return cellDisplayText(value, type)\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n default: {\n const text = cellDisplayText(value, type).trim();\n return text ? [text] : [];\n }\n }\n}\n\nfunction isChecked(value: unknown): boolean {\n return value === true || value === 'true';\n}\n\nfunction dayOf(value: unknown): string | null {\n if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}T/.test(value)) return value.slice(0, 10);\n const range = dateRangeValue(value);\n return range?.start ?? null;\n}\n\n/** Locale number, at most 2 decimals (\"1,234.5\"). */\nexport function formatCalcNumber(n: number): string {\n if (!Number.isFinite(n)) return '—';\n return n.toLocaleString(undefined, { maximumFractionDigits: 2 });\n}\n\nfunction pct(part: number, total: number): string {\n if (!total) return '0%';\n return `${formatCalcNumber((part / total) * 100)}%`;\n}\n\nfunction shortDate(day: string): string {\n return new Date(`${day}T00:00:00Z`).toLocaleDateString(undefined, {\n day: 'numeric',\n month: 'short',\n year: 'numeric',\n timeZone: 'UTC',\n });\n}\n\nexport interface CalcResult {\n /** Short label shown before the value (\"Sum\"). */\n label: string;\n /** The value (\"42\", \"60%\", \"3 Oct 2026\"); '' when there is nothing to show. */\n value: string;\n}\n\n/**\n * The footer result for one column. `values` are the cells of the rows on screen; `type` the\n * column type. Number kinds read numbers from number/formula/rollup cells and skip the rest.\n */\nexport function computeCalculation(values: unknown[], type: string, kind: CalcKind): CalcResult | null {\n if (!kind || kind === 'none') return null;\n const label = CALC_LABELS[kind]?.short ?? kind;\n const total = values.length;\n const empty = values.filter((v) => isEmptyCell(v, type)).length;\n const filled = total - empty;\n const out = (value: string): CalcResult => ({ label, value });\n switch (kind) {\n case 'count_all':\n return out(formatCalcNumber(total));\n case 'count_values':\n return out(formatCalcNumber(values.reduce<number>((n, v) => n + valueTokens(v, type).length, 0)));\n case 'count_unique':\n return out(formatCalcNumber(new Set(values.flatMap((v) => valueTokens(v, type))).size));\n case 'count_empty':\n return out(formatCalcNumber(empty));\n case 'count_not_empty':\n return out(formatCalcNumber(filled));\n case 'percent_empty':\n return out(pct(empty, total));\n case 'percent_not_empty':\n return out(pct(filled, total));\n case 'checked':\n return out(formatCalcNumber(values.filter(isChecked).length));\n case 'unchecked':\n return out(formatCalcNumber(total - values.filter(isChecked).length));\n case 'percent_checked':\n return out(pct(values.filter(isChecked).length, total));\n case 'percent_unchecked':\n return out(pct(total - values.filter(isChecked).length, total));\n case 'sum':\n case 'average':\n case 'median':\n case 'min':\n case 'max':\n case 'range': {\n const nums = values.map((v) => numberValue(v)).filter((n): n is number => n !== null);\n if (!nums.length) return out('—');\n const sorted = [...nums].sort((a, b) => a - b);\n const sum = nums.reduce((a, b) => a + b, 0);\n const mid = Math.floor(sorted.length / 2);\n const value =\n kind === 'sum'\n ? sum\n : kind === 'average'\n ? sum / nums.length\n : kind === 'median'\n ? sorted.length % 2\n ? sorted[mid]\n : (sorted[mid - 1] + sorted[mid]) / 2\n : kind === 'min'\n ? sorted[0]\n : kind === 'max'\n ? sorted[sorted.length - 1]\n : sorted[sorted.length - 1] - sorted[0];\n return out(formatCalcNumber(value));\n }\n case 'earliest':\n case 'latest':\n case 'date_range': {\n const days = values\n .map(dayOf)\n .filter((d): d is string => !!d)\n .sort();\n if (!days.length) return out('—');\n if (kind === 'earliest') return out(shortDate(days[0]));\n if (kind === 'latest') return out(shortDate(days[days.length - 1]));\n const ms = Date.parse(`${days[days.length - 1]}T00:00:00Z`) - Date.parse(`${days[0]}T00:00:00Z`);\n const d = Math.round(ms / 86_400_000);\n return out(`${d} day${d === 1 ? '' : 's'}`);\n }\n default:\n return null;\n }\n}\n\n/** A saved kind that still fits the column (a type change can leave e.g. \"Sum\" on a text column). */\nexport function calcKindFor(saved: unknown, type: string): CalcKind {\n const kind = typeof saved === 'string' ? (saved as CalcKind) : 'none';\n return kindsFor(type).includes(kind) ? kind : 'none';\n}\n"],"names":["d"],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {baseCellValue}from'./databaseView.js';import {dayKeyOf,shiftDayKey,localDayKey}from'./databaseFilter.js';function monthOf(d) {
|
|
2
|
+
return {
|
|
3
|
+
year: d.getFullYear(),
|
|
4
|
+
month: d.getMonth()
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
function shiftMonth(ref, delta) {
|
|
8
|
+
const d = new Date(ref.year, ref.month + delta, 1);
|
|
9
|
+
return {
|
|
10
|
+
year: d.getFullYear(),
|
|
11
|
+
month: d.getMonth()
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function monthOfDay(day) {
|
|
15
|
+
const [y, m] = day.split("-").map(Number);
|
|
16
|
+
return {
|
|
17
|
+
year: y,
|
|
18
|
+
month: m - 1
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function monthLabel(ref) {
|
|
22
|
+
return new Date(ref.year, ref.month, 1).toLocaleDateString(void 0, {
|
|
23
|
+
month: "long",
|
|
24
|
+
year: "numeric"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function weekdayLabels(weekStartsOn = 0, format = "short") {
|
|
28
|
+
return Array.from({
|
|
29
|
+
length: 7
|
|
30
|
+
}, (_, i) => new Date(2023, 0, 1 + (i + weekStartsOn) % 7).toLocaleDateString(void 0, {
|
|
31
|
+
weekday: format
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
function monthGrid(ref, weekStartsOn = 0) {
|
|
35
|
+
const first = new Date(ref.year, ref.month, 1);
|
|
36
|
+
const lead = (first.getDay() - weekStartsOn + 7) % 7;
|
|
37
|
+
const daysInMonth = new Date(ref.year, ref.month + 1, 0).getDate();
|
|
38
|
+
const total = Math.ceil((lead + daysInMonth) / 7) * 7;
|
|
39
|
+
const weeks = [];
|
|
40
|
+
for (let i = 0; i < total; i++) {
|
|
41
|
+
if (i % 7 === 0) weeks.push([]);
|
|
42
|
+
weeks[weeks.length - 1].push(localDayKey(new Date(ref.year, ref.month, 1 - lead + i)));
|
|
43
|
+
}
|
|
44
|
+
return weeks;
|
|
45
|
+
}
|
|
46
|
+
function isSameMonth(day, ref) {
|
|
47
|
+
const m = monthOfDay(day);
|
|
48
|
+
return m.year === ref.year && m.month === ref.month;
|
|
49
|
+
}
|
|
50
|
+
function dayNumber(day) {
|
|
51
|
+
return Number(day.slice(8, 10));
|
|
52
|
+
}
|
|
53
|
+
function dayLabel(day) {
|
|
54
|
+
const [y, m, d] = day.split("-").map(Number);
|
|
55
|
+
return new Date(y, m - 1, d).toLocaleDateString(void 0, {
|
|
56
|
+
weekday: "long",
|
|
57
|
+
month: "long",
|
|
58
|
+
day: "numeric",
|
|
59
|
+
year: "numeric"
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
const MAX_SPAN_DAYS = 62;
|
|
63
|
+
function dateValueEndDay(value, start) {
|
|
64
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
65
|
+
const end = dayKeyOf(value.end);
|
|
66
|
+
return end && end > start ? end : null;
|
|
67
|
+
}
|
|
68
|
+
function bucketRowsByDay(rows, column, getValue = baseCellValue) {
|
|
69
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
70
|
+
const undated = [];
|
|
71
|
+
const spans = /* @__PURE__ */ new Map();
|
|
72
|
+
const put = (day, row) => {
|
|
73
|
+
const list = byDay.get(day);
|
|
74
|
+
if (list) list.push(row);
|
|
75
|
+
else byDay.set(day, [row]);
|
|
76
|
+
};
|
|
77
|
+
for (const row of rows) {
|
|
78
|
+
const value = getValue(row, column);
|
|
79
|
+
const day = dayKeyOf(value);
|
|
80
|
+
if (!day) {
|
|
81
|
+
undated.push(row);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
put(day, row);
|
|
85
|
+
const end = dateValueEndDay(value, day);
|
|
86
|
+
if (!end) continue;
|
|
87
|
+
spans.set(row.id, {
|
|
88
|
+
start: day,
|
|
89
|
+
end
|
|
90
|
+
});
|
|
91
|
+
const n = Math.min(daysBetweenKeys(end, day), MAX_SPAN_DAYS);
|
|
92
|
+
for (let i = 1; i <= n; i++) put(shiftDayKey(day, i), row);
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
byDay,
|
|
96
|
+
undated,
|
|
97
|
+
spans
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function weekOf(day, weekStartsOn = 0) {
|
|
101
|
+
const [y, m, d] = day.split("-").map(Number);
|
|
102
|
+
const lead = (new Date(y, m - 1, d).getDay() - weekStartsOn + 7) % 7;
|
|
103
|
+
return Array.from({
|
|
104
|
+
length: 7
|
|
105
|
+
}, (_, i) => shiftDayKey(day, i - lead));
|
|
106
|
+
}
|
|
107
|
+
function isWeekend(day) {
|
|
108
|
+
const [y, m, d] = day.split("-").map(Number);
|
|
109
|
+
const wd = new Date(y, m - 1, d).getDay();
|
|
110
|
+
return wd === 0 || wd === 6;
|
|
111
|
+
}
|
|
112
|
+
function weekLabel(week) {
|
|
113
|
+
const toDate = (k) => {
|
|
114
|
+
const [y, m, d] = k.split("-").map(Number);
|
|
115
|
+
return new Date(y, m - 1, d);
|
|
116
|
+
};
|
|
117
|
+
const a = toDate(week[0]);
|
|
118
|
+
const b = toDate(week[week.length - 1]);
|
|
119
|
+
const fmt = new Intl.DateTimeFormat(void 0, {
|
|
120
|
+
month: "short",
|
|
121
|
+
day: "numeric",
|
|
122
|
+
year: "numeric"
|
|
123
|
+
});
|
|
124
|
+
if (typeof fmt.formatRange === "function") return fmt.formatRange(a, b);
|
|
125
|
+
const sameMonth = a.getMonth() === b.getMonth() && a.getFullYear() === b.getFullYear();
|
|
126
|
+
const left = a.toLocaleDateString(void 0, {
|
|
127
|
+
month: "short",
|
|
128
|
+
day: "numeric"
|
|
129
|
+
});
|
|
130
|
+
const right = sameMonth ? String(b.getDate()) : b.toLocaleDateString(void 0, {
|
|
131
|
+
month: "short",
|
|
132
|
+
day: "numeric"
|
|
133
|
+
});
|
|
134
|
+
return `${left} \u2013 ${right}, ${b.getFullYear()}`;
|
|
135
|
+
}
|
|
136
|
+
function readCalendarSettings(settings) {
|
|
137
|
+
const s = settings && typeof settings === "object" ? settings : {};
|
|
138
|
+
return {
|
|
139
|
+
mode: s.calendarMode === "week" ? "week" : "month",
|
|
140
|
+
weekStartsOn: s.weekStartsOn === 1 ? 1 : 0,
|
|
141
|
+
showWeekends: s.showWeekends !== false
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function daysBetweenKeys(a, b) {
|
|
145
|
+
const [ya, ma, da] = a.split("-").map(Number);
|
|
146
|
+
const [yb, mb, db] = b.split("-").map(Number);
|
|
147
|
+
return Math.round((Date.UTC(ya, ma - 1, da) - Date.UTC(yb, mb - 1, db)) / 864e5);
|
|
148
|
+
}
|
|
149
|
+
function calendarDateProperty(columns, preferred) {
|
|
150
|
+
var _a, _b;
|
|
151
|
+
const dateLike = (c) => c.type === "date" || c.type === "created_time" || c.type === "last_edited_time";
|
|
152
|
+
if (preferred) {
|
|
153
|
+
const hit = columns.find((c) => c.name === preferred && dateLike(c));
|
|
154
|
+
if (hit) return hit;
|
|
155
|
+
}
|
|
156
|
+
return (_b = (_a = columns.find((c) => c.type === "date")) != null ? _a : columns.find(dateLike)) != null ? _b : null;
|
|
157
|
+
}export{MAX_SPAN_DAYS,bucketRowsByDay,calendarDateProperty,dateValueEndDay,dayLabel,dayNumber,daysBetweenKeys,isSameMonth,isWeekend,monthGrid,monthLabel,monthOf,monthOfDay,readCalendarSettings,shiftMonth,weekLabel,weekOf,weekdayLabels};//# sourceMappingURL=databaseCalendar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"databaseCalendar.js","sources":["../../../../src/features/notion/database/databaseCalendar.ts"],"sourcesContent":["/**\n * databaseCalendar — pure helpers for the calendar view: month grids of `YYYY-MM-DD` day keys,\n * bucketing rows by day, month navigation and moving a date value to another day without losing\n * its stored shape (time of day, `{ start }` objects).\n */\nimport { dateString, type CellGetter, type ColumnLike, type RowLike, baseCellValue } from './databaseView';\nimport { dayKeyOf, localDayKey, shiftDayKey } from './databaseFilter';\n\nexport interface MonthRef {\n year: number;\n /** 0-based month. */\n month: number;\n}\n\nexport function monthOf(d: Date): MonthRef {\n return { year: d.getFullYear(), month: d.getMonth() };\n}\n\nexport function shiftMonth(ref: MonthRef, delta: number): MonthRef {\n const d = new Date(ref.year, ref.month + delta, 1);\n return { year: d.getFullYear(), month: d.getMonth() };\n}\n\n/** The month of a `YYYY-MM-DD` key. */\nexport function monthOfDay(day: string): MonthRef {\n const [y, m] = day.split('-').map(Number);\n return { year: y, month: m - 1 };\n}\n\nexport function monthLabel(ref: MonthRef): string {\n return new Date(ref.year, ref.month, 1).toLocaleDateString(undefined, { month: 'long', year: 'numeric' });\n}\n\n/** Weekday names in grid order (short, localized). */\nexport function weekdayLabels(weekStartsOn = 0, format: 'short' | 'narrow' | 'long' = 'short'): string[] {\n // 2023-01-01 was a Sunday.\n return Array.from({ length: 7 }, (_, i) =>\n new Date(2023, 0, 1 + ((i + weekStartsOn) % 7)).toLocaleDateString(undefined, { weekday: format }),\n );\n}\n\n/**\n * The month as weeks of day keys, padded with the neighbouring months' days so every week is\n * complete (4–6 weeks). `weekStartsOn`: 0 = Sunday, 1 = Monday.\n */\nexport function monthGrid(ref: MonthRef, weekStartsOn = 0): string[][] {\n const first = new Date(ref.year, ref.month, 1);\n const lead = (first.getDay() - weekStartsOn + 7) % 7;\n const daysInMonth = new Date(ref.year, ref.month + 1, 0).getDate();\n const total = Math.ceil((lead + daysInMonth) / 7) * 7;\n const weeks: string[][] = [];\n for (let i = 0; i < total; i++) {\n if (i % 7 === 0) weeks.push([]);\n weeks[weeks.length - 1].push(localDayKey(new Date(ref.year, ref.month, 1 - lead + i)));\n }\n return weeks;\n}\n\nexport function isSameMonth(day: string, ref: MonthRef): boolean {\n const m = monthOfDay(day);\n return m.year === ref.year && m.month === ref.month;\n}\n\n/** Day-of-month number of a key. */\nexport function dayNumber(day: string): number {\n return Number(day.slice(8, 10));\n}\n\n/** Long label for a day key (\"Wednesday, October 7, 2026\"), for screen readers. */\nexport function dayLabel(day: string): string {\n const [y, m, d] = day.split('-').map(Number);\n return new Date(y, m - 1, d).toLocaleDateString(undefined, {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n });\n}\n\nexport interface DayBuckets<R> {\n byDay: Map<string, R[]>;\n /** Rows with no (valid) date for the property. */\n undated: R[];\n /** Rows whose date is a range: row id → first and last day. */\n spans?: Map<string, { start: string; end: string }>;\n}\n\n/** Longest range drawn day by day (longer ranges show on their first 62 days). */\nexport const MAX_SPAN_DAYS = 62;\n\n/** End day of a `{ start, end }` date value after its start, else null. */\nexport function dateValueEndDay(value: unknown, start: string): string | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return null;\n const end = dayKeyOf((value as { end?: unknown }).end);\n return end && end > start ? end : null;\n}\n\n/**\n * Bucket rows by the calendar day of `column` (row order preserved within a day). A date range\n * (`{ start, end }`) puts the row on every day it covers; `spans` records those continuation days.\n */\nexport function bucketRowsByDay<R extends RowLike>(\n rows: R[],\n column: ColumnLike,\n getValue: CellGetter = baseCellValue,\n): DayBuckets<R> {\n const byDay = new Map<string, R[]>();\n const undated: R[] = [];\n const spans = new Map<string, { start: string; end: string }>();\n const put = (day: string, row: R) => {\n const list = byDay.get(day);\n if (list) list.push(row);\n else byDay.set(day, [row]);\n };\n for (const row of rows) {\n const value = getValue(row, column);\n const day = dayKeyOf(value);\n if (!day) {\n undated.push(row);\n continue;\n }\n put(day, row);\n const end = dateValueEndDay(value, day);\n if (!end) continue;\n spans.set(row.id, { start: day, end });\n const n = Math.min(daysBetweenKeys(end, day), MAX_SPAN_DAYS);\n for (let i = 1; i <= n; i++) put(shiftDayKey(day, i), row);\n }\n return { byDay, undated, spans };\n}\n\n/** The week (7 day keys) that contains `day`. */\nexport function weekOf(day: string, weekStartsOn = 0): string[] {\n const [y, m, d] = day.split('-').map(Number);\n const lead = (new Date(y, m - 1, d).getDay() - weekStartsOn + 7) % 7;\n return Array.from({ length: 7 }, (_, i) => shiftDayKey(day, i - lead));\n}\n\n/** Saturday or Sunday. */\nexport function isWeekend(day: string): boolean {\n const [y, m, d] = day.split('-').map(Number);\n const wd = new Date(y, m - 1, d).getDay();\n return wd === 0 || wd === 6;\n}\n\n/** \"Oct 5 – 11, 2026\" / \"Sep 28 – Oct 4, 2026\" for a week of day keys. */\nexport function weekLabel(week: string[]): string {\n const toDate = (k: string) => {\n const [y, m, d] = k.split('-').map(Number);\n return new Date(y, m - 1, d);\n };\n const a = toDate(week[0]);\n const b = toDate(week[week.length - 1]);\n // Locale-aware (\"Oct 5 – 11, 2026\", \"5–11 Oct 2026\") where the runtime supports ranges.\n const fmt = new Intl.DateTimeFormat(undefined, {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n }) as Intl.DateTimeFormat & {\n formatRange?: (x: Date, y: Date) => string;\n };\n if (typeof fmt.formatRange === 'function') return fmt.formatRange(a, b);\n const sameMonth = a.getMonth() === b.getMonth() && a.getFullYear() === b.getFullYear();\n const left = a.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n const right = sameMonth ? String(b.getDate()) : b.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n return `${left} – ${right}, ${b.getFullYear()}`;\n}\n\n/** Calendar options kept in the view's settings. */\nexport interface CalendarSettings {\n mode: 'month' | 'week';\n weekStartsOn: 0 | 1;\n showWeekends: boolean;\n}\n\nexport function readCalendarSettings(settings: unknown): CalendarSettings {\n const s = (settings && typeof settings === 'object' ? settings : {}) as Record<string, unknown>;\n return {\n mode: s.calendarMode === 'week' ? 'week' : 'month',\n weekStartsOn: s.weekStartsOn === 1 ? 1 : 0,\n showWeekends: s.showWeekends !== false,\n };\n}\n\n/**\n * Stored date value moved to `day`, keeping the previous value's shape: `{ start, … }` objects\n * keep their other fields, timestamps keep their time of day (and an `end` keeps its distance).\n * A missing previous value becomes a plain `YYYY-MM-DD`.\n */\nexport function moveDateValue(previous: unknown, day: string): unknown {\n const s = dateString(previous);\n const moveString = (value: string): string => {\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return day;\n const m = /^(\\d{4}-\\d{2}-\\d{2})(T.*)$/.exec(value);\n return m ? `${day}${m[2]}` : day;\n };\n if (previous && typeof previous === 'object' && !Array.isArray(previous)) {\n const obj = previous as Record<string, unknown>;\n const next: Record<string, unknown> = { ...obj, start: s ? moveString(s) : day };\n if (typeof obj.end === 'string' && s) {\n const from = dayKeyOf(s);\n const end = dayKeyOf(obj.end);\n if (from && end) {\n const delta = daysBetweenKeys(day, from);\n const [y, mo, d] = end.split('-').map(Number);\n const movedEnd = localDayKey(new Date(y, mo - 1, d + delta));\n next.end = /^\\d{4}-\\d{2}-\\d{2}$/.test(obj.end) ? movedEnd : `${movedEnd}${obj.end.slice(10)}`;\n }\n }\n return next;\n }\n return s ? moveString(s) : day;\n}\n\n/** Whole days from `b` to `a` (a − b) between two day keys. */\nexport function daysBetweenKeys(a: string, b: string): number {\n const [ya, ma, da] = a.split('-').map(Number);\n const [yb, mb, db] = b.split('-').map(Number);\n return Math.round((Date.UTC(ya, ma - 1, da) - Date.UTC(yb, mb - 1, db)) / 86_400_000);\n}\n\n/** Pick the calendar's date property: the preferred one when it is date-like, else the first. */\nexport function calendarDateProperty(columns: ColumnLike[], preferred?: string | null): ColumnLike | null {\n const dateLike = (c: ColumnLike) => c.type === 'date' || c.type === 'created_time' || c.type === 'last_edited_time';\n if (preferred) {\n const hit = columns.find((c) => c.name === preferred && dateLike(c));\n if (hit) return hit;\n }\n return columns.find((c) => c.type === 'date') ?? columns.find(dateLike) ?? null;\n}\n"],"names":[],"mappings":"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"}
|