@sanity/workflow-studio-plugin 0.28.0 → 0.29.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/CHANGELOG.md +295 -0
- package/dist/_chunks-cjs/index.cjs +563 -193
- package/dist/_chunks-cjs/workflows-tool-root.cjs +698 -257
- package/dist/_chunks-es/index.js +549 -189
- package/dist/_chunks-es/workflows-tool-root.js +712 -261
- package/package.json +12 -12
|
@@ -8,22 +8,28 @@ import { useState, useEffect, useMemo, useRef, useSyncExternalStore, useCallback
|
|
|
8
8
|
|
|
9
9
|
import { useRouter } from "sanity/router";
|
|
10
10
|
|
|
11
|
-
import { isLiveEntry, AbortWorkflowDialog,
|
|
11
|
+
import { isLiveEntry, AbortWorkflowDialog, useSpaceToken, isEvaluationStale, DocPreviewLink, SpinnerSlot, useWorkflowInstanceEntry, useLogEventOnMount, WorkflowInstanceDetailViewed, LoadingRow, InvalidDocNotice, useDefinition, useContainerToken, openActivityGone, InstanceFaultNote, InstanceSnapshotBody, ActivityLog, ActivityDetailDialog, instanceBreadcrumb, CodeChip, instanceTitle, dueDatesOf, isDueDatePast, isOpenActivityStatus, definitionSnapshotOf, stageTitle, isActivityAssignedTo, namesNoDeployedDefinition, mappingIssueDetail, formatTimeAgo, formatShortDateTime, useWorkflowContext, readDeployedDefinitions, describeError, gdrLocality, openableSchemaType, identityOf, useMinuteClock, NoteBanner, EmptyState, CountedHeading, AlertGlyph, MetricPair, formatShortAgo, InlineEmphasis, DismissablePopover, createSubscribers, findActivity, stateByActivity, rowDateControlState, rowAssignControlState, isRoleAssignedTo, assigneesOf, datesOf, committedRowFace, activityRowProps, TOAST_ID, WORKFLOW_API_VERSION, useWorkflowToast, formatDate, parseStoredDateValue, useUserDisplays, useProjectMembers, HoverHint, WorkflowTaskFiltersApplied, DocRefFace, Hairline, LinkChip, BreadcrumbTail, StageFace, StaleLock, ActivityRow, WorkflowTitleSeedDrifted, UnreadableDocsNote, RoleAssignedNotice, ForMeEmptyState, MetaRow, TabSwitch, WORKFLOW_PAGE_TABS, definitionFingerprint, LogEventOnMount, WorkflowBoardWorkflowSelected, WorkflowDefinitionDetailViewed, toolRoute, landingState, TOOL_TABS, tabSelectionNavigates, WorkflowToolOpened, toolTabState, workflowPageState, instanceState, backToTabLabel, useAssignmentIdentity, workflowState } from "./index.js";
|
|
12
12
|
|
|
13
|
-
import { entryDocRefs, startKindOf, isSubjectEntry, isInputSourced, errorMessage, latestDeployedDefinitions,
|
|
13
|
+
import { entryDocRefs, toBareId, findOpenStageEntry, terminalState, documentStuckCause, startKindOf, isSubjectEntry, isInputSourced, errorMessage, latestDeployedDefinitions, isStartableDefinition, findActivityNode } from "@sanity/workflow-engine";
|
|
14
14
|
|
|
15
15
|
import { ArrowLeftIcon } from "@sanity/icons/ArrowLeft";
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { CalendarIcon } from "@sanity/icons/Calendar";
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import { ClockIcon } from "@sanity/icons/Clock";
|
|
20
20
|
|
|
21
|
-
import
|
|
21
|
+
import { DocumentIcon } from "@sanity/icons/Document";
|
|
22
|
+
|
|
23
|
+
import { ErrorOutlineIcon } from "@sanity/icons/ErrorOutline";
|
|
22
24
|
|
|
23
|
-
import {
|
|
25
|
+
import { TransferIcon } from "@sanity/icons/Transfer";
|
|
26
|
+
|
|
27
|
+
import { useDocumentPreviewStore, useSchema, usePerspective, useClient } from "sanity";
|
|
24
28
|
|
|
25
29
|
import { useWorkflowInstances } from "@sanity/workflow-studio";
|
|
26
30
|
|
|
31
|
+
import pluralize from "pluralize-esm";
|
|
32
|
+
|
|
27
33
|
import { AddIcon } from "@sanity/icons/Add";
|
|
28
34
|
|
|
29
35
|
import { SearchIcon } from "@sanity/icons/Search";
|
|
@@ -46,6 +52,10 @@ import { ChevronRightIcon } from "@sanity/icons/ChevronRight";
|
|
|
46
52
|
|
|
47
53
|
import { isReferenceSchemaType } from "@sanity/types";
|
|
48
54
|
|
|
55
|
+
import { EmptyIcon } from "@sanity/icons/Empty";
|
|
56
|
+
|
|
57
|
+
import { WarningOutlineIcon } from "@sanity/icons/WarningOutline";
|
|
58
|
+
|
|
49
59
|
import { WorkflowDiagram } from "@sanity/workflow-diagram";
|
|
50
60
|
|
|
51
61
|
import { useReducedMotion, motion, useSpring, useMotionValueEvent } from "motion/react";
|
|
@@ -89,11 +99,22 @@ function documentRefsOf(instance) {
|
|
|
89
99
|
return [ ...seen.values() ];
|
|
90
100
|
}
|
|
91
101
|
|
|
102
|
+
function rootInstanceOf(instance, byId) {
|
|
103
|
+
const rootRef = instance.ancestors[0];
|
|
104
|
+
return rootRef ? byId.get(toBareId(rootRef.id)) ?? instance : instance;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const TOOL_PANEL_PADDING = 3, TOOL_HEADING_PADDING = 2, PANEL_STEP = 3;
|
|
108
|
+
|
|
92
109
|
function TabStatusRow({children: children}) {
|
|
110
|
+
const firstLineOffset = useSpaceToken(PANEL_STEP) + useSpaceToken(TOOL_HEADING_PADDING);
|
|
93
111
|
/* @__PURE__ */
|
|
94
112
|
return jsx(Box, {
|
|
95
|
-
|
|
96
|
-
|
|
113
|
+
paddingBottom: PANEL_STEP,
|
|
114
|
+
paddingLeft: TOOL_HEADING_PADDING,
|
|
115
|
+
style: {
|
|
116
|
+
paddingTop: firstLineOffset
|
|
117
|
+
},
|
|
97
118
|
children: children
|
|
98
119
|
});
|
|
99
120
|
}
|
|
@@ -344,14 +365,24 @@ function InstanceDetailBody({entry: entry, framed: framed, subject: subject}) {
|
|
|
344
365
|
},
|
|
345
366
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
346
367
|
gap: 5,
|
|
347
|
-
children: [
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsx(InstanceFaultNote, {
|
|
370
|
+
entry: entry,
|
|
371
|
+
scope: {
|
|
372
|
+
kind: "run",
|
|
373
|
+
onOpenActivity: activityName => setOpenActivity({
|
|
374
|
+
stage: instance.currentStage,
|
|
375
|
+
activityName: activityName
|
|
376
|
+
})
|
|
377
|
+
}
|
|
378
|
+
}), subject === "preview" ? /* @__PURE__ */ jsx(SubjectPreview, {
|
|
348
379
|
instance: instance
|
|
349
380
|
}) : null,
|
|
350
381
|
/* @__PURE__ */ jsxs(Stack, {
|
|
351
382
|
gap: 4,
|
|
352
383
|
children: [
|
|
353
384
|
/* @__PURE__ */ jsx(SectionHeading, {
|
|
354
|
-
children: "Stages
|
|
385
|
+
children: "Stages"
|
|
355
386
|
}),
|
|
356
387
|
/* @__PURE__ */ jsx(InstanceSnapshotBody, {
|
|
357
388
|
entry: entry,
|
|
@@ -433,12 +464,140 @@ function byResolvedTitle(titleOf, keyOf) {
|
|
|
433
464
|
};
|
|
434
465
|
}
|
|
435
466
|
|
|
467
|
+
function openActivitiesOf(instance) {
|
|
468
|
+
return (findOpenStageEntry(instance)?.activities ?? []).filter(activity => isOpenActivityStatus(activity.status));
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function overdueTaskCount(instance, now) {
|
|
472
|
+
return openActivitiesOf(instance).filter(activity => dueDatesOf(activity.fields ?? []).some(due => isDueDatePast(due, now))).length;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const NO_SIGNALS = {
|
|
476
|
+
activeCount: 0,
|
|
477
|
+
assignedToMe: 0,
|
|
478
|
+
documentCount: 0,
|
|
479
|
+
documentlessCount: 0,
|
|
480
|
+
initialStageDocumentCount: 0,
|
|
481
|
+
lastTransition: void 0,
|
|
482
|
+
overdueDocumentCount: 0,
|
|
483
|
+
overdueDocumentlessCount: 0,
|
|
484
|
+
stuckCount: 0
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
function noDefinitionSignals() {
|
|
488
|
+
return NO_SIGNALS;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function holdsWorkFor(instance, who) {
|
|
492
|
+
return openActivitiesOf(instance).some(activity => isActivityAssignedTo({
|
|
493
|
+
state: activity.fields ?? [],
|
|
494
|
+
who: who
|
|
495
|
+
}));
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function arrivalOf(instance, byId) {
|
|
499
|
+
const stage = findOpenStageEntry(instance);
|
|
500
|
+
if (stage !== void 0) return {
|
|
501
|
+
at: stage.enteredAt,
|
|
502
|
+
document: documentRefOf(instance, byId),
|
|
503
|
+
stage: stageTitle(definitionSnapshotOf(instance), stage.name)
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function laterArrival(held, next) {
|
|
508
|
+
return next === void 0 ? held : held === void 0 || next.at > held.at ? next : held;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function documentRefOf(instance, byId) {
|
|
512
|
+
return documentRefsOf(rootInstanceOf(instance, byId))[0];
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const NO_DRAFT = {
|
|
516
|
+
...NO_SIGNALS,
|
|
517
|
+
documents: /* @__PURE__ */ new Set,
|
|
518
|
+
initialStageDocuments: /* @__PURE__ */ new Set,
|
|
519
|
+
overdueDocuments: /* @__PURE__ */ new Set
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
function withDocument(held, document2) {
|
|
523
|
+
return document2 === void 0 ? held : new Set(held).add(document2);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function atInitialStage(instance) {
|
|
527
|
+
const snapshot = definitionSnapshotOf(instance);
|
|
528
|
+
return snapshot !== void 0 && instance.currentStage === snapshot.initialStage;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function fold(args) {
|
|
532
|
+
const {byId: byId, held: held, instance: instance, now: now, who: who} = args, stuck = documentStuckCause({
|
|
533
|
+
instance: instance,
|
|
534
|
+
definition: definitionSnapshotOf(instance)
|
|
535
|
+
}), document2 = documentRefOf(instance, byId)?.id, overdue = overdueTaskCount(instance, now) > 0;
|
|
536
|
+
return {
|
|
537
|
+
activeCount: held.activeCount + 1,
|
|
538
|
+
assignedToMe: held.assignedToMe + (who !== void 0 && holdsWorkFor(instance, who) ? 1 : 0),
|
|
539
|
+
documentlessCount: held.documentlessCount + (document2 === void 0 ? 1 : 0),
|
|
540
|
+
documents: withDocument(held.documents, document2),
|
|
541
|
+
initialStageDocuments: atInitialStage(instance) ? withDocument(held.initialStageDocuments, document2) : held.initialStageDocuments,
|
|
542
|
+
lastTransition: laterArrival(held.lastTransition, arrivalOf(instance, byId)),
|
|
543
|
+
overdueDocumentlessCount: held.overdueDocumentlessCount + (overdue && document2 === void 0 ? 1 : 0),
|
|
544
|
+
overdueDocuments: overdue ? withDocument(held.overdueDocuments, document2) : held.overdueDocuments,
|
|
545
|
+
stuckCount: held.stuckCount + (stuck === void 0 ? 0 : 1)
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function settle(draft) {
|
|
550
|
+
const {documents: documents, initialStageDocuments: initialStageDocuments, overdueDocuments: overdueDocuments, ...rest} = draft;
|
|
551
|
+
return {
|
|
552
|
+
...rest,
|
|
553
|
+
documentCount: documents.size,
|
|
554
|
+
initialStageDocumentCount: initialStageDocuments.size,
|
|
555
|
+
overdueDocumentCount: overdueDocuments.size
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function definitionSignals(args) {
|
|
560
|
+
const byId = new Map(args.instances.map(instance => [ instance._id, instance ])), drafts = /* @__PURE__ */ new Map;
|
|
561
|
+
for (const instance of args.instances) {
|
|
562
|
+
if (terminalState(instance) !== "in-flight") continue;
|
|
563
|
+
const held = drafts.get(instance.definition) ?? NO_DRAFT;
|
|
564
|
+
drafts.set(instance.definition, fold({
|
|
565
|
+
byId: byId,
|
|
566
|
+
held: held,
|
|
567
|
+
instance: instance,
|
|
568
|
+
now: args.now,
|
|
569
|
+
who: args.identity
|
|
570
|
+
}));
|
|
571
|
+
}
|
|
572
|
+
return new Map([ ...drafts ].map(([name, draft]) => [ name, settle(draft) ]));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function catalogBands(rows) {
|
|
576
|
+
const assigned = rows.filter(row => row.signals.assignedToMe > 0);
|
|
577
|
+
if (assigned.length === 0) return [ {
|
|
578
|
+
rows: rows,
|
|
579
|
+
title: void 0
|
|
580
|
+
} ];
|
|
581
|
+
const rest = rows.filter(row => row.signals.assignedToMe === 0);
|
|
582
|
+
return [ {
|
|
583
|
+
rows: assigned,
|
|
584
|
+
title: "Assigned to you"
|
|
585
|
+
}, {
|
|
586
|
+
rows: rest,
|
|
587
|
+
title: "Other workflows"
|
|
588
|
+
} ].filter(band => band.rows.length > 0);
|
|
589
|
+
}
|
|
590
|
+
|
|
436
591
|
function definitionCatalog(args) {
|
|
437
|
-
const rejected = [ ...args.issues.values() ]
|
|
592
|
+
const rejected = [ ...args.issues.values() ], signals = definitionSignals({
|
|
593
|
+
identity: args.identity,
|
|
594
|
+
instances: args.instances,
|
|
595
|
+
now: args.now
|
|
596
|
+
});
|
|
438
597
|
return args.definitions.map(definition => ({
|
|
439
598
|
name: definition.name,
|
|
440
599
|
title: definition.title ?? definition.name,
|
|
441
|
-
|
|
600
|
+
signals: signals.get(definition.name) ?? noDefinitionSignals(),
|
|
442
601
|
docTypes: [ ...new Set(args.mappings.filter(mapping => mapping.definition === definition.name).map(mapping => mapping.docType)) ],
|
|
443
602
|
brokenBindings: rejected.filter(issue => issue.definition === definition.name && issue.version === definition.version).map(issue => ({
|
|
444
603
|
docType: issue.docType,
|
|
@@ -476,7 +635,7 @@ function deployedPhrase(definition) {
|
|
|
476
635
|
return ago === "" ? formatShortDateTime(deployedAt) : `${formatShortDateTime(deployedAt)} (${ago})`;
|
|
477
636
|
}
|
|
478
637
|
|
|
479
|
-
const
|
|
638
|
+
const logged = /* @__PURE__ */ new WeakSet;
|
|
480
639
|
|
|
481
640
|
function logReadFailure(what, error) {
|
|
482
641
|
if (typeof error == "object" && error !== null) {
|
|
@@ -514,17 +673,17 @@ function useCappedInstances(filter) {
|
|
|
514
673
|
}, [ instances, loading, unreadable, error ]);
|
|
515
674
|
}
|
|
516
675
|
|
|
517
|
-
const CATALOG_READ_FAILED = "Couldn’t load the deployed workflows. Try again later.", lastRead = /* @__PURE__ */ new WeakMap, issuedReads = /* @__PURE__ */ new WeakMap;
|
|
676
|
+
const CATALOG_READ_FAILED = "Couldn’t load the deployed workflows. Try again later.", lastRead$1 = /* @__PURE__ */ new WeakMap, issuedReads = /* @__PURE__ */ new WeakMap;
|
|
518
677
|
|
|
519
678
|
function useDeployedDefinitions() {
|
|
520
|
-
const {engine: engine} = useWorkflowContext(), [definitions, setDefinitions] = useState(() => lastRead.get(engine)?.rows), [error, setError] = useState(void 0);
|
|
679
|
+
const {engine: engine} = useWorkflowContext(), [definitions, setDefinitions] = useState(() => lastRead$1.get(engine)?.rows), [error, setError] = useState(void 0);
|
|
521
680
|
return useEffect(() => {
|
|
522
681
|
let cancelled = !1;
|
|
523
|
-
setDefinitions(lastRead.get(engine)?.rows), setError(void 0);
|
|
682
|
+
setDefinitions(lastRead$1.get(engine)?.rows), setError(void 0);
|
|
524
683
|
const seq = (issuedReads.get(engine) ?? 0) + 1;
|
|
525
684
|
return issuedReads.set(engine, seq), (async () => {
|
|
526
|
-
const rows = await readDeployedDefinitions(engine), latest = latestDeployedDefinitions(rows), held = lastRead.get(engine);
|
|
527
|
-
(held === void 0 || seq > held.seq) && lastRead.set(engine, {
|
|
685
|
+
const rows = await readDeployedDefinitions(engine), latest = latestDeployedDefinitions(rows), held = lastRead$1.get(engine);
|
|
686
|
+
(held === void 0 || seq > held.seq) && lastRead$1.set(engine, {
|
|
528
687
|
seq: seq,
|
|
529
688
|
rows: latest
|
|
530
689
|
}), cancelled || (setDefinitions(latest), setError(void 0));
|
|
@@ -539,13 +698,78 @@ function useDeployedDefinitions() {
|
|
|
539
698
|
};
|
|
540
699
|
}
|
|
541
700
|
|
|
701
|
+
const NO_TITLES = {
|
|
702
|
+
titles: /* @__PURE__ */ new Map,
|
|
703
|
+
resolved: /* @__PURE__ */ new Set
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
function useDocPreviewTitles(documents) {
|
|
707
|
+
const previewStore = useDocumentPreviewStore(), schema = useSchema(), {perspectiveStack: perspectiveStack} = usePerspective(), {actualTypes: actualTypes, binding: binding} = useWorkflowContext(), [state, setState] = useState(NO_TITLES), key = documents.map(doc => doc.id).join("|");
|
|
708
|
+
return useEffect(() => {
|
|
709
|
+
const titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set, previews = /* @__PURE__ */ new Map, publish = () => setState({
|
|
710
|
+
titles: new Map(titles),
|
|
711
|
+
resolved: new Set(resolved)
|
|
712
|
+
}), localDocs = documents.flatMap(doc => {
|
|
713
|
+
const {parsed: parsed, local: local} = gdrLocality(doc.id, binding.contentResource);
|
|
714
|
+
return !parsed || !local ? (resolved.add(doc.id), []) : [ {
|
|
715
|
+
doc: doc,
|
|
716
|
+
bareId: parsed.documentId
|
|
717
|
+
} ];
|
|
718
|
+
}), untracks = localDocs.map(({bareId: bareId}) => actualTypes.track(bareId)), dropPreview = docId => {
|
|
719
|
+
previews.get(docId)?.unsubscribe(), previews.delete(docId), titles.delete(docId);
|
|
720
|
+
}, observe = ({docId: docId, bareId: bareId, typeName: typeName}) => {
|
|
721
|
+
const schemaType = openableSchemaType(schema, typeName);
|
|
722
|
+
if (!schemaType) return !1;
|
|
723
|
+
if (previews.get(docId)?.typeName === typeName) return !0;
|
|
724
|
+
dropPreview(docId), resolved.delete(docId);
|
|
725
|
+
const subscription = previewStore.observeForPreview({
|
|
726
|
+
_id: bareId,
|
|
727
|
+
_type: schemaType.name
|
|
728
|
+
}, schemaType, {
|
|
729
|
+
perspective: perspectiveStack
|
|
730
|
+
}).subscribe({
|
|
731
|
+
next: event => {
|
|
732
|
+
resolved.add(docId);
|
|
733
|
+
const title = event.snapshot?.title;
|
|
734
|
+
typeof title == "string" ? titles.set(docId, title) : titles.delete(docId), publish();
|
|
735
|
+
},
|
|
736
|
+
error: err => {
|
|
737
|
+
console.error(`[workflow-studio-plugin] preview for "${docId}" failed:`, err), resolved.add(docId),
|
|
738
|
+
publish();
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
return previews.set(docId, {
|
|
742
|
+
typeName: typeName,
|
|
743
|
+
unsubscribe: () => subscription.unsubscribe()
|
|
744
|
+
}), !0;
|
|
745
|
+
}, evaluate = () => {
|
|
746
|
+
for (const {doc: doc, bareId: bareId} of localDocs) {
|
|
747
|
+
const probe = actualTypes.read(bareId);
|
|
748
|
+
if (probe === null) {
|
|
749
|
+
dropPreview(doc.id), resolved.add(doc.id);
|
|
750
|
+
continue;
|
|
751
|
+
}
|
|
752
|
+
!observe({
|
|
753
|
+
docId: doc.id,
|
|
754
|
+
bareId: bareId,
|
|
755
|
+
typeName: probe ?? doc.type
|
|
756
|
+
}) && typeof probe == "string" && (dropPreview(doc.id), resolved.add(doc.id));
|
|
757
|
+
}
|
|
758
|
+
publish();
|
|
759
|
+
}, unsubscribeProbes = actualTypes.subscribe(evaluate);
|
|
760
|
+
return evaluate(), () => {
|
|
761
|
+
unsubscribeProbes(), untracks.forEach(untrack => untrack()), previews.forEach(preview => preview.unsubscribe());
|
|
762
|
+
};
|
|
763
|
+
}, [ key, previewStore, schema, actualTypes, binding.contentResource.id, perspectiveStack.join("|") ]),
|
|
764
|
+
state;
|
|
765
|
+
}
|
|
766
|
+
|
|
542
767
|
const INSTANCE_CAP_COUNT_NOTE = `Counts from the latest ${INSTANCE_CAP} workflows — older ones aren’t counted.`, NEWEST_INSTANCES = {
|
|
543
768
|
includeCompleted: !0
|
|
544
|
-
};
|
|
769
|
+
}, lastRead = /* @__PURE__ */ new WeakMap;
|
|
545
770
|
|
|
546
771
|
function useToolInstances() {
|
|
547
|
-
const {rows: rows, truncated: truncated, loading: loading, unreadable: unreadable, error: error} = useCappedInstances(NEWEST_INSTANCES)
|
|
548
|
-
return useMemo(() => ({
|
|
772
|
+
const {engine: engine} = useWorkflowContext(), {rows: rows, truncated: truncated, loading: loading, unreadable: unreadable, error: error} = useCappedInstances(NEWEST_INSTANCES), fresh = useMemo(() => ({
|
|
549
773
|
inFlight: rows.filter(instance => terminalState(instance) === "in-flight"),
|
|
550
774
|
settled: rows.filter(instance => terminalState(instance) !== "in-flight"),
|
|
551
775
|
truncated: truncated,
|
|
@@ -553,41 +777,118 @@ function useToolInstances() {
|
|
|
553
777
|
unreadable: unreadable,
|
|
554
778
|
error: error
|
|
555
779
|
}), [ rows, truncated, loading, unreadable, error ]);
|
|
780
|
+
return useEffect(() => {
|
|
781
|
+
!fresh.loading && fresh.error === void 0 && lastRead.set(engine, fresh);
|
|
782
|
+
}, [ engine, fresh ]), loading ? lastRead.get(engine) ?? fresh : fresh;
|
|
556
783
|
}
|
|
557
784
|
|
|
558
|
-
function
|
|
559
|
-
return
|
|
785
|
+
function documentPhrase(count) {
|
|
786
|
+
return count === 0 ? "No documents" : pluralize("document", count, !0);
|
|
560
787
|
}
|
|
561
788
|
|
|
562
|
-
function
|
|
563
|
-
|
|
789
|
+
function documentlessTail(count) {
|
|
790
|
+
return count === 0 ? "" : ` (${pluralize("instance", count, !0)})`;
|
|
564
791
|
}
|
|
565
792
|
|
|
566
|
-
|
|
793
|
+
function documentlessNote(work) {
|
|
794
|
+
return work.documentCount > 0 ? "" : documentlessTail(work.documentlessCount);
|
|
795
|
+
}
|
|
567
796
|
|
|
568
|
-
function
|
|
569
|
-
const
|
|
797
|
+
function documentFace(work, atStart) {
|
|
798
|
+
const lead = `${documentPhrase(work.documentCount)} with an active workflow${documentlessNote(work)}`;
|
|
799
|
+
return atStart === 0 ? {
|
|
800
|
+
lead: lead,
|
|
801
|
+
startLine: void 0
|
|
802
|
+
} : atStart === work.documentCount ? {
|
|
803
|
+
lead: `${lead}, yet to leave the starting stage`,
|
|
804
|
+
startLine: void 0
|
|
805
|
+
} : {
|
|
806
|
+
lead: lead,
|
|
807
|
+
startLine: `${atStart} still at the starting stage`
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
function overdueHint(work) {
|
|
812
|
+
return `${documentPhrase(work.documentCount)} with overdue tasks${documentlessTail(work.documentlessCount)}`;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const UNTITLED_DOCUMENT = "Untitled", TRANSITION_HINT_PENDING = "Loading…";
|
|
816
|
+
|
|
817
|
+
function transitionHeading(at) {
|
|
818
|
+
return `Last stage change at ${formatShortDateTime(at)}`;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function transitionFace(args) {
|
|
822
|
+
return args.documentPending ? {
|
|
823
|
+
state: "pending"
|
|
824
|
+
} : {
|
|
825
|
+
state: "ready",
|
|
826
|
+
document: args.documentTitle,
|
|
827
|
+
heading: transitionHeading(args.at),
|
|
828
|
+
lead: args.documentTitle === void 0 ? "Changed to" : "changed to",
|
|
829
|
+
stage: args.stage
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function catalogView(args) {
|
|
834
|
+
if (args.error !== void 0) return {
|
|
835
|
+
kind: "unreadable"
|
|
836
|
+
};
|
|
837
|
+
if (args.definitions === void 0 || args.instances.loading || args.identity.kind === "pending") return {
|
|
838
|
+
kind: "loading"
|
|
839
|
+
};
|
|
840
|
+
if (args.definitions.length === 0) return {
|
|
841
|
+
kind: "empty"
|
|
842
|
+
};
|
|
843
|
+
const rows = definitionCatalog({
|
|
844
|
+
definitions: args.definitions,
|
|
845
|
+
identity: identityOf(args.identity),
|
|
846
|
+
instances: [ ...args.instances.inFlight, ...args.instances.settled ],
|
|
847
|
+
issues: args.issues,
|
|
848
|
+
mappings: args.mappings,
|
|
849
|
+
now: args.now
|
|
850
|
+
});
|
|
851
|
+
return {
|
|
852
|
+
kind: "bands",
|
|
853
|
+
bands: catalogBands(rows)
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function definitionAlert(row) {
|
|
858
|
+
if (row.signals.stuckCount !== 0) return {
|
|
859
|
+
hint: `${pluralize("run", row.signals.stuckCount, !0)} here can’t continue without help`
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
const CARD_MIN_WIDTH = 280, CARD_RADIUS$1 = 3, CARD_PADDING = 4, HINT_DOCUMENT_MAX_WIDTH = 200, BAND_GAP = 6, CARD_MIN_HEIGHT = 120;
|
|
864
|
+
|
|
865
|
+
function OverviewTab({identity: identity, onOpenWorkflow: onOpenWorkflow}) {
|
|
866
|
+
const {definitions: definitions, error: error} = useDeployedDefinitions(), {mappingIssues: mappingIssues, mappings: mappings} = useWorkflowContext(), schema = useSchema(), instances = useToolInstances(), now = useMinuteClock(), view = catalogView({
|
|
867
|
+
definitions: definitions,
|
|
868
|
+
error: error,
|
|
869
|
+
identity: identity,
|
|
870
|
+
instances: instances,
|
|
871
|
+
issues: mappingIssues,
|
|
872
|
+
mappings: mappings,
|
|
873
|
+
now: now
|
|
874
|
+
}), undeployed = /* @__PURE__ */ jsx(UndeployedWorkflows, {
|
|
570
875
|
notices: undeployedWorkflowNotices({
|
|
571
876
|
issues: mappingIssues,
|
|
572
877
|
titleOf: name => schema.get(name)?.title
|
|
573
878
|
})
|
|
574
879
|
});
|
|
575
|
-
|
|
880
|
+
return view.kind === "unreadable" ? /* @__PURE__ */ jsx(NoteBanner, {
|
|
576
881
|
label: CATALOG_READ_FAILED,
|
|
577
882
|
tone: "critical"
|
|
578
|
-
})
|
|
579
|
-
if (definitions === void 0) /* @__PURE__ */
|
|
580
|
-
return jsx(TabStatusRow, {
|
|
883
|
+
}) : view.kind === "loading" ? /* @__PURE__ */ jsx(TabStatusRow, {
|
|
581
884
|
children: /* @__PURE__ */ jsx(LoadingRow, {
|
|
582
885
|
label: "Loading workflows…"
|
|
583
886
|
})
|
|
584
|
-
})
|
|
585
|
-
if (definitions.length === 0) /* @__PURE__ */
|
|
586
|
-
return jsxs(Flex, {
|
|
887
|
+
}) : view.kind === "empty" ? /* @__PURE__ */ jsxs(Flex, {
|
|
587
888
|
direction: "column",
|
|
588
889
|
flex: 1,
|
|
589
890
|
gap: 3,
|
|
590
|
-
paddingBottom:
|
|
891
|
+
paddingBottom: 3,
|
|
591
892
|
paddingTop: 3,
|
|
592
893
|
children: [ undeployed,
|
|
593
894
|
/* @__PURE__ */ jsx(EmptyState, {
|
|
@@ -595,19 +896,7 @@ function OverviewTab({onOpenWorkflow: onOpenWorkflow}) {
|
|
|
595
896
|
icon: /* @__PURE__ */ jsx(TransferIcon, {}),
|
|
596
897
|
title: "No workflows deployed"
|
|
597
898
|
}) ]
|
|
598
|
-
})
|
|
599
|
-
const rows = definitionCatalog({
|
|
600
|
-
definitions: definitions,
|
|
601
|
-
mappings: mappings,
|
|
602
|
-
inFlight: instances.inFlight,
|
|
603
|
-
issues: mappingIssues
|
|
604
|
-
}), active = rows.reduce((sum, row) => sum + row.activeCount, 0), activity = activeHeadline({
|
|
605
|
-
active: active,
|
|
606
|
-
error: instances.error,
|
|
607
|
-
loading: instances.loading
|
|
608
|
-
});
|
|
609
|
-
/* @__PURE__ */
|
|
610
|
-
return jsxs(Stack, {
|
|
899
|
+
}) : /* @__PURE__ */ jsxs(Stack, {
|
|
611
900
|
gap: 3,
|
|
612
901
|
paddingBottom: 4,
|
|
613
902
|
paddingTop: 3,
|
|
@@ -615,39 +904,48 @@ function OverviewTab({onOpenWorkflow: onOpenWorkflow}) {
|
|
|
615
904
|
label: INSTANCES_READ_FAILED,
|
|
616
905
|
tone: "critical"
|
|
617
906
|
}),
|
|
618
|
-
/* @__PURE__ */
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
gridAutoRows: `minmax(${CARD_MIN_HEIGHT}px, auto)`,
|
|
637
|
-
gridTemplateColumns: `repeat(auto-fill, minmax(${CARD_MIN_WIDTH}px, 1fr))`
|
|
638
|
-
},
|
|
639
|
-
children: rows.map(row => /* @__PURE__ */ jsx(WorkflowCard, {
|
|
640
|
-
countKnown: instances.error === void 0 && !instances.loading,
|
|
641
|
-
onOpen: () => onOpenWorkflow(row.name),
|
|
642
|
-
row: row
|
|
643
|
-
}, row.name))
|
|
907
|
+
/* @__PURE__ */ jsx(Stack, {
|
|
908
|
+
gap: BAND_GAP,
|
|
909
|
+
children: view.bands.map(band => /* @__PURE__ */ jsxs(Stack, {
|
|
910
|
+
gap: 3,
|
|
911
|
+
children: [ band.title === void 0 ? null : /* @__PURE__ */ jsx(Box, {
|
|
912
|
+
padding: TOOL_HEADING_PADDING,
|
|
913
|
+
children: /* @__PURE__ */ jsx(CountedHeading, {
|
|
914
|
+
count: band.rows.length,
|
|
915
|
+
title: band.title
|
|
916
|
+
})
|
|
917
|
+
}),
|
|
918
|
+
/* @__PURE__ */ jsx(CardGrid, {
|
|
919
|
+
countKnown: instances.error === void 0,
|
|
920
|
+
now: now,
|
|
921
|
+
onOpenWorkflow: onOpenWorkflow,
|
|
922
|
+
rows: band.rows
|
|
923
|
+
}) ]
|
|
924
|
+
}, band.title ?? UNBANDED_KEY))
|
|
644
925
|
}), instances.truncated ? /* @__PURE__ */ jsx(MutedNote, {
|
|
645
926
|
text: INSTANCE_CAP_COUNT_NOTE
|
|
646
927
|
}) : null ]
|
|
647
928
|
});
|
|
648
929
|
}
|
|
649
930
|
|
|
650
|
-
const
|
|
931
|
+
const UNBANDED_KEY = "all";
|
|
932
|
+
|
|
933
|
+
function CardGrid({countKnown: countKnown, now: now, onOpenWorkflow: onOpenWorkflow, rows: rows}) {
|
|
934
|
+
/* @__PURE__ */
|
|
935
|
+
return jsx(Grid, {
|
|
936
|
+
gap: 3,
|
|
937
|
+
style: {
|
|
938
|
+
gridAutoRows: `minmax(${CARD_MIN_HEIGHT}px, auto)`,
|
|
939
|
+
gridTemplateColumns: `repeat(auto-fill, minmax(${CARD_MIN_WIDTH}px, 1fr))`
|
|
940
|
+
},
|
|
941
|
+
children: rows.map(row => /* @__PURE__ */ jsx(WorkflowCard, {
|
|
942
|
+
countKnown: countKnown,
|
|
943
|
+
now: now,
|
|
944
|
+
onOpen: () => onOpenWorkflow(row.name),
|
|
945
|
+
row: row
|
|
946
|
+
}, row.name))
|
|
947
|
+
});
|
|
948
|
+
}
|
|
651
949
|
|
|
652
950
|
function UndeployedWorkflows({notices: notices}) {
|
|
653
951
|
return notices.length === 0 ? null :
|
|
@@ -660,8 +958,104 @@ function UndeployedWorkflows({notices: notices}) {
|
|
|
660
958
|
});
|
|
661
959
|
}
|
|
662
960
|
|
|
663
|
-
function
|
|
664
|
-
const
|
|
961
|
+
function LastTransitionHint({transition: transition}) {
|
|
962
|
+
const documents = useMemo(() => transition.document === void 0 ? [] : [ transition.document ], [ transition.document ]), {resolved: resolved, titles: titles} = useDocPreviewTitles(documents), id = transition.document?.id, face = transitionFace({
|
|
963
|
+
at: transition.at,
|
|
964
|
+
documentPending: id !== void 0 && !resolved.has(id),
|
|
965
|
+
documentTitle: id === void 0 ? void 0 : titles.get(id) ?? UNTITLED_DOCUMENT,
|
|
966
|
+
stage: transition.stage
|
|
967
|
+
});
|
|
968
|
+
return face.state === "pending" ? /* @__PURE__ */ jsx(Text, {
|
|
969
|
+
muted: !0,
|
|
970
|
+
size: 1,
|
|
971
|
+
children: TRANSITION_HINT_PENDING
|
|
972
|
+
}) :
|
|
973
|
+
/* @__PURE__ */ jsxs(Stack, {
|
|
974
|
+
gap: 3,
|
|
975
|
+
children: [
|
|
976
|
+
/* @__PURE__ */ jsx(Text, {
|
|
977
|
+
muted: !0,
|
|
978
|
+
size: 1,
|
|
979
|
+
children: face.heading
|
|
980
|
+
}),
|
|
981
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
982
|
+
size: 1,
|
|
983
|
+
textOverflow: "ellipsis",
|
|
984
|
+
children: [ face.document === void 0 ? null : /* @__PURE__ */ jsx(HintDocument, {
|
|
985
|
+
children: face.document
|
|
986
|
+
}), face.document === void 0 ? "" : " ", face.lead, " ",
|
|
987
|
+
/* @__PURE__ */ jsx(InlineEmphasis, {
|
|
988
|
+
children: face.stage
|
|
989
|
+
}) ]
|
|
990
|
+
}) ]
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
function HintDocument({children: children}) {
|
|
995
|
+
/* @__PURE__ */
|
|
996
|
+
return jsx("span", {
|
|
997
|
+
style: {
|
|
998
|
+
display: "inline-block",
|
|
999
|
+
maxWidth: HINT_DOCUMENT_MAX_WIDTH,
|
|
1000
|
+
overflow: "hidden",
|
|
1001
|
+
textOverflow: "ellipsis",
|
|
1002
|
+
verticalAlign: "bottom",
|
|
1003
|
+
whiteSpace: "nowrap"
|
|
1004
|
+
},
|
|
1005
|
+
children: /* @__PURE__ */ jsx(InlineEmphasis, {
|
|
1006
|
+
children: children
|
|
1007
|
+
})
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
function overdueWork(signals) {
|
|
1012
|
+
return {
|
|
1013
|
+
documentCount: signals.overdueDocumentCount,
|
|
1014
|
+
documentlessCount: signals.overdueDocumentlessCount
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
function CardMetrics$1({now: now, signals: signals}) {
|
|
1019
|
+
const overdue = overdueWork(signals), overdueTotal = overdue.documentCount + overdue.documentlessCount, documents = documentFace(signals, signals.initialStageDocumentCount);
|
|
1020
|
+
/* @__PURE__ */
|
|
1021
|
+
return jsxs(Flex, {
|
|
1022
|
+
align: "center",
|
|
1023
|
+
gap: 3,
|
|
1024
|
+
children: [
|
|
1025
|
+
/* @__PURE__ */ jsx(MetricPair, {
|
|
1026
|
+
Icon: DocumentIcon,
|
|
1027
|
+
empty: signals.documentCount === 0 && signals.documentlessCount === 0,
|
|
1028
|
+
face: {
|
|
1029
|
+
text: documents.lead,
|
|
1030
|
+
...documents.startLine === void 0 ? {} : {
|
|
1031
|
+
description: documents.startLine
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
value: String(signals.documentCount)
|
|
1035
|
+
}), signals.lastTransition === void 0 ? null : /* @__PURE__ */ jsx(MetricPair, {
|
|
1036
|
+
Icon: ClockIcon,
|
|
1037
|
+
face: {
|
|
1038
|
+
content: /* @__PURE__ */ jsx(LastTransitionHint, {
|
|
1039
|
+
transition: signals.lastTransition
|
|
1040
|
+
}),
|
|
1041
|
+
wide: !0
|
|
1042
|
+
},
|
|
1043
|
+
value: formatShortAgo(signals.lastTransition.at, now)
|
|
1044
|
+
}), overdueTotal === 0 ? null : /* @__PURE__ */ jsx(MetricPair, {
|
|
1045
|
+
Icon: CalendarIcon,
|
|
1046
|
+
face: {
|
|
1047
|
+
text: overdueHint(overdue)
|
|
1048
|
+
},
|
|
1049
|
+
tone: "caution",
|
|
1050
|
+
value: String(overdueTotal)
|
|
1051
|
+
}) ]
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
function WorkflowCard({countKnown: countKnown, now: now, onOpen: onOpen, row: row}) {
|
|
1056
|
+
const alert = definitionAlert(row);
|
|
1057
|
+
/* @__PURE__ */
|
|
1058
|
+
return jsxs(Card, {
|
|
665
1059
|
as: "button",
|
|
666
1060
|
onClick: onOpen,
|
|
667
1061
|
padding: CARD_PADDING,
|
|
@@ -674,50 +1068,44 @@ function WorkflowCard({countKnown: countKnown, onOpen: onOpen, row: row}) {
|
|
|
674
1068
|
textAlign: "left",
|
|
675
1069
|
width: "100%"
|
|
676
1070
|
},
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
} : {},
|
|
680
|
-
children: /* @__PURE__ */ jsxs(Flex, {
|
|
1071
|
+
children: [
|
|
1072
|
+
/* @__PURE__ */ jsxs(Flex, {
|
|
681
1073
|
align: "flex-start",
|
|
682
|
-
gap:
|
|
683
|
-
|
|
684
|
-
size: 1,
|
|
685
|
-
children: /* @__PURE__ */ jsx(WarningOutlineIcon, {})
|
|
686
|
-
}) : null,
|
|
687
|
-
/* @__PURE__ */ jsxs(Stack, {
|
|
1074
|
+
gap: 2,
|
|
1075
|
+
style: {
|
|
688
1076
|
flex: 1,
|
|
689
|
-
|
|
1077
|
+
minWidth: 0
|
|
1078
|
+
},
|
|
1079
|
+
children: [
|
|
1080
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1081
|
+
size: 1,
|
|
690
1082
|
style: {
|
|
1083
|
+
flex: 1,
|
|
691
1084
|
minWidth: 0
|
|
692
1085
|
},
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
muted: !0,
|
|
700
|
-
size: 1,
|
|
701
|
-
children: activeSummary(row.activeCount)
|
|
702
|
-
}) : null ]
|
|
1086
|
+
weight: "medium",
|
|
1087
|
+
children: row.title
|
|
1088
|
+
}), alert === void 0 ? null : /* @__PURE__ */ jsx(AlertGlyph, {
|
|
1089
|
+
Icon: ErrorOutlineIcon,
|
|
1090
|
+
hint: alert.hint,
|
|
1091
|
+
tone: "critical"
|
|
703
1092
|
}) ]
|
|
704
|
-
})
|
|
1093
|
+
}), countKnown ? /* @__PURE__ */ jsx(CardMetrics$1, {
|
|
1094
|
+
now: now,
|
|
1095
|
+
signals: row.signals
|
|
1096
|
+
}) : null ]
|
|
705
1097
|
});
|
|
706
|
-
return flagged ? /* @__PURE__ */ jsx(HoverHint, {
|
|
707
|
-
fill: !0,
|
|
708
|
-
text: CARD_ISSUES_HINT,
|
|
709
|
-
children: card
|
|
710
|
-
}) : card;
|
|
711
1098
|
}
|
|
712
1099
|
|
|
713
1100
|
function useStartableDefinitions() {
|
|
714
|
-
const {definitions: definitions, error: error} = useDeployedDefinitions()
|
|
1101
|
+
const {definitions: definitions, error: error} = useDeployedDefinitions(), startable = useMemo(() => definitions?.filter(row => isStartableDefinition(row)).map(row => ({
|
|
1102
|
+
name: row.name,
|
|
1103
|
+
title: row.title ?? row.name,
|
|
1104
|
+
description: row.description
|
|
1105
|
+
})), [ definitions ]);
|
|
715
1106
|
return {
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
title: row.title ?? row.name,
|
|
719
|
-
description: row.description
|
|
720
|
-
})), [ definitions ]),
|
|
1107
|
+
catalogEmpty: definitions?.length === 0,
|
|
1108
|
+
definitions: startable,
|
|
721
1109
|
error: error
|
|
722
1110
|
};
|
|
723
1111
|
}
|
|
@@ -749,16 +1137,45 @@ function NewWorkflowButton() {
|
|
|
749
1137
|
});
|
|
750
1138
|
}
|
|
751
1139
|
|
|
1140
|
+
const PANEL_WIDTH = 340;
|
|
1141
|
+
|
|
1142
|
+
function NothingToStart({catalogEmpty: catalogEmpty}) {
|
|
1143
|
+
/* @__PURE__ */
|
|
1144
|
+
return jsx(Box, {
|
|
1145
|
+
padding: 4,
|
|
1146
|
+
style: {
|
|
1147
|
+
width: PANEL_WIDTH
|
|
1148
|
+
},
|
|
1149
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
1150
|
+
gap: 3,
|
|
1151
|
+
children: [
|
|
1152
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1153
|
+
align: "center",
|
|
1154
|
+
size: 1,
|
|
1155
|
+
weight: "medium",
|
|
1156
|
+
children: catalogEmpty ? "No workflows deployed" : "Nothing to start by hand"
|
|
1157
|
+
}),
|
|
1158
|
+
/* @__PURE__ */ jsx(Text, {
|
|
1159
|
+
align: "center",
|
|
1160
|
+
muted: !0,
|
|
1161
|
+
size: 1,
|
|
1162
|
+
children: catalogEmpty ? "Deploy a workflow to this project to start one from here" : "Every deployed workflow here is started by a parent workflow, never by hand"
|
|
1163
|
+
}) ]
|
|
1164
|
+
})
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
|
|
752
1168
|
function DefinitionPickerPanel({onPick: onPick}) {
|
|
753
|
-
const {definitions: definitions, error: error} = useStartableDefinitions(), [query, setQuery] = useState(""), visible = useMemo(() => {
|
|
1169
|
+
const {catalogEmpty: catalogEmpty, definitions: definitions, error: error} = useStartableDefinitions(), [query, setQuery] = useState(""), visible = useMemo(() => {
|
|
754
1170
|
const q = query.trim().toLowerCase();
|
|
755
1171
|
return definitions ? q ? definitions.filter(d => `${d.title} ${d.name}`.toLowerCase().includes(q)) : definitions : [];
|
|
756
1172
|
}, [ definitions, query ]), settled = error === void 0 ? definitions : void 0;
|
|
757
|
-
/* @__PURE__ */
|
|
758
|
-
|
|
1173
|
+
return settled?.length === 0 ? /* @__PURE__ */ jsx(NothingToStart, {
|
|
1174
|
+
catalogEmpty: catalogEmpty
|
|
1175
|
+
}) : /* @__PURE__ */ jsx(Box, {
|
|
759
1176
|
padding: 2,
|
|
760
1177
|
style: {
|
|
761
|
-
width:
|
|
1178
|
+
width: PANEL_WIDTH
|
|
762
1179
|
},
|
|
763
1180
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
764
1181
|
gap: 2,
|
|
@@ -775,8 +1192,6 @@ function DefinitionPickerPanel({onPick: onPick}) {
|
|
|
775
1192
|
tone: "critical"
|
|
776
1193
|
}) : null, !definitions && !error ? /* @__PURE__ */ jsx(LoadingRow, {
|
|
777
1194
|
label: "Loading workflows…"
|
|
778
|
-
}) : null, settled?.length === 0 ? /* @__PURE__ */ jsx(MutedNote, {
|
|
779
|
-
text: "No startable workflows are deployed"
|
|
780
1195
|
}) : null, settled !== void 0 && settled.length > 0 && visible.length === 0 ? /* @__PURE__ */ jsx(MutedNote, {
|
|
781
1196
|
text: "No workflows match"
|
|
782
1197
|
}) : null,
|
|
@@ -1055,13 +1470,20 @@ function useBandOpen(bands, key) {
|
|
|
1055
1470
|
};
|
|
1056
1471
|
}
|
|
1057
1472
|
|
|
1058
|
-
const
|
|
1473
|
+
const REVEAL_STALL_MS = 2e3, REVEAL_COLD_MS = 15e3;
|
|
1059
1474
|
|
|
1060
1475
|
function useRevealGate(args) {
|
|
1061
|
-
const {loading: loading, ready: ready} = args, settled = !loading && ready,
|
|
1476
|
+
const {loading: loading, progress: progress, ready: ready} = args, settled = !loading && ready, [stalled, setStalled] = useState(!1);
|
|
1477
|
+
useEffect(() => {
|
|
1478
|
+
if (loading || ready) return;
|
|
1479
|
+
setStalled(!1);
|
|
1480
|
+
const budget = progress > 0 ? REVEAL_STALL_MS : REVEAL_COLD_MS, timer = setTimeout(() => setStalled(!0), budget);
|
|
1481
|
+
return () => clearTimeout(timer);
|
|
1482
|
+
}, [ loading, progress, ready ]);
|
|
1483
|
+
const [revealed, setRevealed] = useState(!1);
|
|
1062
1484
|
return useEffect(() => {
|
|
1063
|
-
!revealed && (settled ||
|
|
1064
|
-
}, [
|
|
1485
|
+
!revealed && (settled || stalled) && setRevealed(!0);
|
|
1486
|
+
}, [ revealed, settled, stalled ]), revealed || settled || stalled;
|
|
1065
1487
|
}
|
|
1066
1488
|
|
|
1067
1489
|
function spawnOrigins(instances) {
|
|
@@ -1074,11 +1496,6 @@ function spawnOrigins(instances) {
|
|
|
1074
1496
|
return origins;
|
|
1075
1497
|
}
|
|
1076
1498
|
|
|
1077
|
-
function rootOf(instance, byId) {
|
|
1078
|
-
const rootRef = instance.ancestors[0];
|
|
1079
|
-
return rootRef ? byId.get(toBareId(rootRef.id)) ?? instance : instance;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
1499
|
function taskRowsOf(args) {
|
|
1083
1500
|
const {instance: instance, identity: identity} = args, open = findOpenStageEntry(instance);
|
|
1084
1501
|
if (!open) return [];
|
|
@@ -1138,7 +1555,7 @@ function deriveTaskGroups(args) {
|
|
|
1138
1555
|
activityName: origin.activityName
|
|
1139
1556
|
}).title : void 0,
|
|
1140
1557
|
rows: rows
|
|
1141
|
-
}, root =
|
|
1558
|
+
}, root = rootInstanceOf(instance, byId), documents = documentRefsOf(root), document2 = documents[0];
|
|
1142
1559
|
if (!document2) {
|
|
1143
1560
|
withoutDocuments.push(entry);
|
|
1144
1561
|
continue;
|
|
@@ -1444,72 +1861,6 @@ function SettleOrphansDialog({workflows: workflows, onClose: onClose}) {
|
|
|
1444
1861
|
});
|
|
1445
1862
|
}
|
|
1446
1863
|
|
|
1447
|
-
const NO_TITLES = {
|
|
1448
|
-
titles: /* @__PURE__ */ new Map,
|
|
1449
|
-
resolved: /* @__PURE__ */ new Set
|
|
1450
|
-
};
|
|
1451
|
-
|
|
1452
|
-
function useDocPreviewTitles(documents) {
|
|
1453
|
-
const previewStore = useDocumentPreviewStore(), schema = useSchema(), {perspectiveStack: perspectiveStack} = usePerspective(), {actualTypes: actualTypes, binding: binding} = useWorkflowContext(), [state, setState] = useState(NO_TITLES), key = documents.map(doc => doc.id).join("|");
|
|
1454
|
-
return useEffect(() => {
|
|
1455
|
-
const titles = /* @__PURE__ */ new Map, resolved = /* @__PURE__ */ new Set, previews = /* @__PURE__ */ new Map, publish = () => setState({
|
|
1456
|
-
titles: new Map(titles),
|
|
1457
|
-
resolved: new Set(resolved)
|
|
1458
|
-
}), localDocs = documents.flatMap(doc => {
|
|
1459
|
-
const {parsed: parsed, local: local} = gdrLocality(doc.id, binding.contentResource);
|
|
1460
|
-
return !parsed || !local ? (resolved.add(doc.id), []) : [ {
|
|
1461
|
-
doc: doc,
|
|
1462
|
-
bareId: parsed.documentId
|
|
1463
|
-
} ];
|
|
1464
|
-
}), untracks = localDocs.map(({bareId: bareId}) => actualTypes.track(bareId)), dropPreview = docId => {
|
|
1465
|
-
previews.get(docId)?.unsubscribe(), previews.delete(docId), titles.delete(docId);
|
|
1466
|
-
}, observe = ({docId: docId, bareId: bareId, typeName: typeName}) => {
|
|
1467
|
-
const schemaType = openableSchemaType(schema, typeName);
|
|
1468
|
-
if (!schemaType) return !1;
|
|
1469
|
-
if (previews.get(docId)?.typeName === typeName) return !0;
|
|
1470
|
-
dropPreview(docId), resolved.delete(docId);
|
|
1471
|
-
const subscription = previewStore.observeForPreview({
|
|
1472
|
-
_id: bareId,
|
|
1473
|
-
_type: schemaType.name
|
|
1474
|
-
}, schemaType, {
|
|
1475
|
-
perspective: perspectiveStack
|
|
1476
|
-
}).subscribe({
|
|
1477
|
-
next: event => {
|
|
1478
|
-
resolved.add(docId);
|
|
1479
|
-
const title = event.snapshot?.title;
|
|
1480
|
-
typeof title == "string" ? titles.set(docId, title) : titles.delete(docId), publish();
|
|
1481
|
-
},
|
|
1482
|
-
error: err => {
|
|
1483
|
-
console.error(`[workflow-studio-plugin] preview for "${docId}" failed:`, err), resolved.add(docId),
|
|
1484
|
-
publish();
|
|
1485
|
-
}
|
|
1486
|
-
});
|
|
1487
|
-
return previews.set(docId, {
|
|
1488
|
-
typeName: typeName,
|
|
1489
|
-
unsubscribe: () => subscription.unsubscribe()
|
|
1490
|
-
}), !0;
|
|
1491
|
-
}, evaluate = () => {
|
|
1492
|
-
for (const {doc: doc, bareId: bareId} of localDocs) {
|
|
1493
|
-
const probe = actualTypes.read(bareId);
|
|
1494
|
-
if (probe === null) {
|
|
1495
|
-
dropPreview(doc.id), resolved.add(doc.id);
|
|
1496
|
-
continue;
|
|
1497
|
-
}
|
|
1498
|
-
!observe({
|
|
1499
|
-
docId: doc.id,
|
|
1500
|
-
bareId: bareId,
|
|
1501
|
-
typeName: probe ?? doc.type
|
|
1502
|
-
}) && typeof probe == "string" && (dropPreview(doc.id), resolved.add(doc.id));
|
|
1503
|
-
}
|
|
1504
|
-
publish();
|
|
1505
|
-
}, unsubscribeProbes = actualTypes.subscribe(evaluate);
|
|
1506
|
-
return evaluate(), () => {
|
|
1507
|
-
unsubscribeProbes(), untracks.forEach(untrack => untrack()), previews.forEach(preview => preview.unsubscribe());
|
|
1508
|
-
};
|
|
1509
|
-
}, [ key, previewStore, schema, actualTypes, binding.contentResource.id, perspectiveStack.join("|") ]),
|
|
1510
|
-
state;
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
1864
|
function taskFilterOptions(groups) {
|
|
1514
1865
|
const workflows = /* @__PURE__ */ new Map, documents = /* @__PURE__ */ new Map;
|
|
1515
1866
|
for (const group of groups.withDocuments) {
|
|
@@ -2687,6 +3038,7 @@ function TasksTab({error: error, filterSlot: filterSlot, instances: instances, l
|
|
|
2687
3038
|
identity: identity
|
|
2688
3039
|
}), [ instances, identity ]), orphans = useOrphanedWorkflows(groups), listed = useMemo(() => hideOrphanedGroups(groups, orphans.groupKeys), [ groups, orphans.groupKeys ]), options = useMemo(() => taskFilterOptions(listed), [ listed ]), titles = useGroupTitles(listed), revealed = useRevealGate({
|
|
2689
3040
|
loading: loading,
|
|
3041
|
+
progress: titles.resolved.size,
|
|
2690
3042
|
ready: titles.ready
|
|
2691
3043
|
}), visible = useMemo(() => {
|
|
2692
3044
|
const filtered = applyTaskFilters({
|
|
@@ -2746,6 +3098,30 @@ function TasksTab({error: error, filterSlot: filterSlot, instances: instances, l
|
|
|
2746
3098
|
});
|
|
2747
3099
|
}
|
|
2748
3100
|
|
|
3101
|
+
function cardFacts(args) {
|
|
3102
|
+
return new Map(args.instances.map(instance => [ instance._id, {
|
|
3103
|
+
pending: openActivitiesOf(instance).length,
|
|
3104
|
+
overdue: overdueTaskCount(instance, args.now),
|
|
3105
|
+
stuck: documentStuckCause({
|
|
3106
|
+
instance: instance,
|
|
3107
|
+
definition: definitionSnapshotOf(instance)
|
|
3108
|
+
}) !== void 0,
|
|
3109
|
+
settled: terminalState(instance) !== "in-flight"
|
|
3110
|
+
} ]));
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3113
|
+
function laneTotals(cards, facts) {
|
|
3114
|
+
let overdue = 0, stuck = 0;
|
|
3115
|
+
for (const card of cards) {
|
|
3116
|
+
const held = facts.get(card.instanceId);
|
|
3117
|
+
held !== void 0 && (held.overdue > 0 && (overdue += 1), held.stuck && (stuck += 1));
|
|
3118
|
+
}
|
|
3119
|
+
return {
|
|
3120
|
+
overdue: overdue,
|
|
3121
|
+
stuck: stuck
|
|
3122
|
+
};
|
|
3123
|
+
}
|
|
3124
|
+
|
|
2749
3125
|
const BOARD_EMPTY_STAGE_NOTE = "No items";
|
|
2750
3126
|
|
|
2751
3127
|
function faceOf(instance) {
|
|
@@ -2804,6 +3180,24 @@ function boardDocuments(board) {
|
|
|
2804
3180
|
return board.groups.flatMap(group => group.cards.flatMap(card => card.face.kind === "document" ? [ card.face.document ] : []));
|
|
2805
3181
|
}
|
|
2806
3182
|
|
|
3183
|
+
function pendingHint(pending) {
|
|
3184
|
+
return pending === 0 ? "All tasks done" : `${pluralize("task", pending, !0)} still open`;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
function overdueTasksHint(overdue) {
|
|
3188
|
+
return `${pluralize("task", overdue, !0)} past ${overdue === 1 ? "its" : "their"} due date`;
|
|
3189
|
+
}
|
|
3190
|
+
|
|
3191
|
+
const STUCK_RUN_HINT = "This run can’t continue without help";
|
|
3192
|
+
|
|
3193
|
+
function laneOverdueHint(overdue) {
|
|
3194
|
+
return `${overdue} of these ${overdue === 1 ? "has" : "have"} overdue tasks`;
|
|
3195
|
+
}
|
|
3196
|
+
|
|
3197
|
+
function laneStuckHint(stuck) {
|
|
3198
|
+
return `${stuck} of these can’t continue without help`;
|
|
3199
|
+
}
|
|
3200
|
+
|
|
2807
3201
|
function CardTitleFace({title: title}) {
|
|
2808
3202
|
return title.kind === "title" ? /* @__PURE__ */ jsx(Fragment, {
|
|
2809
3203
|
children: title.title
|
|
@@ -2830,23 +3224,10 @@ function cardTitle(args) {
|
|
|
2830
3224
|
};
|
|
2831
3225
|
}
|
|
2832
3226
|
|
|
2833
|
-
function ownOpenTasks(instance) {
|
|
2834
|
-
const open = findOpenStageEntry(instance);
|
|
2835
|
-
return open ? (open.activities ?? []).filter(activity => isOpenActivityStatus(activity.status)).length : 0;
|
|
2836
|
-
}
|
|
2837
|
-
|
|
2838
|
-
function pendingTaskCounts(instances) {
|
|
2839
|
-
return new Map(instances.map(instance => [ instance._id, ownOpenTasks(instance) ]));
|
|
2840
|
-
}
|
|
2841
|
-
|
|
2842
|
-
function pendingTasksPhrase(pending) {
|
|
2843
|
-
if (pending !== void 0) return pending === 0 ? "All tasks done" : pluralize("pending task", pending, !0);
|
|
2844
|
-
}
|
|
2845
|
-
|
|
2846
3227
|
const CARD_RADIUS = 3;
|
|
2847
3228
|
|
|
2848
3229
|
function BoardCard({card: card, wiring: wiring}) {
|
|
2849
|
-
const {
|
|
3230
|
+
const {facts: facts, onSelect: onSelect, selectedInstanceId: selectedInstanceId, titles: titles} = wiring, {color: color} = useTheme_v2(), selected = card.instanceId === selectedInstanceId, held = facts.get(card.instanceId);
|
|
2850
3231
|
/* @__PURE__ */
|
|
2851
3232
|
return jsx(Card, {
|
|
2852
3233
|
"aria-pressed": selected,
|
|
@@ -2864,54 +3245,93 @@ function BoardCard({card: card, wiring: wiring}) {
|
|
|
2864
3245
|
children: /* @__PURE__ */ jsxs(Stack, {
|
|
2865
3246
|
gap: 3,
|
|
2866
3247
|
children: [
|
|
2867
|
-
/* @__PURE__ */
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
children:
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
3248
|
+
/* @__PURE__ */ jsxs(Flex, {
|
|
3249
|
+
align: "flex-start",
|
|
3250
|
+
gap: 2,
|
|
3251
|
+
children: [
|
|
3252
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3253
|
+
size: 1,
|
|
3254
|
+
style: {
|
|
3255
|
+
flex: 1,
|
|
3256
|
+
minWidth: 0
|
|
3257
|
+
},
|
|
3258
|
+
weight: "medium",
|
|
3259
|
+
children: /* @__PURE__ */ jsx(CardTitleFace, {
|
|
3260
|
+
title: cardTitle({
|
|
3261
|
+
face: card.face,
|
|
3262
|
+
titles: titles
|
|
3263
|
+
})
|
|
2874
3264
|
})
|
|
2875
|
-
})
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
3265
|
+
}), held?.stuck === !0 ? /* @__PURE__ */ jsx(AlertGlyph, {
|
|
3266
|
+
Icon: ErrorOutlineIcon,
|
|
3267
|
+
hint: STUCK_RUN_HINT,
|
|
3268
|
+
tone: "critical"
|
|
3269
|
+
}) : null ]
|
|
3270
|
+
}), held === void 0 ? null : /* @__PURE__ */ jsx(CardMetrics, {
|
|
3271
|
+
facts: held
|
|
2879
3272
|
}) ]
|
|
2880
3273
|
})
|
|
2881
3274
|
});
|
|
2882
3275
|
}
|
|
2883
3276
|
|
|
2884
|
-
function
|
|
2885
|
-
|
|
2886
|
-
return phrase === void 0 ? null : /* @__PURE__ */ jsx(Flex, {
|
|
3277
|
+
function CardMetrics({facts: facts}) {
|
|
3278
|
+
return facts.settled ? null : /* @__PURE__ */ jsxs(Flex, {
|
|
2887
3279
|
align: "center",
|
|
2888
|
-
|
|
2889
|
-
children:
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
3280
|
+
gap: 3,
|
|
3281
|
+
children: [
|
|
3282
|
+
/* @__PURE__ */ jsx(MetricPair, {
|
|
3283
|
+
Icon: EmptyIcon,
|
|
3284
|
+
empty: facts.pending === 0,
|
|
3285
|
+
face: {
|
|
3286
|
+
text: pendingHint(facts.pending)
|
|
3287
|
+
},
|
|
3288
|
+
value: String(facts.pending)
|
|
3289
|
+
}), facts.overdue === 0 ? null : /* @__PURE__ */ jsx(MetricPair, {
|
|
3290
|
+
Icon: CalendarIcon,
|
|
3291
|
+
face: {
|
|
3292
|
+
text: overdueTasksHint(facts.overdue)
|
|
3293
|
+
},
|
|
3294
|
+
tone: "caution",
|
|
3295
|
+
value: String(facts.overdue)
|
|
3296
|
+
}) ]
|
|
2899
3297
|
});
|
|
2900
3298
|
}
|
|
2901
3299
|
|
|
2902
|
-
function StageGroupHeading({group: group}) {
|
|
3300
|
+
function StageGroupHeading({facts: facts, group: group}) {
|
|
3301
|
+
const totals = laneTotals(group.cards, facts);
|
|
2903
3302
|
/* @__PURE__ */
|
|
2904
3303
|
return jsxs(Flex, {
|
|
2905
3304
|
align: "center",
|
|
2906
3305
|
gap: 2,
|
|
2907
3306
|
children: [
|
|
2908
|
-
/* @__PURE__ */ jsx(
|
|
3307
|
+
/* @__PURE__ */ jsx(CountedHeading, {
|
|
2909
3308
|
count: group.cards.length,
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
3309
|
+
title: group.title
|
|
3310
|
+
}), totals.overdue === 0 && totals.stuck === 0 ? null : /* @__PURE__ */ jsxs(Fragment, {
|
|
3311
|
+
children: [
|
|
3312
|
+
/* @__PURE__ */ jsx(Flex, {
|
|
3313
|
+
flex: 1
|
|
3314
|
+
}),
|
|
3315
|
+
/* @__PURE__ */ jsxs(Flex, {
|
|
3316
|
+
align: "center",
|
|
3317
|
+
flex: "none",
|
|
3318
|
+
gap: 3,
|
|
3319
|
+
children: [ totals.overdue === 0 ? null : /* @__PURE__ */ jsx(MetricPair, {
|
|
3320
|
+
Icon: CalendarIcon,
|
|
3321
|
+
face: {
|
|
3322
|
+
text: laneOverdueHint(totals.overdue)
|
|
3323
|
+
},
|
|
3324
|
+
tone: "caution",
|
|
3325
|
+
value: String(totals.overdue)
|
|
3326
|
+
}), totals.stuck === 0 ? null : /* @__PURE__ */ jsx(MetricPair, {
|
|
3327
|
+
Icon: ErrorOutlineIcon,
|
|
3328
|
+
face: {
|
|
3329
|
+
text: laneStuckHint(totals.stuck)
|
|
3330
|
+
},
|
|
3331
|
+
tone: "critical",
|
|
3332
|
+
value: String(totals.stuck)
|
|
3333
|
+
}) ]
|
|
3334
|
+
}) ]
|
|
2915
3335
|
}), group.retired ?
|
|
2916
3336
|
/* @__PURE__ */ jsx(Text, {
|
|
2917
3337
|
muted: !0,
|
|
@@ -2960,6 +3380,7 @@ function StageColumn({group: group, leadingRule: leadingRule, trailingRule: trai
|
|
|
2960
3380
|
paddingTop: 4,
|
|
2961
3381
|
paddingX: LANE_PADDING,
|
|
2962
3382
|
children: /* @__PURE__ */ jsx(StageGroupHeading, {
|
|
3383
|
+
facts: wiring.facts,
|
|
2963
3384
|
group: group
|
|
2964
3385
|
})
|
|
2965
3386
|
}), group.cards.length === 0 ? /* @__PURE__ */ jsx(Flex, {
|
|
@@ -3100,7 +3521,7 @@ function useBoard(args) {
|
|
|
3100
3521
|
}), {titles: titles, ready: ready} = seeded, board = useMemo(() => derived ? orderBoardByPreviewTitle(derived, titles) : void 0, [ derived, titles ]);
|
|
3101
3522
|
return useMemo(() => ({
|
|
3102
3523
|
board: board,
|
|
3103
|
-
ready: ready,
|
|
3524
|
+
ready: board !== void 0 && ready,
|
|
3104
3525
|
titles: seeded
|
|
3105
3526
|
}), [ board, ready, seeded ]);
|
|
3106
3527
|
}
|
|
@@ -3207,11 +3628,13 @@ function ActiveCount({face: face}) {
|
|
|
3207
3628
|
}
|
|
3208
3629
|
|
|
3209
3630
|
function DefinitionFacts({definition: definition}) {
|
|
3210
|
-
const {mappingIssues: mappingIssues, mappings: mappings} = useWorkflowContext(), schema = useSchema(), instances = useToolInstances(), snapshotWidth = useContainerToken(2), [row] = definitionCatalog({
|
|
3631
|
+
const {mappingIssues: mappingIssues, mappings: mappings} = useWorkflowContext(), schema = useSchema(), instances = useToolInstances(), now = useMinuteClock(), snapshotWidth = useContainerToken(2), [row] = definitionCatalog({
|
|
3211
3632
|
definitions: [ definition ],
|
|
3633
|
+
identity: void 0,
|
|
3212
3634
|
mappings: mappings,
|
|
3213
|
-
|
|
3214
|
-
issues: mappingIssues
|
|
3635
|
+
instances: [ ...instances.inFlight, ...instances.settled ],
|
|
3636
|
+
issues: mappingIssues,
|
|
3637
|
+
now: now
|
|
3215
3638
|
}), runsOn = docTypeLabels(row?.docTypes ?? [], name => schema.get(name)?.title).map(docType => docType.title);
|
|
3216
3639
|
/* @__PURE__ */
|
|
3217
3640
|
return jsxs(Flex, {
|
|
@@ -3249,7 +3672,7 @@ function DefinitionFacts({definition: definition}) {
|
|
|
3249
3672
|
label: "Active instances",
|
|
3250
3673
|
children: /* @__PURE__ */ jsx(ActiveCount, {
|
|
3251
3674
|
face: activeCountFace({
|
|
3252
|
-
count: row?.activeCount ?? 0,
|
|
3675
|
+
count: row?.signals.activeCount ?? 0,
|
|
3253
3676
|
error: instances.error,
|
|
3254
3677
|
loading: instances.loading,
|
|
3255
3678
|
truncated: instances.truncated
|
|
@@ -3317,7 +3740,7 @@ function pickerLabel(face) {
|
|
|
3317
3740
|
}
|
|
3318
3741
|
|
|
3319
3742
|
function WorkflowPicker({face: face, onSelect: onSelect, options: options}) {
|
|
3320
|
-
const empty = options.length === 0;
|
|
3743
|
+
const empty = options.length === 0, reclaimed = -useSpaceToken(TOOL_HEADING_PADDING);
|
|
3321
3744
|
/* @__PURE__ */
|
|
3322
3745
|
return jsx(MenuButton, {
|
|
3323
3746
|
button: /* @__PURE__ */ jsx(Button, {
|
|
@@ -3327,6 +3750,9 @@ function WorkflowPicker({face: face, onSelect: onSelect, options: options}) {
|
|
|
3327
3750
|
iconRight: ChevronDownIcon,
|
|
3328
3751
|
mode: "bleed",
|
|
3329
3752
|
padding: TOOL_HEADING_PADDING,
|
|
3753
|
+
style: {
|
|
3754
|
+
margin: reclaimed
|
|
3755
|
+
},
|
|
3330
3756
|
text: pickerLabel(face),
|
|
3331
3757
|
textWeight: "semibold"
|
|
3332
3758
|
}),
|
|
@@ -3357,6 +3783,7 @@ function WorkflowPageHeader({face: face, onSelectPage: onSelectPage, onSelectWor
|
|
|
3357
3783
|
children: [
|
|
3358
3784
|
/* @__PURE__ */ jsx(Flex, {
|
|
3359
3785
|
align: "center",
|
|
3786
|
+
padding: TOOL_HEADING_PADDING,
|
|
3360
3787
|
children: /* @__PURE__ */ jsx(WorkflowPicker, {
|
|
3361
3788
|
face: face,
|
|
3362
3789
|
onSelect: onSelectWorkflow,
|
|
@@ -3800,20 +4227,28 @@ function WorkflowPage({onOpenWorkflow: onOpenWorkflow, onSelectPage: onSelectPag
|
|
|
3800
4227
|
}), instances = useBoardInstances(view.streamName), {board: board, ready: ready, titles: titles} = useBoard({
|
|
3801
4228
|
definition: selected,
|
|
3802
4229
|
instances: instances.rows
|
|
3803
|
-
}), {select: select, selectedInstanceId: selectedInstanceId} = usePageSelection(page), panel = usePanelPresence(panelSubject({
|
|
4230
|
+
}), {select: select, selectedInstanceId: selectedInstanceId} = usePageSelection(page), now = useMinuteClock(), panel = usePanelPresence(panelSubject({
|
|
3804
4231
|
board: board,
|
|
3805
4232
|
selectedInstanceId: selectedInstanceId
|
|
3806
4233
|
})), revealed = useRevealGate({
|
|
3807
4234
|
loading: instances.loading,
|
|
4235
|
+
progress: titles.resolved.size,
|
|
3808
4236
|
ready: ready
|
|
3809
|
-
})
|
|
4237
|
+
});
|
|
3810
4238
|
if (selection.kind === "loading") /* @__PURE__ */ return jsx(UnresolvedPage, {
|
|
3811
|
-
error: catalogError
|
|
3812
|
-
|
|
4239
|
+
error: catalogError
|
|
4240
|
+
});
|
|
4241
|
+
const catalogEmpty = (definitions ?? []).length === 0;
|
|
4242
|
+
if (selection.kind === "unknown" && catalogEmpty) /* @__PURE__ */
|
|
4243
|
+
return jsx(EmptyCatalogPage, {
|
|
4244
|
+
name: selection.name
|
|
3813
4245
|
});
|
|
3814
4246
|
const wiring = {
|
|
3815
4247
|
onSelect: select,
|
|
3816
|
-
|
|
4248
|
+
facts: cardFacts({
|
|
4249
|
+
instances: instances.rows,
|
|
4250
|
+
now: now
|
|
4251
|
+
}),
|
|
3817
4252
|
selectedInstanceId: selectedInstanceId,
|
|
3818
4253
|
titles: titles
|
|
3819
4254
|
};
|
|
@@ -3866,7 +4301,7 @@ function WorkflowPage({onOpenWorkflow: onOpenWorkflow, onSelectPage: onSelectPag
|
|
|
3866
4301
|
}),
|
|
3867
4302
|
/* @__PURE__ */ jsx(PageBody, {
|
|
3868
4303
|
board: board,
|
|
3869
|
-
catalogEmpty:
|
|
4304
|
+
catalogEmpty: catalogEmpty,
|
|
3870
4305
|
catalogError: catalogError,
|
|
3871
4306
|
instancesError: instances.error,
|
|
3872
4307
|
loading: !revealed,
|
|
@@ -3896,30 +4331,45 @@ function WorkflowPage({onOpenWorkflow: onOpenWorkflow, onSelectPage: onSelectPag
|
|
|
3896
4331
|
});
|
|
3897
4332
|
}
|
|
3898
4333
|
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
function UnresolvedPage({error: error, waiting: waiting}) {
|
|
4334
|
+
function UnresolvedPage({error: error}) {
|
|
3902
4335
|
/* @__PURE__ */
|
|
3903
4336
|
return jsx(Flex, {
|
|
3904
4337
|
direction: "column",
|
|
3905
4338
|
height: "fill",
|
|
3906
4339
|
overflow: "hidden",
|
|
3907
|
-
children: error === void 0 ? /* @__PURE__ */ jsx(WaitingFace, {
|
|
3908
|
-
waiting: waiting
|
|
3909
|
-
}) : /* @__PURE__ */ jsx(ReadErrorFace, {
|
|
4340
|
+
children: error === void 0 ? /* @__PURE__ */ jsx(WaitingFace, {}) : /* @__PURE__ */ jsx(ReadErrorFace, {
|
|
3910
4341
|
text: CATALOG_READ_FAILED
|
|
3911
4342
|
})
|
|
3912
4343
|
});
|
|
3913
4344
|
}
|
|
3914
4345
|
|
|
3915
|
-
function WaitingFace(
|
|
4346
|
+
function WaitingFace() {
|
|
3916
4347
|
/* @__PURE__ */
|
|
3917
4348
|
return jsx(StatusBox, {
|
|
3918
|
-
children:
|
|
4349
|
+
children: /* @__PURE__ */ jsx(TabStatusRow, {
|
|
3919
4350
|
children: /* @__PURE__ */ jsx(LoadingRow, {
|
|
3920
4351
|
label: "Loading workflow…"
|
|
3921
4352
|
})
|
|
3922
|
-
})
|
|
4353
|
+
})
|
|
4354
|
+
});
|
|
4355
|
+
}
|
|
4356
|
+
|
|
4357
|
+
function EmptyCatalogPage({name: name}) {
|
|
4358
|
+
const face = unknownWorkflowFace({
|
|
4359
|
+
catalogEmpty: !0,
|
|
4360
|
+
name: name
|
|
4361
|
+
});
|
|
4362
|
+
/* @__PURE__ */
|
|
4363
|
+
return jsx(Flex, {
|
|
4364
|
+
direction: "column",
|
|
4365
|
+
height: "fill",
|
|
4366
|
+
overflow: "hidden",
|
|
4367
|
+
padding: LANE_PADDING,
|
|
4368
|
+
children: /* @__PURE__ */ jsx(EmptyState, {
|
|
4369
|
+
description: face.description,
|
|
4370
|
+
icon: /* @__PURE__ */ jsx(SearchIcon, {}),
|
|
4371
|
+
title: face.title
|
|
4372
|
+
})
|
|
3923
4373
|
});
|
|
3924
4374
|
}
|
|
3925
4375
|
|
|
@@ -4124,11 +4574,12 @@ function WorkflowsHome({filterSlot: filterSlot, onOpenInstance: onOpenInstance,
|
|
|
4124
4574
|
|
|
4125
4575
|
function HomePanel({filterSlot: filterSlot, identity: identity, instances: instances, onOpenInstance: onOpenInstance, onOpenTask: onOpenTask, onOpenWorkflow: onOpenWorkflow, tab: tab}) {
|
|
4126
4576
|
return tab === "overview" ? /* @__PURE__ */ jsx(OverviewTab, {
|
|
4577
|
+
identity: identity,
|
|
4127
4578
|
onOpenWorkflow: onOpenWorkflow
|
|
4128
4579
|
}) : /* @__PURE__ */ jsx(TasksTab, {
|
|
4129
4580
|
error: instances.error,
|
|
4130
4581
|
filterSlot: filterSlot,
|
|
4131
|
-
identity: identity,
|
|
4582
|
+
identity: identityOf(identity),
|
|
4132
4583
|
instances: [ ...instances.inFlight, ...instances.settled ],
|
|
4133
4584
|
loading: instances.loading,
|
|
4134
4585
|
onOpenInstance: onOpenInstance,
|