@pitcher/js-api 1.28.0 → 1.30.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/js-api.esm.js +477 -44
- package/js-api.esm.js.map +1 -1
- package/js-api.umd.min.js +32 -11
- package/js-api.umd.min.js.map +1 -1
- package/lib/ai-tasks/__tests__/weekly-focus.spec.d.ts +1 -0
- package/lib/ai-tasks/weekly-focus.d.ts +241 -0
- package/lib/apps/browser/appTypes.d.ts +28 -0
- package/lib/apps/browser/stores/api.d.ts +6 -1
- package/lib/apps/browser/stores/app.d.ts +5 -0
- package/lib/apps/browser/stores/app.selectionPruneScope.test.d.ts +1 -0
- package/lib/apps/browser/stores/upload.d.ts +26 -1
- package/lib/apps/browser/stores/upload.types.d.ts +9 -0
- package/lib/apps/browser/util/lifecycle.d.ts +57 -0
- package/lib/apps/browser/util/lifecycle.test.d.ts +1 -0
- package/lib/apps/canvas-builder/components/ui/DynamicContent/useDynamicContent.d.ts +2 -0
- package/lib/apps/canvas-builder/components/ui/Multimedia/Multimedia.ldAsset.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/composables/useCanvas.d.ts +203 -1
- package/lib/apps/canvas-builder/composables/useCanvas.saveEcho.spec.d.ts +1 -0
- package/lib/apps/canvas-builder/composables/useCanvasBlocks.d.ts +36 -0
- package/lib/apps/canvas-builder/composables/useCanvasExit.d.ts +1 -0
- package/lib/apps/canvas-builder/composables/useCanvasHistory.d.ts +36 -0
- package/lib/apps/canvas-builder/composables/useCanvasTheme.d.ts +20 -18
- package/lib/apps/canvas-builder/composables/useContentSelector.d.ts +8 -1
- package/lib/apps/canvas-builder/composables/useInstalledEmbeddables.d.ts +1 -1
- package/lib/apps/canvas-builder/composables/useNavigatorDrawer.d.ts +2 -0
- package/lib/apps/canvas-builder/composables/usePopupApps.d.ts +2 -0
- package/lib/apps/canvas-builder/types/canvas.d.ts +53 -3
- package/lib/apps/canvas-builder/util/canvas.util.d.ts +8 -0
- package/lib/apps/canvas-builder/util/completionWizard.util.d.ts +107 -0
- package/lib/apps/canvas-builder/util/completionWizard.util.test.d.ts +1 -0
- package/lib/apps/canvas-builder/util/fullscreenMode.util.d.ts +7 -0
- package/lib/apps/canvas-builder/util/fullscreenMode.util.test.d.ts +1 -0
- package/lib/apps/canvas-builder/util/lazySections.util.d.ts +35 -0
- package/lib/apps/canvas-builder/util/lazySections.util.test.d.ts +1 -0
- package/lib/apps/collection-player/composables/collection-navigation.util.d.ts +27 -0
- package/lib/apps/collection-player/composables/collection-navigation.util.spec.d.ts +1 -0
- package/lib/apps/collection-player/stores/app.store.d.ts +3 -0
- package/lib/apps/content-selector/components/Assets.uploaderRefresh.spec.d.ts +1 -0
- package/lib/apps/content-selector/stores/app.d.ts +1 -1
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.annotations.use.d.ts +5 -1
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.formFields.use.d.ts +8 -0
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.link.use.d.ts +1 -1
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.overlayItems.use.d.ts +1 -1
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.use.d.ts +4 -9
- package/lib/components/CFileViewer/pdf/CFileViewer.pdf.util.d.ts +1 -1
- package/lib/components/CFileViewer/pdf/CFileViewerFullscreen.pdf.use.d.ts +1 -1
- package/lib/components/CFileViewer/pdf/__tests__/CFileViewer.pdf.annotations.text.test.d.ts +1 -0
- package/lib/components/savedCanvases/CSavedCanvasesManagement.use.d.ts +1 -0
- package/lib/composables/useCourseOnlyApps.d.ts +1 -1
- package/lib/composables/usePdfInterpolation.d.ts +2 -2
- package/lib/composables/useWindowEvents.d.ts +1 -1
- package/lib/constants/cdp.const.d.ts +1 -0
- package/lib/constants/translationLanguages.const.d.ts +72 -0
- package/lib/main.lib.d.ts +2 -0
- package/lib/sdk/api/HighLevelApi.d.ts +26 -9
- package/lib/sdk/api/modules/admin/types.admin.d.ts +1 -0
- package/lib/sdk/api/modules/ai.d.ts +43 -1
- package/lib/sdk/api/modules/ai.spec.d.ts +1 -0
- package/lib/sdk/api/modules/canvas.d.ts +8 -0
- package/lib/sdk/api/modules/index.d.ts +2 -1
- package/lib/sdk/api/modules/stt.d.ts +65 -0
- package/lib/sdk/api/modules/stt.spec.d.ts +1 -0
- package/lib/sdk/api/modules/tts.d.ts +41 -0
- package/lib/sdk/api/modules/tts.spec.d.ts +1 -0
- package/lib/sdk/api/modules/ui/types.ui.d.ts +7 -0
- package/lib/sdk/interfaces.d.ts +26 -1
- package/lib/sdk/main.d.ts +35 -6
- package/lib/sdk/payload.types.d.ts +284 -0
- package/lib/types/ai-tasks.const.d.ts +39 -1
- package/lib/types/call.d.ts +14 -0
- package/lib/types/canvases.d.ts +0 -3
- package/lib/types/launchDarkly.types.d.ts +1 -3
- package/lib/types/organizationSettings.types.d.ts +10 -0
- package/lib/types/sfdc.d.ts +15 -0
- package/lib/util/soql.util.d.ts +36 -0
- package/lib/util/user.d.ts +18 -0
- package/lib/util/user.test.d.ts +1 -0
- package/package.json +1 -1
- package/types/openapi/index.d.ts +0 -1
- package/types/openapi/models/DeletedEnvironment.d.ts +0 -1
- package/types/openapi/models/Environment.d.ts +0 -1
- package/types/openapi/models/EnvironmentRequest.d.ts +0 -1
- package/types/openapi/models/File.d.ts +2 -0
- package/types/openapi/models/FileRetrieve.d.ts +2 -0
- package/types/openapi/models/PatchedEnvironmentRequest.d.ts +0 -1
- package/types/openapi/models/PatchedUserRequest.d.ts +1 -2
- package/types/openapi/models/User.d.ts +1 -2
- package/types/openapi/models/UserRequest.d.ts +1 -2
- package/lib/sdk/api/modules/languages.d.ts +0 -8
- package/types/openapi/models/LanguageEnum.d.ts +0 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `weekly_focus` AITask — window, prompt, parser and ordinal resolver (PIT-7257).
|
|
3
|
+
*
|
|
4
|
+
* Ported from the battle-tested client-side implementation in the pre-call-brief
|
|
5
|
+
* embedded app (`ng-demo-scripts/Embedded Apps/pre-call-brief/src/weekly-focus/`,
|
|
6
|
+
* PIT-6305), which has been ranking reps' weeks on-device via a single Gemma
|
|
7
|
+
* `ai.complete` call. This is the FRONT-END copy — used by the JS-API SDK's
|
|
8
|
+
* on-device `weeklyFocusRank` (`sdk/api/modules/ai.ts`) and, in turn, the
|
|
9
|
+
* pre-call-brief app.
|
|
10
|
+
*
|
|
11
|
+
* There is a PARALLEL copy in next-core
|
|
12
|
+
* (`packages/next-core/src/services/pia-prepare/prompts/weekly-focus.ts`) that
|
|
13
|
+
* serves the online Bedrock route. The two are a deliberate duplicate: next-core
|
|
14
|
+
* imports canvas-ui TYPES only, never a runtime value (ADR-002 invariant 1 — the
|
|
15
|
+
* package's main barrel is a Vue bundle that must not reach a Node Fargate task).
|
|
16
|
+
* They MUST stay behaviourally in lockstep — each carries its own behavioural
|
|
17
|
+
* test suite (`__tests__/weekly-focus.spec.ts` here,
|
|
18
|
+
* `__tests__/weekly-focus-logic.test.ts` there). Change one, change the other.
|
|
19
|
+
*
|
|
20
|
+
* The app OWNS its cache (localStorage, local date, end-of-day TTL), its
|
|
21
|
+
* single-inference lock (`aiLock.ts`, shared with the brief prewarm queue) and
|
|
22
|
+
* its CRM rail fetch. Those are deliberately NOT here — PIT-7257 explicitly
|
|
23
|
+
* scopes out "changing the app's on-device cache/lock/prewarm mechanics".
|
|
24
|
+
*/
|
|
25
|
+
/** Rolling window: today + 6 days. */
|
|
26
|
+
export declare const WINDOW_DAYS = 6;
|
|
27
|
+
/**
|
|
28
|
+
* Working-window cap: the on-device model runs a ~2K-token window and a meeting
|
|
29
|
+
* block costs ~80-110 tokens, leaving room for ~12. Heavier weeks rank the 12
|
|
30
|
+
* NEAREST meetings; the rest fold into `collapsed_count`, which stays truthful.
|
|
31
|
+
* Kept identical on the Bedrock path (which has no such limit) so the ordinals
|
|
32
|
+
* and `collapsed_count` mean the same thing on both backends.
|
|
33
|
+
*/
|
|
34
|
+
export declare const MAX_RANK_MEETINGS = 12;
|
|
35
|
+
/** Hard output caps — enforced in JS, never trusted to the model. */
|
|
36
|
+
export declare const HERO_MAX_CHARS = 400;
|
|
37
|
+
export declare const REASON_MAX_CHARS = 140;
|
|
38
|
+
/** Spec default; admins may configure 1-8. */
|
|
39
|
+
export declare const DEFAULT_MAX_PICKS = 5;
|
|
40
|
+
/** The meeting shape the ranking needs. A structural subset of the app's `Meeting`. */
|
|
41
|
+
export type WeeklyFocusMeeting = {
|
|
42
|
+
event_id: string;
|
|
43
|
+
account_id: string;
|
|
44
|
+
account_name: string;
|
|
45
|
+
meeting_subject: string;
|
|
46
|
+
/** ISO datetime, or a date-only 'YYYY-MM-DD' (SFDC ActivityDate). */
|
|
47
|
+
meeting_time: string;
|
|
48
|
+
attendee_count?: number;
|
|
49
|
+
};
|
|
50
|
+
/** One labeled CRM record inside an account context section. */
|
|
51
|
+
export type WeeklyFocusContextItem = {
|
|
52
|
+
title: string;
|
|
53
|
+
fields?: Array<{
|
|
54
|
+
label: string;
|
|
55
|
+
value: string;
|
|
56
|
+
}>;
|
|
57
|
+
days_ago?: number | null;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* One account's CRM context, as mapped by the admin's config-driven rail (open
|
|
61
|
+
* tasks, opportunity state, recent calls — whatever they mapped). `items` is
|
|
62
|
+
* already in display order: soonest upcoming, else most recent past.
|
|
63
|
+
*/
|
|
64
|
+
export type WeeklyFocusContextSection = {
|
|
65
|
+
label: string;
|
|
66
|
+
items: WeeklyFocusContextItem[];
|
|
67
|
+
/** Only admin-labeled (curated) fields reach the prompt; raw API dumps are token noise. */
|
|
68
|
+
fields_curated?: boolean;
|
|
69
|
+
};
|
|
70
|
+
export type WeeklyFocusAccountContext = {
|
|
71
|
+
sections: WeeklyFocusContextSection[];
|
|
72
|
+
};
|
|
73
|
+
/** One resolved pick — a decoration over a meeting the surface already renders. */
|
|
74
|
+
export type WeeklyFocusPick = {
|
|
75
|
+
event_id: string;
|
|
76
|
+
/** 1 = highest priority; unique and contiguous from 1. */
|
|
77
|
+
rank: number;
|
|
78
|
+
reason: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* The task's typed output — the ORDINAL shape the model returns. `m` is the
|
|
82
|
+
* meeting's number in the prompt's numbered list, not an id: a small model
|
|
83
|
+
* mangles 18-char SFDC ids, and an ordinal is a single token. Resolving
|
|
84
|
+
* ordinals to `event_id`s needs the meeting list, so it happens in
|
|
85
|
+
* `resolveWeeklyFocusPicks` (route/caller side), keeping normalize/extract
|
|
86
|
+
* context-free like every other AITask.
|
|
87
|
+
*/
|
|
88
|
+
export type WeeklyFocusOutput = {
|
|
89
|
+
hero: string;
|
|
90
|
+
top: Array<{
|
|
91
|
+
m: number;
|
|
92
|
+
reason: string;
|
|
93
|
+
}>;
|
|
94
|
+
collapsed_count?: number;
|
|
95
|
+
};
|
|
96
|
+
export type WeeklyFocusVariables = {
|
|
97
|
+
meetings: WeeklyFocusMeeting[];
|
|
98
|
+
/** Keyed by `account_id`. One bundle per UNIQUE account. */
|
|
99
|
+
context?: Record<string, WeeklyFocusAccountContext>;
|
|
100
|
+
max_picks?: number;
|
|
101
|
+
one_per_account?: boolean;
|
|
102
|
+
/** Overrides the default ranking rules (the admin-editable template). */
|
|
103
|
+
ranking_rules?: string;
|
|
104
|
+
/** IANA zone for the relative day labels. Defaults to the runtime's local zone. */
|
|
105
|
+
time_zone?: string;
|
|
106
|
+
now?: Date;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Persona + ranking rules ONLY. The JSON output-shape instruction and the
|
|
110
|
+
* numbered MEETINGS block are appended by code and are NOT admin-editable: the
|
|
111
|
+
* output is parser-coupled, so an edited-away format instruction would turn
|
|
112
|
+
* every generation into a parse failure.
|
|
113
|
+
*
|
|
114
|
+
* Tokens: {{meeting_count}}, {{max_picks}}, {{reason_max_chars}},
|
|
115
|
+
* {{hero_max_chars}}, {{account_rule}}.
|
|
116
|
+
*/
|
|
117
|
+
export declare const WEEKLY_FOCUS_RANKING_RULES = "You rank a sales rep's upcoming meetings by how much they need preparation.\n\nBelow are {{meeting_count}} numbered meetings, each with its account's CRM context (deals, tasks, recent calls).\n\nPick the {{max_picks}} most important. Pick fewer only if the list has fewer meetings.\n\nRules:\n- Highest priority first; ties go to the earlier meeting.\n- Strongest signals: an overdue or due-soon high-priority task, a poorly rated recent interaction, a deal closing within days. Routine meetings on healthy accounts rank last.\n- {{account_rule}}\n- Each \"reason\": ONE sentence, max {{reason_max_chars}} characters, only facts from the data \u2014 name the deal, task, rating, or date that makes it matter.\n- \"hero\": 1-2 sentences, max {{hero_max_chars}} characters, summarizing the week in plain business language.\n- Never invent facts. Never repeat field names, codes, or IDs.";
|
|
118
|
+
export declare const output_schema: {
|
|
119
|
+
readonly type: "object";
|
|
120
|
+
readonly properties: {
|
|
121
|
+
readonly hero: {
|
|
122
|
+
readonly type: "string";
|
|
123
|
+
readonly description: "One or two sentences summarising the rep's week in plain business language, max 400 characters.";
|
|
124
|
+
};
|
|
125
|
+
readonly top: {
|
|
126
|
+
readonly type: "array";
|
|
127
|
+
readonly description: "The picked meetings, highest priority first.";
|
|
128
|
+
readonly items: {
|
|
129
|
+
readonly type: "object";
|
|
130
|
+
readonly properties: {
|
|
131
|
+
readonly m: {
|
|
132
|
+
readonly type: "integer";
|
|
133
|
+
readonly description: "The picked meeting's number from the numbered MEETINGS list.";
|
|
134
|
+
};
|
|
135
|
+
readonly reason: {
|
|
136
|
+
readonly type: "string";
|
|
137
|
+
readonly description: "One sentence, max 140 characters, using only facts from the data.";
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
readonly required: readonly ["m", "reason"];
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
};
|
|
144
|
+
readonly required: readonly ["hero", "top"];
|
|
145
|
+
};
|
|
146
|
+
/** Admin-configured pick count, clamped to a sane range. */
|
|
147
|
+
export declare function effectiveMaxPicks(maxPicks?: number): number;
|
|
148
|
+
/**
|
|
149
|
+
* Whole CALENDAR days between `iso` and now (positive = past, negative = future);
|
|
150
|
+
* null when unparseable.
|
|
151
|
+
*
|
|
152
|
+
* `timeZone` matters: on-device the runtime's local zone IS the rep's zone, but
|
|
153
|
+
* next-core runs UTC on Fargate — windowing a Los Angeles rep's week against the
|
|
154
|
+
* server clock would shift the day boundary and drop or admit a day's meetings.
|
|
155
|
+
* Callers outside the rep's device MUST pass the rep's zone.
|
|
156
|
+
*
|
|
157
|
+
* Date-only values (SFDC ActivityDate/CloseDate, 'YYYY-MM-DD') parse as UTC
|
|
158
|
+
* midnight per ECMAScript, which is the PREVIOUS local day in negative-UTC-offset
|
|
159
|
+
* zones — a task due today would read "yesterday" in the US. They are calendar
|
|
160
|
+
* dates with no zone, so they're compared as-written.
|
|
161
|
+
*/
|
|
162
|
+
export declare function daysAgo(iso: string, options?: {
|
|
163
|
+
now?: Date;
|
|
164
|
+
timeZone?: string;
|
|
165
|
+
}): number | null;
|
|
166
|
+
/**
|
|
167
|
+
* Upcoming meetings inside the rolling window (today + 6 days), nearest first.
|
|
168
|
+
* Exported so a surface can list exactly the window the ranking saw.
|
|
169
|
+
*/
|
|
170
|
+
export declare function weeklyWindowMeetings(meetings: WeeklyFocusMeeting[], options?: {
|
|
171
|
+
now?: Date;
|
|
172
|
+
timeZone?: string;
|
|
173
|
+
}): WeeklyFocusMeeting[];
|
|
174
|
+
/**
|
|
175
|
+
* The full rank-and-annotate prompt. `meetings` must already be the windowed,
|
|
176
|
+
* capped list — the ordinals in the output index into it.
|
|
177
|
+
*
|
|
178
|
+
* The shape is described WITHOUT concrete meeting numbers: a small model parrots
|
|
179
|
+
* literal example values — an earlier {"m": 1}, {"m": 4} example made it return
|
|
180
|
+
* exactly meetings 1 and 4 (with freshly written reasons) run after run.
|
|
181
|
+
*/
|
|
182
|
+
export declare function template(variables: WeeklyFocusVariables): string;
|
|
183
|
+
/**
|
|
184
|
+
* Object (tool-use) → typed contract. Context-free: ordinals stay ordinals and
|
|
185
|
+
* are range-checked later against the meeting list. Caps ARE enforced here —
|
|
186
|
+
* they need no context and must hold on both the tool-use and text paths.
|
|
187
|
+
*/
|
|
188
|
+
export declare function normalizeWeeklyFocus(parsed: unknown): WeeklyFocusOutput;
|
|
189
|
+
/** Free text → typed contract. Soft-degrades to an empty shape, never throws. */
|
|
190
|
+
export declare function extractWeeklyFocus(rawText: string): WeeklyFocusOutput;
|
|
191
|
+
/**
|
|
192
|
+
* Resolve the model's ordinals against the meetings the prompt actually numbered,
|
|
193
|
+
* dropping out-of-range ordinals, duplicates and (by default) later same-account
|
|
194
|
+
* picks; assigns contiguous ranks from the surviving order.
|
|
195
|
+
*
|
|
196
|
+
* `windowCount` is the size of the FULL 7-day window, not the capped ranking set:
|
|
197
|
+
* `collapsed_count` answers "how many of my week's meetings aren't shown?", so it
|
|
198
|
+
* counts everything in the window that did not get a pick — including meetings
|
|
199
|
+
* that were ranked but not picked, and those beyond the 12-nearest cap.
|
|
200
|
+
*
|
|
201
|
+
* One-pick-per-account is the default: the model's highest-ranked pick represents
|
|
202
|
+
* the account. The softer "a second pick needs its own independent reason" rule
|
|
203
|
+
* failed three ways on-device (borrowed reasons, paraphrased reasons, and reasons
|
|
204
|
+
* that name the meeting's topic while still justifying from the sibling's
|
|
205
|
+
* context). Account context is shared, so the model cannot reliably tell which
|
|
206
|
+
* meeting deserves it.
|
|
207
|
+
*/
|
|
208
|
+
export declare function resolveWeeklyFocusPicks(output: WeeklyFocusOutput, rankedMeetings: WeeklyFocusMeeting[], options?: {
|
|
209
|
+
maxPicks?: number;
|
|
210
|
+
onePerAccount?: boolean;
|
|
211
|
+
windowCount?: number;
|
|
212
|
+
}): {
|
|
213
|
+
top: WeeklyFocusPick[];
|
|
214
|
+
collapsed_count: number;
|
|
215
|
+
dropped: number;
|
|
216
|
+
};
|
|
217
|
+
/**
|
|
218
|
+
* How many picks this week can actually support — the bar a result must clear
|
|
219
|
+
* before it counts as an undershoot worth one retry.
|
|
220
|
+
*
|
|
221
|
+
* With one-per-account enforcement the ceiling is DISTINCT ACCOUNTS, not
|
|
222
|
+
* meetings: a five-meeting week across two accounts can never yield more than
|
|
223
|
+
* two picks, and retrying it forever would be chasing an impossible target.
|
|
224
|
+
*/
|
|
225
|
+
export declare function weeklyFocusTarget(rankedMeetings: WeeklyFocusMeeting[], options?: {
|
|
226
|
+
maxPicks?: number;
|
|
227
|
+
onePerAccount?: boolean;
|
|
228
|
+
}): number;
|
|
229
|
+
/**
|
|
230
|
+
* The window + cap the prompt should see, and the window size `collapsed_count`
|
|
231
|
+
* must be computed against. One call so a caller cannot accidentally pair a
|
|
232
|
+
* capped list with the wrong window count.
|
|
233
|
+
*/
|
|
234
|
+
export declare function prepareWeeklyFocusMeetings(meetings: WeeklyFocusMeeting[], options?: {
|
|
235
|
+
now?: Date;
|
|
236
|
+
timeZone?: string;
|
|
237
|
+
}): {
|
|
238
|
+
windowMeetings: WeeklyFocusMeeting[];
|
|
239
|
+
rankedMeetings: WeeklyFocusMeeting[];
|
|
240
|
+
windowCount: number;
|
|
241
|
+
};
|
|
@@ -47,4 +47,32 @@ export interface BrowserAppProps {
|
|
|
47
47
|
onAssignDistributionGroups?: DistributionGroupsAssigner;
|
|
48
48
|
distributionGroupsManageUrl?: string;
|
|
49
49
|
customFilterComponents?: BrowserCustomFilterComponent[];
|
|
50
|
+
/**
|
|
51
|
+
* Shows the content lifecycle chip (All / Active / Expiring soon / Expired).
|
|
52
|
+
* Opt-in because the browser is shared with Impact, where the server already
|
|
53
|
+
* strips expired files for reps — an always-on chip would offer them an
|
|
54
|
+
* "Expired" view that is permanently empty.
|
|
55
|
+
*
|
|
56
|
+
* Deliberately NOT a `customFilterComponents` entry: any active custom filter
|
|
57
|
+
* forces a server fetch (`hasActiveCustomFilter` in ActionsToolbar), the API
|
|
58
|
+
* has no lifecycle parameter, and Django filter backends ignore unknown query
|
|
59
|
+
* params — so it would round-trip and return an unfiltered list.
|
|
60
|
+
*/
|
|
61
|
+
showLifecycleFilter?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Shows the content-translation entry points: the per-row Translate button and
|
|
64
|
+
* the upload modal's target-language picker.
|
|
65
|
+
*
|
|
66
|
+
* Opt-in for the same reason as `showLifecycleFilter`, plus a hard requirement:
|
|
67
|
+
* the feature is gated by the `enable_content_translation` LaunchDarkly flag and
|
|
68
|
+
* canvas-ui never reads LaunchDarkly, so the admin host passes this only when the
|
|
69
|
+
* flag resolves true. The rep host (`BrowserView.vue`) never passes it and never
|
|
70
|
+
* binds `translateFile` / `translateUploadedFile` — unhandled emits are silent
|
|
71
|
+
* no-ops — and the row button additionally requires `appName === 'admin'`, so
|
|
72
|
+
* reps have three independent blocks, not one.
|
|
73
|
+
*
|
|
74
|
+
* Both entry points only EMIT. The host owns every call to the translation
|
|
75
|
+
* routes; canvas-ui is shared and stays host-agnostic.
|
|
76
|
+
*/
|
|
77
|
+
showTranslateAction?: boolean;
|
|
50
78
|
}
|
|
@@ -40,7 +40,7 @@ type FileListFetcher = (params?: any) => Promise<File[]>;
|
|
|
40
40
|
type FileListSearchFetcher = (params?: any) => Promise<void>;
|
|
41
41
|
type FilesFoldersDeleter = (payload: BulkDeleteRequest) => Promise<BulkDeleteResponse>;
|
|
42
42
|
type SelectDeviceFile = () => Promise<DeviceFile | undefined>;
|
|
43
|
-
type CompactFile = Pick<File, 'id' | 'name' | 'thumbnail_url' | 'tags' | 'created_by' | 'modified_at' | 'status' | 'content_type' | 'permissions' | 'owned_by' | 'original_extension' | 'metadata'>;
|
|
43
|
+
type CompactFile = Pick<File, 'id' | 'name' | 'thumbnail_url' | 'tags' | 'created_by' | 'modified_at' | 'status' | 'content_type' | 'permissions' | 'owned_by' | 'original_extension' | 'metadata' | 'expires_at'>;
|
|
44
44
|
type ItemsMoverItem = {
|
|
45
45
|
id: File['id'] | Folder['id'];
|
|
46
46
|
type: 'file' | 'folder';
|
|
@@ -169,6 +169,7 @@ declare const _default: () => {
|
|
|
169
169
|
readonly can_print: boolean;
|
|
170
170
|
} | undefined;
|
|
171
171
|
readonly content_type: import('../../../../types/openapi').FileContentTypeEnum;
|
|
172
|
+
readonly expires_at?: string | null | undefined;
|
|
172
173
|
readonly status: FileStatusEnum;
|
|
173
174
|
readonly original_extension: string | null;
|
|
174
175
|
readonly owned_by: {
|
|
@@ -204,6 +205,7 @@ declare const _default: () => {
|
|
|
204
205
|
readonly original_url: string | null;
|
|
205
206
|
readonly thumbnail_url: string | null;
|
|
206
207
|
readonly download_type?: import('../../../../types/openapi').DownloadTypeEnum | undefined;
|
|
208
|
+
readonly downloaded_at?: string | null | undefined;
|
|
207
209
|
readonly zip_size: number | null;
|
|
208
210
|
readonly zip_url: string | null;
|
|
209
211
|
readonly access_type?: import('../../../../types/openapi').AccessTypeEnum | undefined;
|
|
@@ -452,6 +454,7 @@ declare const _default: () => {
|
|
|
452
454
|
readonly can_print: boolean;
|
|
453
455
|
} | undefined;
|
|
454
456
|
readonly content_type: import('../../../../types/openapi').FileContentTypeEnum;
|
|
457
|
+
readonly expires_at?: string | null | undefined;
|
|
455
458
|
readonly status: FileStatusEnum;
|
|
456
459
|
readonly original_extension: string | null;
|
|
457
460
|
readonly owned_by: {
|
|
@@ -588,6 +591,7 @@ declare const _default: () => {
|
|
|
588
591
|
readonly can_print: boolean;
|
|
589
592
|
} | undefined;
|
|
590
593
|
readonly content_type: import('../../../../types/openapi').FileContentTypeEnum;
|
|
594
|
+
expires_at?: string | null | undefined;
|
|
591
595
|
readonly status: FileStatusEnum;
|
|
592
596
|
readonly original_extension: string | null;
|
|
593
597
|
readonly owned_by: {
|
|
@@ -623,6 +627,7 @@ declare const _default: () => {
|
|
|
623
627
|
readonly original_url: string | null;
|
|
624
628
|
readonly thumbnail_url: string | null;
|
|
625
629
|
download_type?: import('../../../../types/openapi').DownloadTypeEnum | undefined;
|
|
630
|
+
readonly downloaded_at?: string | null | undefined;
|
|
626
631
|
readonly zip_size: number | null;
|
|
627
632
|
readonly zip_url: string | null;
|
|
628
633
|
access_type?: import('../../../../types/openapi').AccessTypeEnum | undefined;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Ref, ComputedRef } from 'vue';
|
|
2
2
|
import { File, Folder, MiniFolder } from '../../../../types/openapi';
|
|
3
3
|
import { ViewCompactFile, ViewCompactFileFolder, ViewCompactFolder } from '../../../types/files';
|
|
4
|
+
import { LifecycleFilter } from '../util/lifecycle';
|
|
4
5
|
import { OrganizationSettings } from '../../../types/organizationSettings.types';
|
|
5
6
|
import { InstanceSettings } from '../../../types/instanceSettings.types';
|
|
6
7
|
export type AppName = 'admin' | 'impact';
|
|
@@ -17,6 +18,7 @@ type View = 'grid' | 'table';
|
|
|
17
18
|
export default function (): {
|
|
18
19
|
setAppName(appName: AppName): void;
|
|
19
20
|
setSortOption(sortOption: SortOption): void;
|
|
21
|
+
setLifecycleFilter(filter: LifecycleFilter): void;
|
|
20
22
|
resetSelectedItems(): void;
|
|
21
23
|
removeSelectedItems(removeIds: SelectedItemId[]): void;
|
|
22
24
|
selectAll(): void;
|
|
@@ -49,7 +51,10 @@ export default function (): {
|
|
|
49
51
|
displayedFiles: ComputedRef<ViewCompactFile[]>;
|
|
50
52
|
displayedFolders: ComputedRef<ViewCompactFolder[]>;
|
|
51
53
|
displayedFilesFolders: ComputedRef<ViewCompactFileFolder[]>;
|
|
54
|
+
hasDisplayableItems: ComputedRef<boolean>;
|
|
55
|
+
hasActiveNarrowing: ComputedRef<boolean>;
|
|
52
56
|
isContentPanelOpen: Ref<boolean>;
|
|
57
|
+
lifecycleFilter: Ref<LifecycleFilter>;
|
|
53
58
|
updatingFolderId: Ref<Folder["id"] | null>;
|
|
54
59
|
selectedFileId: ComputedRef<File["id"] | null>;
|
|
55
60
|
selectedFolderId: ComputedRef<Folder["id"] | null>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { AccessTypeEnum } from '../../../../types/openapi';
|
|
1
|
+
import { AccessTypeEnum, File } from '../../../../types/openapi';
|
|
2
2
|
import { Upload } from './upload.types';
|
|
3
3
|
import { DeviceFile } from '../../../types/files';
|
|
4
|
+
export declare const INTERRUPTED_UPLOADS_STORAGE_KEY = "pitcher:browser:interrupted-uploads";
|
|
4
5
|
export default function (): {
|
|
5
6
|
state: {
|
|
6
7
|
queue: import('vue').Ref<({
|
|
@@ -14,6 +15,7 @@ export default function (): {
|
|
|
14
15
|
groupsAssignmentErrorMessage?: string | undefined;
|
|
15
16
|
group_ids?: string[] | undefined;
|
|
16
17
|
additionalFolderIds?: string[] | undefined;
|
|
18
|
+
targetLanguages?: string[] | undefined;
|
|
17
19
|
fanOutWarningMessage?: ((failedFolderIds: string[]) => string) | undefined;
|
|
18
20
|
path: string;
|
|
19
21
|
content: {
|
|
@@ -63,6 +65,7 @@ export default function (): {
|
|
|
63
65
|
groupsAssignmentErrorMessage?: string | undefined;
|
|
64
66
|
group_ids?: string[] | undefined;
|
|
65
67
|
additionalFolderIds?: string[] | undefined;
|
|
68
|
+
targetLanguages?: string[] | undefined;
|
|
66
69
|
fanOutWarningMessage?: ((failedFolderIds: string[]) => string) | undefined;
|
|
67
70
|
content?: {
|
|
68
71
|
readonly size: number;
|
|
@@ -114,6 +117,7 @@ export default function (): {
|
|
|
114
117
|
groupsAssignmentErrorMessage?: string | undefined;
|
|
115
118
|
group_ids?: string[] | undefined;
|
|
116
119
|
additionalFolderIds?: string[] | undefined;
|
|
120
|
+
targetLanguages?: string[] | undefined;
|
|
117
121
|
fanOutWarningMessage?: ((failedFolderIds: string[]) => string) | undefined;
|
|
118
122
|
path: string;
|
|
119
123
|
content: {
|
|
@@ -163,6 +167,7 @@ export default function (): {
|
|
|
163
167
|
groupsAssignmentErrorMessage?: string | undefined;
|
|
164
168
|
group_ids?: string[] | undefined;
|
|
165
169
|
additionalFolderIds?: string[] | undefined;
|
|
170
|
+
targetLanguages?: string[] | undefined;
|
|
166
171
|
fanOutWarningMessage?: ((failedFolderIds: string[]) => string) | undefined;
|
|
167
172
|
content?: {
|
|
168
173
|
readonly size: number;
|
|
@@ -238,10 +243,30 @@ export default function (): {
|
|
|
238
243
|
path: string;
|
|
239
244
|
size: number;
|
|
240
245
|
}[]>;
|
|
246
|
+
pendingTranslations: import('vue').Ref<{
|
|
247
|
+
id: File["id"];
|
|
248
|
+
targetLanguages: string[];
|
|
249
|
+
}[], {
|
|
250
|
+
id: File["id"];
|
|
251
|
+
targetLanguages: string[];
|
|
252
|
+
}[] | {
|
|
253
|
+
id: File["id"];
|
|
254
|
+
targetLanguages: string[];
|
|
255
|
+
}[]>;
|
|
256
|
+
hasPendingTranslations: import('vue').ComputedRef<boolean>;
|
|
241
257
|
};
|
|
242
258
|
actions: {
|
|
243
259
|
addUploads: (uploads: Upload[], onUploadCompleteCb?: any) => void;
|
|
244
260
|
removeUpload: (id: Upload["id"]) => void;
|
|
245
261
|
clearCompletedAndFailed: () => void;
|
|
262
|
+
consumeInterruptedUploads: () => string[];
|
|
263
|
+
queueTranslation: (selection: {
|
|
264
|
+
id: File["id"];
|
|
265
|
+
targetLanguages: string[];
|
|
266
|
+
}) => void;
|
|
267
|
+
takePendingTranslations: () => {
|
|
268
|
+
id: File["id"];
|
|
269
|
+
targetLanguages: string[];
|
|
270
|
+
}[];
|
|
246
271
|
};
|
|
247
272
|
};
|
|
@@ -24,6 +24,15 @@ export type Upload = {
|
|
|
24
24
|
* API in this shape; the upload store iterates it to drive copy calls.
|
|
25
25
|
*/
|
|
26
26
|
additionalFolderIds?: string[];
|
|
27
|
+
/**
|
|
28
|
+
* Platform locales the uploader asked for translated copies in. Client-side
|
|
29
|
+
* only — deliberately NOT part of the file-create payload: `File.metadata` is
|
|
30
|
+
* template-validated on write, so an unknown key can fail the upload itself on
|
|
31
|
+
* an instance with a strict metadata template, and nothing server-side reads it.
|
|
32
|
+
* The upload modal reads it back on completion and emits the selection to the
|
|
33
|
+
* host, which calls the translation route with the created file's id.
|
|
34
|
+
*/
|
|
35
|
+
targetLanguages?: string[];
|
|
27
36
|
/**
|
|
28
37
|
* Message factory invoked when the fan-out finishes with some failures.
|
|
29
38
|
* Returns the warning string to display on the upload queue item.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content lifecycle filtering for the content browser.
|
|
3
|
+
*
|
|
4
|
+
* `expires_at` is Pitcher's archival primitive: once the timestamp passes, the
|
|
5
|
+
* file is out of rep circulation (Django's `active()` / `for_user()` filter on
|
|
6
|
+
* `expires_at__gt=now`), but the row stays in the database, stays visible to
|
|
7
|
+
* admins, and is reversible by extending or clearing the date. Nothing here is
|
|
8
|
+
* on the delete path. So "expired" reads as "archived", and this filter is the
|
|
9
|
+
* way to see that set as a set.
|
|
10
|
+
*
|
|
11
|
+
* Purely client-side on purpose: the admin browser already requests
|
|
12
|
+
* `include_expired: true` and the folder fetch is not paginated, so the client
|
|
13
|
+
* already holds every row together with its `expires_at`. There is no server
|
|
14
|
+
* parameter and none is needed.
|
|
15
|
+
*/
|
|
16
|
+
export type LifecycleFilter = 'all' | 'active' | 'expiring' | 'expired';
|
|
17
|
+
/**
|
|
18
|
+
* Matches the Analytics Admin "Expiring Files" report window. Two surfaces
|
|
19
|
+
* disagreeing on what "expiring soon" means is a support ticket waiting to
|
|
20
|
+
* happen, so this constant is deliberately not configurable.
|
|
21
|
+
*/
|
|
22
|
+
export declare const EXPIRING_WINDOW_DAYS = 30;
|
|
23
|
+
export declare const LIFECYCLE_FILTERS: readonly LifecycleFilter[];
|
|
24
|
+
/**
|
|
25
|
+
* True when `item` belongs in the given lifecycle bucket.
|
|
26
|
+
*
|
|
27
|
+
* `active` and `expiring` deliberately OVERLAP: a file due in ten days is both
|
|
28
|
+
* still in circulation and in need of attention. The control is single-select,
|
|
29
|
+
* so `active` means "everything reps can still see" and `expiring` narrows to
|
|
30
|
+
* the subset with a deadline. Do not "fix" these into disjoint buckets — an
|
|
31
|
+
* `active` view that hid content expiring next week would mislead.
|
|
32
|
+
*
|
|
33
|
+
* Comparison is instant-based, not calendar-day based, because expiry is a
|
|
34
|
+
* timestamp and the row badge renders it relatively ("Expires in a day").
|
|
35
|
+
*/
|
|
36
|
+
export declare function matchesLifecycle(item: {
|
|
37
|
+
expires_at?: string | null;
|
|
38
|
+
}, filter: LifecycleFilter, now?: number): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Folders are deliberately NOT filtered, in any bucket.
|
|
41
|
+
*
|
|
42
|
+
* They carry no `expires_at`, so an earlier draft hid them from the expiring and
|
|
43
|
+
* expired views on the reasoning that "an archive view should be a list of
|
|
44
|
+
* archived content, not content plus every folder". That was wrong for this UI:
|
|
45
|
+
* the content browser has no folder tree or sidebar, so a folder row in the
|
|
46
|
+
* table is the ONLY way to descend, and breadcrumbs only navigate up. Hiding
|
|
47
|
+
* folders made archived content that lives in a subfolder unreachable — the
|
|
48
|
+
* admin got "no results" at the root and had no way down, which defeats the
|
|
49
|
+
* whole point of the filter.
|
|
50
|
+
*
|
|
51
|
+
* Folders are navigation chrome here, not content. The row's own expiry badge is
|
|
52
|
+
* what distinguishes retired files from live ones.
|
|
53
|
+
*
|
|
54
|
+
* Do NOT "fix" this by routing folders through `matchesLifecycle`: they have no
|
|
55
|
+
* date, so the null-date rule would call them active, which happens to look
|
|
56
|
+
* right for three buckets and silently wrong for `expired`.
|
|
57
|
+
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -180,6 +180,7 @@ export declare function useDynamicContent(hasConfig?: Ref<boolean> | ComputedRef
|
|
|
180
180
|
readonly original_url: string | null;
|
|
181
181
|
readonly thumbnail_url: string | null;
|
|
182
182
|
download_type?: import('../../../../../../types/openapi').DownloadTypeEnum | undefined;
|
|
183
|
+
readonly downloaded_at?: string | null | undefined;
|
|
183
184
|
readonly zip_size: number | null;
|
|
184
185
|
readonly zip_url: string | null;
|
|
185
186
|
access_type?: import('../../../../../../types/openapi').AccessTypeEnum | undefined;
|
|
@@ -255,6 +256,7 @@ export declare function useDynamicContent(hasConfig?: Ref<boolean> | ComputedRef
|
|
|
255
256
|
readonly original_url: string | null;
|
|
256
257
|
readonly thumbnail_url: string | null;
|
|
257
258
|
download_type?: import('../../../../../../types/openapi').DownloadTypeEnum | undefined;
|
|
259
|
+
readonly downloaded_at?: string | null | undefined;
|
|
258
260
|
readonly zip_size: number | null;
|
|
259
261
|
readonly zip_url: string | null;
|
|
260
262
|
access_type?: import('../../../../../../types/openapi').AccessTypeEnum | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|