@burdenoff/microfe-planmagnet 2026.928.3 → 2026.928.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/planmagnet/PlanMagnetRoot.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoot.js +126 -84
- package/dist/planmagnet/PlanMagnetRoot.js.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +192 -64
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/automation/AutomationExecutionsPanel.d.ts +5 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.d.ts.map +1 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.js +107 -0
- package/dist/planmagnet/automation/AutomationExecutionsPanel.js.map +1 -0
- package/dist/planmagnet/automation/AutomationRuleFields.d.ts +29 -0
- package/dist/planmagnet/automation/AutomationRuleFields.d.ts.map +1 -0
- package/dist/planmagnet/automation/AutomationRuleFields.js +308 -0
- package/dist/planmagnet/automation/AutomationRuleFields.js.map +1 -0
- package/dist/planmagnet/automation/automationRuleTypes.d.ts +60 -0
- package/dist/planmagnet/automation/automationRuleTypes.d.ts.map +1 -0
- package/dist/planmagnet/automation/automationRuleTypes.js +113 -0
- package/dist/planmagnet/automation/automationRuleTypes.js.map +1 -0
- package/dist/planmagnet/board/BulkActions.d.ts +11 -0
- package/dist/planmagnet/board/BulkActions.d.ts.map +1 -0
- package/dist/planmagnet/board/BulkActions.js +182 -0
- package/dist/planmagnet/board/BulkActions.js.map +1 -0
- package/dist/planmagnet/board/ProjectBoard.d.ts.map +1 -1
- package/dist/planmagnet/board/ProjectBoard.js +289 -254
- package/dist/planmagnet/board/ProjectBoard.js.map +1 -1
- package/dist/planmagnet/budgets/BudgetControls.d.ts +30 -0
- package/dist/planmagnet/budgets/BudgetControls.d.ts.map +1 -0
- package/dist/planmagnet/budgets/BudgetControls.js +470 -0
- package/dist/planmagnet/budgets/BudgetControls.js.map +1 -0
- package/dist/planmagnet/budgets/ExpenseControls.d.ts +27 -0
- package/dist/planmagnet/budgets/ExpenseControls.d.ts.map +1 -0
- package/dist/planmagnet/budgets/ExpenseControls.js +366 -0
- package/dist/planmagnet/budgets/ExpenseControls.js.map +1 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.d.ts +5 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.d.ts.map +1 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.js +112 -0
- package/dist/planmagnet/budgets/ProjectBudgetsSummary.js.map +1 -0
- package/dist/planmagnet/budgets/budgetMath.d.ts +26 -0
- package/dist/planmagnet/budgets/budgetMath.d.ts.map +1 -0
- package/dist/planmagnet/budgets/budgetMath.js +49 -0
- package/dist/planmagnet/budgets/budgetMath.js.map +1 -0
- package/dist/planmagnet/controls/AutomationRuleControls.d.ts +23 -0
- package/dist/planmagnet/controls/AutomationRuleControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/AutomationRuleControls.js +172 -0
- package/dist/planmagnet/controls/AutomationRuleControls.js.map +1 -0
- package/dist/planmagnet/controls/CompetitorControls.d.ts +20 -0
- package/dist/planmagnet/controls/CompetitorControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/CompetitorControls.js +172 -0
- package/dist/planmagnet/controls/CompetitorControls.js.map +1 -0
- package/dist/planmagnet/controls/CustomFieldControls.d.ts +42 -0
- package/dist/planmagnet/controls/CustomFieldControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/CustomFieldControls.js +84 -0
- package/dist/planmagnet/controls/CustomFieldControls.js.map +1 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts +8 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.d.ts.map +1 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.js +315 -0
- package/dist/planmagnet/controls/CustomFieldValuesPanel.js.map +1 -0
- package/dist/planmagnet/controls/FeatureControls.js +53 -53
- package/dist/planmagnet/controls/FeatureTriage.js +11 -11
- package/dist/planmagnet/controls/ObjectiveControls.js +37 -37
- package/dist/planmagnet/controls/Pickers.d.ts +17 -2
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +100 -9
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/controls/PortfolioControls.d.ts +13 -0
- package/dist/planmagnet/controls/PortfolioControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/PortfolioControls.js +114 -0
- package/dist/planmagnet/controls/PortfolioControls.js.map +1 -0
- package/dist/planmagnet/controls/ProgramControls.d.ts +25 -0
- package/dist/planmagnet/controls/ProgramControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/ProgramControls.js +187 -0
- package/dist/planmagnet/controls/ProgramControls.js.map +1 -0
- package/dist/planmagnet/controls/ProjectControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/ProjectControls.js +54 -47
- package/dist/planmagnet/controls/ProjectControls.js.map +1 -1
- package/dist/planmagnet/controls/ReleaseControls.js +7 -7
- package/dist/planmagnet/controls/RiskControls.d.ts +27 -0
- package/dist/planmagnet/controls/RiskControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/RiskControls.js +346 -0
- package/dist/planmagnet/controls/RiskControls.js.map +1 -0
- package/dist/planmagnet/controls/TemplateControls.d.ts +15 -0
- package/dist/planmagnet/controls/TemplateControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/TemplateControls.js +55 -0
- package/dist/planmagnet/controls/TemplateControls.js.map +1 -0
- package/dist/planmagnet/controls/WorkItemControls.js +1 -1
- package/dist/planmagnet/create/CreateDialogs.d.ts +20 -0
- package/dist/planmagnet/create/CreateDialogs.d.ts.map +1 -1
- package/dist/planmagnet/create/CreateDialogs.js +455 -116
- package/dist/planmagnet/create/CreateDialogs.js.map +1 -1
- package/dist/planmagnet/dependency/DependencyPanel.d.ts +6 -0
- package/dist/planmagnet/dependency/DependencyPanel.d.ts.map +1 -0
- package/dist/planmagnet/dependency/DependencyPanel.js +310 -0
- package/dist/planmagnet/dependency/DependencyPanel.js.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js +171 -0
- package/dist/planmagnet/pages/AutomationAutomationRuleDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js +232 -0
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts +2 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +93 -0
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js.map +1 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js +127 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js +129 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js +132 -0
- package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js.map +1 -0
- package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js +181 -0
- package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js.map +1 -0
- package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.js +242 -0
- package/dist/planmagnet/pages/PortfoliosCreatePortfolioPagePage.js.map +1 -0
- package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js +302 -0
- package/dist/planmagnet/pages/PortfoliosEditPortfolioPagePage.js.map +1 -0
- package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +335 -0
- package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js +154 -0
- package/dist/planmagnet/pages/PortfoliosPortfoliosPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +124 -138
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js +221 -0
- package/dist/planmagnet/pages/ProgramsCreateProgramPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProgramsEditProgramPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProgramsEditProgramPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js +279 -0
- package/dist/planmagnet/pages/ProgramsEditProgramPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.js +178 -0
- package/dist/planmagnet/pages/ProgramsProgramDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProgramsProgramsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProgramsProgramsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProgramsProgramsPagePage.js +157 -0
- package/dist/planmagnet/pages/ProgramsProgramsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js +315 -0
- package/dist/planmagnet/pages/ProjectsBudgetDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +186 -0
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js +164 -0
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js +348 -0
- package/dist/planmagnet/pages/ProjectsCustomFieldsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +130 -103
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsMilestoneDetailPagePage.js +4 -4
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +4 -4
- package/dist/planmagnet/pages/ProjectsPlanningEditPagePage.js +6 -6
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js +325 -189
- package/dist/planmagnet/pages/ProjectsProjectDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +81 -72
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.js +278 -0
- package/dist/planmagnet/pages/RisksRiskDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js +191 -0
- package/dist/planmagnet/pages/RisksRiskRegisterPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksCreateTaskPagePage.js +5 -5
- package/dist/planmagnet/pages/TasksEditTaskPagePage.js +4 -4
- package/dist/planmagnet/pages/TasksImportPagePage.js +5 -5
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js +161 -137
- package/dist/planmagnet/pages/TasksTaskDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TasksTasksPagePage.js +124 -113
- package/dist/planmagnet/pages/TasksTasksPagePage.js.map +1 -1
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +263 -0
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js +254 -0
- package/dist/planmagnet/pages/TasksTimesheetDetailPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.js +165 -0
- package/dist/planmagnet/pages/TasksTimesheetsPagePage.js.map +1 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js +316 -0
- package/dist/planmagnet/pages/TemplatesEditTemplatePagePage.js.map +1 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js +208 -0
- package/dist/planmagnet/pages/TemplatesTemplatesPagePage.js.map +1 -0
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts +0 -5
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.d.ts.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +47 -89
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js.map +1 -1
- package/dist/planmagnet/roadmaps/RoadmapControls.js +24 -24
- package/dist/planmagnet/time/TaskTimePanel.d.ts +7 -0
- package/dist/planmagnet/time/TaskTimePanel.d.ts.map +1 -0
- package/dist/planmagnet/time/TaskTimePanel.js +104 -0
- package/dist/planmagnet/time/TaskTimePanel.js.map +1 -0
- package/dist/planmagnet/time/TimeEntryControls.d.ts +37 -0
- package/dist/planmagnet/time/TimeEntryControls.d.ts.map +1 -0
- package/dist/planmagnet/time/TimeEntryControls.js +338 -0
- package/dist/planmagnet/time/TimeEntryControls.js.map +1 -0
- package/dist/planmagnet/time/TimesheetControls.d.ts +18 -0
- package/dist/planmagnet/time/TimesheetControls.d.ts.map +1 -0
- package/dist/planmagnet/time/TimesheetControls.js +244 -0
- package/dist/planmagnet/time/TimesheetControls.js.map +1 -0
- package/dist/planmagnet/time/timeShared.d.ts +29 -0
- package/dist/planmagnet/time/timeShared.d.ts.map +1 -0
- package/dist/planmagnet/time/timeShared.js +34 -0
- package/dist/planmagnet/time/timeShared.js.map +1 -0
- package/dist/planmagnet/utils/rowNavigation.js +5 -2
- package/dist/planmagnet/utils/rowNavigation.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutomationExecutionsPanel.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/automation/AutomationExecutionsPanel.tsx"],"names":[],"mappings":"AA6DA,wBAAgB,yBAAyB,CAAC,EACxC,WAAW,EACX,MAAM,GACP,EAAE;IACD,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB,2CA+DA"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { gql as e } from "@apollo/client";
|
|
2
|
+
import { useQuery as t } from "@apollo/client/react";
|
|
3
|
+
import { jsx as n, jsxs as r } from "react/jsx-runtime";
|
|
4
|
+
import { Badge as i } from "@burdenoff/fe-libs/ui";
|
|
5
|
+
//#region src/planmagnet/automation/AutomationExecutionsPanel.tsx
|
|
6
|
+
var a = e`
|
|
7
|
+
query AutomationExecutionsForRule(
|
|
8
|
+
$workspaceId: ID!
|
|
9
|
+
$filter: PlanmagnetAutomationExecutionFilter
|
|
10
|
+
$pagination: PlanmagnetPaginationInput
|
|
11
|
+
) {
|
|
12
|
+
planmagnetAutomationExecutions(
|
|
13
|
+
workspaceId: $workspaceId
|
|
14
|
+
filter: $filter
|
|
15
|
+
pagination: $pagination
|
|
16
|
+
) {
|
|
17
|
+
totalCount
|
|
18
|
+
items {
|
|
19
|
+
id
|
|
20
|
+
status
|
|
21
|
+
errorMessage
|
|
22
|
+
result
|
|
23
|
+
durationMs
|
|
24
|
+
executedAt
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`, o = {
|
|
29
|
+
SUCCESS: "success",
|
|
30
|
+
PARTIAL_FAILURE: "warning",
|
|
31
|
+
FAILURE: "destructive",
|
|
32
|
+
SKIPPED: "secondary",
|
|
33
|
+
PENDING: "secondary",
|
|
34
|
+
RUNNING: "secondary"
|
|
35
|
+
};
|
|
36
|
+
function s(e) {
|
|
37
|
+
if (!e || typeof e != "object") return null;
|
|
38
|
+
let t = e.dispatched;
|
|
39
|
+
return !Array.isArray(t) || t.length === 0 ? null : t.join(", ");
|
|
40
|
+
}
|
|
41
|
+
function c({ workspaceId: e, ruleId: c }) {
|
|
42
|
+
let { data: l, loading: u, error: d } = t(a, {
|
|
43
|
+
variables: {
|
|
44
|
+
workspaceId: e ?? "",
|
|
45
|
+
filter: { ruleId: c },
|
|
46
|
+
pagination: { first: 20 }
|
|
47
|
+
},
|
|
48
|
+
skip: !e,
|
|
49
|
+
fetchPolicy: "cache-and-network"
|
|
50
|
+
}), f = l?.planmagnetAutomationExecutions, p = f?.items ?? [];
|
|
51
|
+
return u && !l ? /* @__PURE__ */ n("p", {
|
|
52
|
+
className: "text-sm text-muted-foreground",
|
|
53
|
+
children: "Loading recent executions…"
|
|
54
|
+
}) : d ? /* @__PURE__ */ r("p", {
|
|
55
|
+
role: "alert",
|
|
56
|
+
className: "text-sm text-destructive",
|
|
57
|
+
children: ["Recent executions could not be loaded: ", d.message]
|
|
58
|
+
}) : p.length === 0 ? /* @__PURE__ */ n("p", {
|
|
59
|
+
className: "text-sm text-muted-foreground",
|
|
60
|
+
children: "No executions yet. They appear here once the rule fires or is run manually."
|
|
61
|
+
}) : /* @__PURE__ */ r("div", {
|
|
62
|
+
className: "space-y-2",
|
|
63
|
+
children: [p.map((e) => {
|
|
64
|
+
let t = s(e.result);
|
|
65
|
+
return /* @__PURE__ */ n("div", {
|
|
66
|
+
className: "flex flex-wrap items-start justify-between gap-2 rounded-md border p-3 text-sm",
|
|
67
|
+
children: /* @__PURE__ */ r("div", {
|
|
68
|
+
className: "min-w-0 space-y-1",
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ r("div", {
|
|
71
|
+
className: "flex items-center gap-2",
|
|
72
|
+
children: [/* @__PURE__ */ n(i, {
|
|
73
|
+
variant: o[e.status] ?? "secondary",
|
|
74
|
+
children: e.status.toLowerCase().replace("_", " ")
|
|
75
|
+
}), /* @__PURE__ */ r("span", {
|
|
76
|
+
className: "text-xs text-muted-foreground",
|
|
77
|
+
children: [new Date(e.executedAt).toLocaleString(), e.durationMs == null ? "" : ` · ${e.durationMs}ms`]
|
|
78
|
+
})]
|
|
79
|
+
}),
|
|
80
|
+
t && /* @__PURE__ */ r("p", {
|
|
81
|
+
className: "text-xs text-muted-foreground",
|
|
82
|
+
children: ["Ran: ", t]
|
|
83
|
+
}),
|
|
84
|
+
e.errorMessage && /* @__PURE__ */ n("p", {
|
|
85
|
+
role: "alert",
|
|
86
|
+
className: "text-xs text-destructive",
|
|
87
|
+
children: e.errorMessage
|
|
88
|
+
})
|
|
89
|
+
]
|
|
90
|
+
})
|
|
91
|
+
}, e.id);
|
|
92
|
+
}), f && f.totalCount > p.length && /* @__PURE__ */ r("p", {
|
|
93
|
+
className: "text-xs text-muted-foreground",
|
|
94
|
+
children: [
|
|
95
|
+
"Showing the ",
|
|
96
|
+
p.length,
|
|
97
|
+
" most recent of ",
|
|
98
|
+
f.totalCount,
|
|
99
|
+
"."
|
|
100
|
+
]
|
|
101
|
+
})]
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
export { c as AutomationExecutionsPanel };
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=AutomationExecutionsPanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutomationExecutionsPanel.js","names":[],"sources":["../../../src/planmagnet/automation/AutomationExecutionsPanel.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { Badge } from '@burdenoff/fe-libs/ui';\n\n/**\n * Recent executions for one rule (BOFF-8047, capability register row \"Automation rules\": gate 3/UI was the only\n * gap — `planmagnetAutomationExecutions` has been real and prod-verified since BOFF-7822/8043). Every run this\n * engine has EVER attempted for the rule is here, including a non-match (`SKIPPED`, \"conditions did not match\")\n * from a manual run and a `PARTIAL_FAILURE` where only some declared actions dispatched — so a rule that looks\n * \"successful\" in the header can still show failures here.\n */\n\nconst EXECUTIONS = gql`\n query AutomationExecutionsForRule(\n $workspaceId: ID!\n $filter: PlanmagnetAutomationExecutionFilter\n $pagination: PlanmagnetPaginationInput\n ) {\n planmagnetAutomationExecutions(\n workspaceId: $workspaceId\n filter: $filter\n pagination: $pagination\n ) {\n totalCount\n items {\n id\n status\n errorMessage\n result\n durationMs\n executedAt\n }\n }\n }\n`;\n\ninterface ExecutionRow {\n id: string;\n status: string;\n errorMessage: string | null;\n result: unknown;\n durationMs: number | null;\n executedAt: string;\n}\n\nconst STATUS_VARIANT: Record<string, 'success' | 'warning' | 'destructive' | 'secondary'> = {\n SUCCESS: 'success',\n PARTIAL_FAILURE: 'warning',\n FAILURE: 'destructive',\n SKIPPED: 'secondary',\n PENDING: 'secondary',\n RUNNING: 'secondary',\n};\n\nfunction dispatchedSummary(result: unknown): string | null {\n if (!result || typeof result !== 'object') return null;\n const dispatched = (result as { dispatched?: unknown }).dispatched;\n if (!Array.isArray(dispatched) || dispatched.length === 0) return null;\n return dispatched.join(', ');\n}\n\nexport function AutomationExecutionsPanel({\n workspaceId,\n ruleId,\n}: {\n workspaceId: string | undefined;\n ruleId: string;\n}) {\n const { data, loading, error } = useQuery<{\n planmagnetAutomationExecutions: { totalCount: number; items: ExecutionRow[] };\n }>(EXECUTIONS, {\n variables: { workspaceId: workspaceId ?? '', filter: { ruleId }, pagination: { first: 20 } },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n\n const list = data?.planmagnetAutomationExecutions;\n const executions = list?.items ?? [];\n\n if (loading && !data)\n return <p className=\"text-sm text-muted-foreground\">Loading recent executions…</p>;\n if (error)\n return (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n Recent executions could not be loaded: {error.message}\n </p>\n );\n if (executions.length === 0)\n return (\n <p className=\"text-sm text-muted-foreground\">\n No executions yet. They appear here once the rule fires or is run manually.\n </p>\n );\n\n return (\n <div className=\"space-y-2\">\n {executions.map((execution) => {\n const dispatched = dispatchedSummary(execution.result);\n return (\n <div\n key={execution.id}\n className=\"flex flex-wrap items-start justify-between gap-2 rounded-md border p-3 text-sm\"\n >\n <div className=\"min-w-0 space-y-1\">\n <div className=\"flex items-center gap-2\">\n <Badge variant={STATUS_VARIANT[execution.status] ?? 'secondary'}>\n {execution.status.toLowerCase().replace('_', ' ')}\n </Badge>\n <span className=\"text-xs text-muted-foreground\">\n {new Date(execution.executedAt).toLocaleString()}\n {execution.durationMs != null ? ` · ${execution.durationMs}ms` : ''}\n </span>\n </div>\n {dispatched && <p className=\"text-xs text-muted-foreground\">Ran: {dispatched}</p>}\n {execution.errorMessage && (\n <p role=\"alert\" className=\"text-xs text-destructive\">\n {execution.errorMessage}\n </p>\n )}\n </div>\n </div>\n );\n })}\n {list && list.totalCount > executions.length && (\n <p className=\"text-xs text-muted-foreground\">\n Showing the {executions.length} most recent of {list.totalCount}.\n </p>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAYA,IAAM,IAAa,CAAG;;;;;;;;;;;;;;;;;;;;;;GAiChB,IAAsF;CAC1F,SAAS;CACT,iBAAiB;CACjB,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACV;AAED,SAAS,EAAkB,GAAgC;AACzD,KAAI,CAAC,KAAU,OAAO,KAAW,SAAU,QAAO;CAClD,IAAM,IAAc,EAAoC;AAExD,QADI,CAAC,MAAM,QAAQ,EAAW,IAAI,EAAW,WAAW,IAAU,OAC3D,EAAW,KAAK,KAAK;;AAG9B,SAAgB,EAA0B,EACxC,gBACA,aAIC;CACD,IAAM,EAAE,SAAM,YAAS,aAAU,EAE9B,GAAY;EACb,WAAW;GAAE,aAAa,KAAe;GAAI,QAAQ,EAAE,WAAQ;GAAE,YAAY,EAAE,OAAO,IAAI;GAAE;EAC5F,MAAM,CAAC;EACP,aAAa;EACd,CAAC,EAEI,IAAO,GAAM,gCACb,IAAa,GAAM,SAAS,EAAE;AAiBpC,QAfI,KAAW,CAAC,IACP,kBAAC,KAAD;EAAG,WAAU;YAAgC;EAA8B,CAAA,GAChF,IAEA,kBAAC,KAAD;EAAG,MAAK;EAAQ,WAAU;YAA1B,CAAqD,2CACX,EAAM,QAC5C;MAEJ,EAAW,WAAW,IAEtB,kBAAC,KAAD;EAAG,WAAU;YAAgC;EAEzC,CAAA,GAIN,kBAAC,OAAD;EAAK,WAAU;YAAf,CACG,EAAW,KAAK,MAAc;GAC7B,IAAM,IAAa,EAAkB,EAAU,OAAO;AACtD,UACE,kBAAC,OAAD;IAEE,WAAU;cAEV,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD;QAAO,SAAS,EAAe,EAAU,WAAW;kBACjD,EAAU,OAAO,aAAa,CAAC,QAAQ,KAAK,IAAI;QAC3C,CAAA,EACR,kBAAC,QAAD;QAAM,WAAU;kBAAhB,CACG,IAAI,KAAK,EAAU,WAAW,CAAC,gBAAgB,EAC/C,EAAU,cAAc,OAAwC,KAAjC,MAAM,EAAU,WAAW,IACtD;UACH;;MACL,KAAc,kBAAC,KAAD;OAAG,WAAU;iBAAb,CAA6C,SAAM,EAAe;;MAChF,EAAU,gBACT,kBAAC,KAAD;OAAG,MAAK;OAAQ,WAAU;iBACvB,EAAU;OACT,CAAA;MAEF;;IACF,EApBC,EAAU,GAoBX;IAER,EACD,KAAQ,EAAK,aAAa,EAAW,UACpC,kBAAC,KAAD;GAAG,WAAU;aAAb;IAA6C;IAC9B,EAAW;IAAO;IAAiB,EAAK;IAAW;IAC9D;KAEF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RuleAction, RuleCondition, TriggerType } from './automationRuleTypes';
|
|
2
|
+
|
|
3
|
+
/** The editable shape both the create and edit pages share. */
|
|
4
|
+
export interface AutomationRuleFormState {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
projectId: string;
|
|
8
|
+
triggerType: TriggerType;
|
|
9
|
+
conditions: RuleCondition[];
|
|
10
|
+
actions: RuleAction[];
|
|
11
|
+
}
|
|
12
|
+
/** The actions builder: only the four types the engine can actually dispatch (see automationRuleTypes.ts). */
|
|
13
|
+
export declare function ActionsEditor({ actions, onChange, }: {
|
|
14
|
+
actions: RuleAction[];
|
|
15
|
+
onChange: (next: RuleAction[]) => void;
|
|
16
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
/** The conditions builder. A rule with no conditions always matches — the gate is opt-in (engine default). */
|
|
18
|
+
export declare function ConditionsEditor({ conditions, onChange, }: {
|
|
19
|
+
conditions: RuleCondition[];
|
|
20
|
+
onChange: (next: RuleCondition[]) => void;
|
|
21
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
/** Name, description, project, trigger, conditions and actions — the fields create and edit share. */
|
|
23
|
+
export declare function AutomationRuleFields({ form, onChange, projectLocked, }: {
|
|
24
|
+
form: AutomationRuleFormState;
|
|
25
|
+
onChange: (next: AutomationRuleFormState) => void;
|
|
26
|
+
/** The edit page cannot change the project (the API accepts no `projectId` on update). */
|
|
27
|
+
projectLocked?: boolean;
|
|
28
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
29
|
+
//# sourceMappingURL=AutomationRuleFields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutomationRuleFields.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/automation/AutomationRuleFields.tsx"],"names":[],"mappings":"AASA,OAAO,EAWL,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,uBAAuB,CAAC;AAE/B,+DAA+D;AAC/D,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AA0DD,8GAA8G;AAC9G,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,IAAI,CAAC;CACxC,2CA0EA;AAED,8GAA8G;AAC9G,wBAAgB,gBAAgB,CAAC,EAC/B,UAAU,EACV,QAAQ,GACT,EAAE;IACD,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;CAC3C,2CA4EA;AAED,sGAAsG;AACtG,wBAAgB,oBAAoB,CAAC,EACnC,IAAI,EACJ,QAAQ,EACR,aAAqB,GACtB,EAAE;IACD,IAAI,EAAE,uBAAuB,CAAC;IAC9B,QAAQ,EAAE,CAAC,IAAI,EAAE,uBAAuB,KAAK,IAAI,CAAC;IAClD,0FAA0F;IAC1F,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,2CA6FA"}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { ProjectSelect as e } from "../controls/Pickers.js";
|
|
2
|
+
import { AssigneeSelect as t, WORK_ITEM_PRIORITIES as n, WORK_ITEM_STATUSES as r, enumLabel as i } from "../controls/WorkItemControls.js";
|
|
3
|
+
import { ACTION_TYPES as a, ACTION_TYPE_LABEL as o, AUTOMATIC_TRIGGER_TYPES as s, CONDITION_FIELDS as c, CONDITION_OPERATORS as l, CONDITION_OPERATOR_LABEL as u, TRIGGER_TYPES as d, TRIGGER_TYPE_LABEL as f } from "./automationRuleTypes.js";
|
|
4
|
+
import { Plus as p, X as m } from "lucide-react";
|
|
5
|
+
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
6
|
+
import { Button as _, Input as v } from "@burdenoff/fe-libs/ui";
|
|
7
|
+
//#region src/planmagnet/automation/AutomationRuleFields.tsx
|
|
8
|
+
var y = "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60";
|
|
9
|
+
function b({ action: e, onChange: a }) {
|
|
10
|
+
switch (e.type) {
|
|
11
|
+
case "ASSIGN_TO_USER": return /* @__PURE__ */ h(t, {
|
|
12
|
+
value: e.value,
|
|
13
|
+
onChange: a
|
|
14
|
+
});
|
|
15
|
+
case "SET_STATUS": return /* @__PURE__ */ g("select", {
|
|
16
|
+
className: y,
|
|
17
|
+
value: e.value,
|
|
18
|
+
onChange: (e) => a(e.target.value),
|
|
19
|
+
children: [/* @__PURE__ */ h("option", {
|
|
20
|
+
value: "",
|
|
21
|
+
children: "Choose a status"
|
|
22
|
+
}), r.map((e) => /* @__PURE__ */ h("option", {
|
|
23
|
+
value: e,
|
|
24
|
+
children: i(e)
|
|
25
|
+
}, e))]
|
|
26
|
+
});
|
|
27
|
+
case "SET_PRIORITY": return /* @__PURE__ */ g("select", {
|
|
28
|
+
className: y,
|
|
29
|
+
value: e.value,
|
|
30
|
+
onChange: (e) => a(e.target.value),
|
|
31
|
+
children: [/* @__PURE__ */ h("option", {
|
|
32
|
+
value: "",
|
|
33
|
+
children: "Choose a priority"
|
|
34
|
+
}), n.map((e) => /* @__PURE__ */ h("option", {
|
|
35
|
+
value: e,
|
|
36
|
+
children: i(e)
|
|
37
|
+
}, e))]
|
|
38
|
+
});
|
|
39
|
+
default: return /* @__PURE__ */ h(v, {
|
|
40
|
+
"aria-label": "Label",
|
|
41
|
+
placeholder: "e.g. needs-review",
|
|
42
|
+
value: e.value,
|
|
43
|
+
onChange: (e) => a(e.target.value)
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function x({ actions: e, onChange: t }) {
|
|
48
|
+
let n = (n, r) => t(e.map((e, t) => t === n ? {
|
|
49
|
+
...e,
|
|
50
|
+
...r
|
|
51
|
+
} : e)), r = (n) => t(e.filter((e, t) => t !== n));
|
|
52
|
+
return /* @__PURE__ */ g("div", {
|
|
53
|
+
className: "space-y-2",
|
|
54
|
+
children: [
|
|
55
|
+
e.map((e, t) => {
|
|
56
|
+
let i = a.includes(e.type), s = i ? a : [e.type, ...a];
|
|
57
|
+
return /* @__PURE__ */ g("div", {
|
|
58
|
+
className: "space-y-1",
|
|
59
|
+
children: [/* @__PURE__ */ g("div", {
|
|
60
|
+
className: "flex items-start gap-2",
|
|
61
|
+
children: [
|
|
62
|
+
/* @__PURE__ */ h("select", {
|
|
63
|
+
"aria-label": "Action type",
|
|
64
|
+
className: `${y} mt-0 w-40 shrink-0`,
|
|
65
|
+
value: e.type,
|
|
66
|
+
onChange: (r) => n(t, {
|
|
67
|
+
type: r.target.value,
|
|
68
|
+
value: r.target.value === e.type ? e.value : ""
|
|
69
|
+
}),
|
|
70
|
+
children: s.map((t) => /* @__PURE__ */ h("option", {
|
|
71
|
+
value: t,
|
|
72
|
+
children: i || t !== e.type ? o[t] ?? t : t
|
|
73
|
+
}, t))
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ h("div", {
|
|
76
|
+
className: "min-w-0 flex-1",
|
|
77
|
+
children: /* @__PURE__ */ h(b, {
|
|
78
|
+
action: e,
|
|
79
|
+
onChange: (e) => n(t, { value: e })
|
|
80
|
+
})
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ h(_, {
|
|
83
|
+
type: "button",
|
|
84
|
+
size: "sm",
|
|
85
|
+
variant: "ghost",
|
|
86
|
+
"aria-label": "Remove action",
|
|
87
|
+
onClick: () => r(t),
|
|
88
|
+
children: /* @__PURE__ */ h(m, { className: "h-4 w-4" })
|
|
89
|
+
})
|
|
90
|
+
]
|
|
91
|
+
}), !i && /* @__PURE__ */ h("p", {
|
|
92
|
+
className: "text-xs text-muted-foreground",
|
|
93
|
+
children: "This action type is not run by the engine yet; the rule keeps it but never dispatches it."
|
|
94
|
+
})]
|
|
95
|
+
}, t);
|
|
96
|
+
}),
|
|
97
|
+
/* @__PURE__ */ g(_, {
|
|
98
|
+
type: "button",
|
|
99
|
+
size: "sm",
|
|
100
|
+
variant: "outline",
|
|
101
|
+
onClick: () => t([...e, {
|
|
102
|
+
type: "ASSIGN_TO_USER",
|
|
103
|
+
value: ""
|
|
104
|
+
}]),
|
|
105
|
+
"data-testid": "automation-add-action",
|
|
106
|
+
children: [/* @__PURE__ */ h(p, { className: "mr-1 h-4 w-4" }), "Add action"]
|
|
107
|
+
}),
|
|
108
|
+
e.length === 0 && /* @__PURE__ */ h("p", {
|
|
109
|
+
className: "text-xs text-muted-foreground",
|
|
110
|
+
children: "A rule with no actions still records that it ran, but changes nothing."
|
|
111
|
+
})
|
|
112
|
+
]
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function S({ conditions: e, onChange: t }) {
|
|
116
|
+
let n = (n, r) => t(e.map((e, t) => t === n ? {
|
|
117
|
+
...e,
|
|
118
|
+
...r
|
|
119
|
+
} : e)), r = (n) => t(e.filter((e, t) => t !== n));
|
|
120
|
+
return /* @__PURE__ */ g("div", {
|
|
121
|
+
className: "space-y-2",
|
|
122
|
+
children: [
|
|
123
|
+
e.map((e, t) => /* @__PURE__ */ g("div", {
|
|
124
|
+
className: "flex items-start gap-2",
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ h(v, {
|
|
127
|
+
"aria-label": "Condition field",
|
|
128
|
+
list: "automation-condition-fields",
|
|
129
|
+
className: "w-36 shrink-0",
|
|
130
|
+
placeholder: "field",
|
|
131
|
+
value: e.field,
|
|
132
|
+
onChange: (e) => n(t, { field: e.target.value })
|
|
133
|
+
}),
|
|
134
|
+
/* @__PURE__ */ h("select", {
|
|
135
|
+
"aria-label": "Condition operator",
|
|
136
|
+
className: `${y} mt-0 w-32 shrink-0`,
|
|
137
|
+
value: e.operator,
|
|
138
|
+
onChange: (e) => n(t, { operator: e.target.value }),
|
|
139
|
+
children: l.map((e) => /* @__PURE__ */ h("option", {
|
|
140
|
+
value: e,
|
|
141
|
+
children: u[e]
|
|
142
|
+
}, e))
|
|
143
|
+
}),
|
|
144
|
+
e.operator !== "exists" && /* @__PURE__ */ h(v, {
|
|
145
|
+
"aria-label": "Condition value",
|
|
146
|
+
className: "min-w-0 flex-1",
|
|
147
|
+
placeholder: e.operator === "in" || e.operator === "notIn" ? "comma, separated, values" : "value",
|
|
148
|
+
value: e.value,
|
|
149
|
+
onChange: (e) => n(t, { value: e.target.value })
|
|
150
|
+
}),
|
|
151
|
+
/* @__PURE__ */ h(_, {
|
|
152
|
+
type: "button",
|
|
153
|
+
size: "sm",
|
|
154
|
+
variant: "ghost",
|
|
155
|
+
"aria-label": "Remove condition",
|
|
156
|
+
onClick: () => r(t),
|
|
157
|
+
children: /* @__PURE__ */ h(m, { className: "h-4 w-4" })
|
|
158
|
+
})
|
|
159
|
+
]
|
|
160
|
+
}, t)),
|
|
161
|
+
/* @__PURE__ */ h("datalist", {
|
|
162
|
+
id: "automation-condition-fields",
|
|
163
|
+
children: c.map((e) => /* @__PURE__ */ h("option", { value: e }, e))
|
|
164
|
+
}),
|
|
165
|
+
/* @__PURE__ */ g(_, {
|
|
166
|
+
type: "button",
|
|
167
|
+
size: "sm",
|
|
168
|
+
variant: "outline",
|
|
169
|
+
onClick: () => t([...e, {
|
|
170
|
+
field: "status",
|
|
171
|
+
operator: "eq",
|
|
172
|
+
value: ""
|
|
173
|
+
}]),
|
|
174
|
+
"data-testid": "automation-add-condition",
|
|
175
|
+
children: [/* @__PURE__ */ h(p, { className: "mr-1 h-4 w-4" }), "Add condition"]
|
|
176
|
+
}),
|
|
177
|
+
e.length === 0 && /* @__PURE__ */ h("p", {
|
|
178
|
+
className: "text-xs text-muted-foreground",
|
|
179
|
+
children: "No conditions: the rule matches every event."
|
|
180
|
+
})
|
|
181
|
+
]
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function C({ form: t, onChange: n, projectLocked: r = !1 }) {
|
|
185
|
+
return /* @__PURE__ */ g("div", {
|
|
186
|
+
className: "space-y-4",
|
|
187
|
+
children: [
|
|
188
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
189
|
+
htmlFor: "automation-name",
|
|
190
|
+
className: "text-sm font-medium",
|
|
191
|
+
children: "Name"
|
|
192
|
+
}), /* @__PURE__ */ h(v, {
|
|
193
|
+
id: "automation-name",
|
|
194
|
+
className: "mt-1",
|
|
195
|
+
value: t.name,
|
|
196
|
+
onChange: (e) => n({
|
|
197
|
+
...t,
|
|
198
|
+
name: e.target.value
|
|
199
|
+
}),
|
|
200
|
+
placeholder: "e.g. Assign new bugs to triage"
|
|
201
|
+
})] }),
|
|
202
|
+
/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
203
|
+
htmlFor: "automation-description",
|
|
204
|
+
className: "text-sm font-medium",
|
|
205
|
+
children: "Description"
|
|
206
|
+
}), /* @__PURE__ */ h("textarea", {
|
|
207
|
+
id: "automation-description",
|
|
208
|
+
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[72px]",
|
|
209
|
+
value: t.description,
|
|
210
|
+
onChange: (e) => n({
|
|
211
|
+
...t,
|
|
212
|
+
description: e.target.value
|
|
213
|
+
}),
|
|
214
|
+
placeholder: "What this rule is for"
|
|
215
|
+
})] }),
|
|
216
|
+
/* @__PURE__ */ g("div", {
|
|
217
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2",
|
|
218
|
+
children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("label", {
|
|
219
|
+
htmlFor: "automation-project",
|
|
220
|
+
className: "text-sm font-medium",
|
|
221
|
+
children: "Project"
|
|
222
|
+
}), r ? /* @__PURE__ */ h("p", {
|
|
223
|
+
className: "mt-1 text-sm text-muted-foreground",
|
|
224
|
+
children: "A rule's project cannot be changed after it is created."
|
|
225
|
+
}) : /* @__PURE__ */ h("div", {
|
|
226
|
+
className: "mt-1",
|
|
227
|
+
children: /* @__PURE__ */ h(e, {
|
|
228
|
+
id: "automation-project",
|
|
229
|
+
value: t.projectId,
|
|
230
|
+
onChange: (e) => n({
|
|
231
|
+
...t,
|
|
232
|
+
projectId: e
|
|
233
|
+
})
|
|
234
|
+
})
|
|
235
|
+
})] }), /* @__PURE__ */ g("div", { children: [
|
|
236
|
+
/* @__PURE__ */ h("label", {
|
|
237
|
+
htmlFor: "automation-trigger",
|
|
238
|
+
className: "text-sm font-medium",
|
|
239
|
+
children: "Trigger"
|
|
240
|
+
}),
|
|
241
|
+
/* @__PURE__ */ h("select", {
|
|
242
|
+
id: "automation-trigger",
|
|
243
|
+
className: y,
|
|
244
|
+
value: t.triggerType,
|
|
245
|
+
onChange: (e) => n({
|
|
246
|
+
...t,
|
|
247
|
+
triggerType: e.target.value
|
|
248
|
+
}),
|
|
249
|
+
children: d.map((e) => /* @__PURE__ */ g("option", {
|
|
250
|
+
value: e,
|
|
251
|
+
children: [f[e], s.has(e) ? "" : " (not yet automatic)"]
|
|
252
|
+
}, e))
|
|
253
|
+
}),
|
|
254
|
+
!s.has(t.triggerType) && /* @__PURE__ */ g("p", {
|
|
255
|
+
className: "mt-1 text-xs text-muted-foreground",
|
|
256
|
+
children: [
|
|
257
|
+
"This trigger is saved but does not fire on its own yet — use",
|
|
258
|
+
" ",
|
|
259
|
+
/* @__PURE__ */ h("span", {
|
|
260
|
+
className: "font-medium",
|
|
261
|
+
children: "Run now"
|
|
262
|
+
}),
|
|
263
|
+
" to run it against a work item."
|
|
264
|
+
]
|
|
265
|
+
})
|
|
266
|
+
] })]
|
|
267
|
+
}),
|
|
268
|
+
/* @__PURE__ */ g("div", { children: [
|
|
269
|
+
/* @__PURE__ */ h("p", {
|
|
270
|
+
className: "text-sm font-medium",
|
|
271
|
+
children: "Conditions"
|
|
272
|
+
}),
|
|
273
|
+
/* @__PURE__ */ h("p", {
|
|
274
|
+
className: "mb-2 text-xs text-muted-foreground",
|
|
275
|
+
children: "All conditions must match. Leave empty to match every event."
|
|
276
|
+
}),
|
|
277
|
+
/* @__PURE__ */ h(S, {
|
|
278
|
+
conditions: t.conditions,
|
|
279
|
+
onChange: (e) => n({
|
|
280
|
+
...t,
|
|
281
|
+
conditions: e
|
|
282
|
+
})
|
|
283
|
+
})
|
|
284
|
+
] }),
|
|
285
|
+
/* @__PURE__ */ g("div", { children: [
|
|
286
|
+
/* @__PURE__ */ h("p", {
|
|
287
|
+
className: "text-sm font-medium",
|
|
288
|
+
children: "Actions"
|
|
289
|
+
}),
|
|
290
|
+
/* @__PURE__ */ h("p", {
|
|
291
|
+
className: "mb-2 text-xs text-muted-foreground",
|
|
292
|
+
children: "Run in order when the conditions match."
|
|
293
|
+
}),
|
|
294
|
+
/* @__PURE__ */ h(x, {
|
|
295
|
+
actions: t.actions,
|
|
296
|
+
onChange: (e) => n({
|
|
297
|
+
...t,
|
|
298
|
+
actions: e
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
] })
|
|
302
|
+
]
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
//#endregion
|
|
306
|
+
export { C as AutomationRuleFields };
|
|
307
|
+
|
|
308
|
+
//# sourceMappingURL=AutomationRuleFields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutomationRuleFields.js","names":[],"sources":["../../../src/planmagnet/automation/AutomationRuleFields.tsx"],"sourcesContent":["import { Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Plus, X } from 'lucide-react';\nimport {\n AssigneeSelect,\n WORK_ITEM_PRIORITIES,\n WORK_ITEM_STATUSES,\n enumLabel,\n} from '../controls/WorkItemControls';\nimport { ProjectSelect } from '../controls/Pickers';\nimport {\n ACTION_TYPES,\n ACTION_TYPE_LABEL,\n AUTOMATIC_TRIGGER_TYPES,\n CONDITION_FIELDS,\n CONDITION_OPERATORS,\n CONDITION_OPERATOR_LABEL,\n TRIGGER_TYPES,\n TRIGGER_TYPE_LABEL,\n type ActionType,\n type ConditionOperator,\n type RuleAction,\n type RuleCondition,\n type TriggerType,\n} from './automationRuleTypes';\n\n/** The editable shape both the create and edit pages share. */\nexport interface AutomationRuleFormState {\n name: string;\n description: string;\n projectId: string;\n triggerType: TriggerType;\n conditions: RuleCondition[];\n actions: RuleAction[];\n}\n\nconst fieldClass =\n 'mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm disabled:opacity-60';\n\nfunction ActionValueEditor({\n action,\n onChange,\n}: {\n action: RuleAction;\n onChange: (value: string) => void;\n}) {\n switch (action.type) {\n case 'ASSIGN_TO_USER':\n return <AssigneeSelect value={action.value} onChange={onChange} />;\n case 'SET_STATUS':\n return (\n <select\n className={fieldClass}\n value={action.value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">Choose a status</option>\n {WORK_ITEM_STATUSES.map((s) => (\n <option key={s} value={s}>\n {enumLabel(s)}\n </option>\n ))}\n </select>\n );\n case 'SET_PRIORITY':\n return (\n <select\n className={fieldClass}\n value={action.value}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">Choose a priority</option>\n {WORK_ITEM_PRIORITIES.map((p) => (\n <option key={p} value={p}>\n {enumLabel(p)}\n </option>\n ))}\n </select>\n );\n case 'ADD_LABEL':\n default:\n return (\n <Input\n aria-label=\"Label\"\n placeholder=\"e.g. needs-review\"\n value={action.value}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n }\n}\n\n/** The actions builder: only the four types the engine can actually dispatch (see automationRuleTypes.ts). */\nexport function ActionsEditor({\n actions,\n onChange,\n}: {\n actions: RuleAction[];\n onChange: (next: RuleAction[]) => void;\n}) {\n const update = (index: number, patch: Partial<RuleAction>) =>\n onChange(actions.map((a, i) => (i === index ? { ...a, ...patch } : a)));\n const remove = (index: number) => onChange(actions.filter((_, i) => i !== index));\n const add = () => onChange([...actions, { type: 'ASSIGN_TO_USER', value: '' }]);\n\n return (\n <div className=\"space-y-2\">\n {actions.map((action, index) => {\n // A rule created before this UI existed (or via the API directly) can carry an action type this\n // builder does not offer (e.g. POST_COMMENT, which the engine never dispatches — see\n // automationRuleTypes.ts). Keep it selectable and visible rather than silently swapping it out from\n // under the user the moment they open the edit page.\n const known = (ACTION_TYPES as readonly string[]).includes(action.type);\n const typeOptions = known ? ACTION_TYPES : [action.type, ...ACTION_TYPES];\n return (\n <div key={index} className=\"space-y-1\">\n <div className=\"flex items-start gap-2\">\n <select\n aria-label=\"Action type\"\n className={`${fieldClass} mt-0 w-40 shrink-0`}\n value={action.type}\n onChange={(e) =>\n update(index, {\n type: e.target.value as ActionType,\n value: e.target.value === action.type ? action.value : '',\n })\n }\n >\n {typeOptions.map((t) => (\n <option key={t} value={t}>\n {known || t !== action.type ? (ACTION_TYPE_LABEL[t as ActionType] ?? t) : t}\n </option>\n ))}\n </select>\n <div className=\"min-w-0 flex-1\">\n <ActionValueEditor action={action} onChange={(value) => update(index, { value })} />\n </div>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label=\"Remove action\"\n onClick={() => remove(index)}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n {!known && (\n <p className=\"text-xs text-muted-foreground\">\n This action type is not run by the engine yet; the rule keeps it but never\n dispatches it.\n </p>\n )}\n </div>\n );\n })}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={add}\n data-testid=\"automation-add-action\"\n >\n <Plus className=\"mr-1 h-4 w-4\" />\n Add action\n </Button>\n {actions.length === 0 && (\n <p className=\"text-xs text-muted-foreground\">\n A rule with no actions still records that it ran, but changes nothing.\n </p>\n )}\n </div>\n );\n}\n\n/** The conditions builder. A rule with no conditions always matches — the gate is opt-in (engine default). */\nexport function ConditionsEditor({\n conditions,\n onChange,\n}: {\n conditions: RuleCondition[];\n onChange: (next: RuleCondition[]) => void;\n}) {\n const update = (index: number, patch: Partial<RuleCondition>) =>\n onChange(conditions.map((c, i) => (i === index ? { ...c, ...patch } : c)));\n const remove = (index: number) => onChange(conditions.filter((_, i) => i !== index));\n const add = () => onChange([...conditions, { field: 'status', operator: 'eq', value: '' }]);\n\n return (\n <div className=\"space-y-2\">\n {conditions.map((condition, index) => (\n <div key={index} className=\"flex items-start gap-2\">\n <Input\n aria-label=\"Condition field\"\n list=\"automation-condition-fields\"\n className=\"w-36 shrink-0\"\n placeholder=\"field\"\n value={condition.field}\n onChange={(e) => update(index, { field: e.target.value })}\n />\n <select\n aria-label=\"Condition operator\"\n className={`${fieldClass} mt-0 w-32 shrink-0`}\n value={condition.operator}\n onChange={(e) => update(index, { operator: e.target.value as ConditionOperator })}\n >\n {CONDITION_OPERATORS.map((op) => (\n <option key={op} value={op}>\n {CONDITION_OPERATOR_LABEL[op]}\n </option>\n ))}\n </select>\n {condition.operator !== 'exists' && (\n <Input\n aria-label=\"Condition value\"\n className=\"min-w-0 flex-1\"\n placeholder={\n condition.operator === 'in' || condition.operator === 'notIn'\n ? 'comma, separated, values'\n : 'value'\n }\n value={condition.value}\n onChange={(e) => update(index, { value: e.target.value })}\n />\n )}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label=\"Remove condition\"\n onClick={() => remove(index)}\n >\n <X className=\"h-4 w-4\" />\n </Button>\n </div>\n ))}\n <datalist id=\"automation-condition-fields\">\n {CONDITION_FIELDS.map((f) => (\n <option key={f} value={f} />\n ))}\n </datalist>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"outline\"\n onClick={add}\n data-testid=\"automation-add-condition\"\n >\n <Plus className=\"mr-1 h-4 w-4\" />\n Add condition\n </Button>\n {conditions.length === 0 && (\n <p className=\"text-xs text-muted-foreground\">\n No conditions: the rule matches every event.\n </p>\n )}\n </div>\n );\n}\n\n/** Name, description, project, trigger, conditions and actions — the fields create and edit share. */\nexport function AutomationRuleFields({\n form,\n onChange,\n projectLocked = false,\n}: {\n form: AutomationRuleFormState;\n onChange: (next: AutomationRuleFormState) => void;\n /** The edit page cannot change the project (the API accepts no `projectId` on update). */\n projectLocked?: boolean;\n}) {\n return (\n <div className=\"space-y-4\">\n <div>\n <label htmlFor=\"automation-name\" className=\"text-sm font-medium\">\n Name\n </label>\n <Input\n id=\"automation-name\"\n className=\"mt-1\"\n value={form.name}\n onChange={(e) => onChange({ ...form, name: e.target.value })}\n placeholder=\"e.g. Assign new bugs to triage\"\n />\n </div>\n <div>\n <label htmlFor=\"automation-description\" className=\"text-sm font-medium\">\n Description\n </label>\n <textarea\n id=\"automation-description\"\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[72px]\"\n value={form.description}\n onChange={(e) => onChange({ ...form, description: e.target.value })}\n placeholder=\"What this rule is for\"\n />\n </div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"automation-project\" className=\"text-sm font-medium\">\n Project\n </label>\n {projectLocked ? (\n <p className=\"mt-1 text-sm text-muted-foreground\">\n A rule's project cannot be changed after it is created.\n </p>\n ) : (\n <div className=\"mt-1\">\n <ProjectSelect\n id=\"automation-project\"\n value={form.projectId}\n onChange={(projectId) => onChange({ ...form, projectId })}\n />\n </div>\n )}\n </div>\n <div>\n <label htmlFor=\"automation-trigger\" className=\"text-sm font-medium\">\n Trigger\n </label>\n <select\n id=\"automation-trigger\"\n className={fieldClass}\n value={form.triggerType}\n onChange={(e) => onChange({ ...form, triggerType: e.target.value as TriggerType })}\n >\n {TRIGGER_TYPES.map((t) => (\n <option key={t} value={t}>\n {TRIGGER_TYPE_LABEL[t]}\n {AUTOMATIC_TRIGGER_TYPES.has(t) ? '' : ' (not yet automatic)'}\n </option>\n ))}\n </select>\n {!AUTOMATIC_TRIGGER_TYPES.has(form.triggerType) && (\n <p className=\"mt-1 text-xs text-muted-foreground\">\n This trigger is saved but does not fire on its own yet — use{' '}\n <span className=\"font-medium\">Run now</span> to run it against a work item.\n </p>\n )}\n </div>\n </div>\n <div>\n <p className=\"text-sm font-medium\">Conditions</p>\n <p className=\"mb-2 text-xs text-muted-foreground\">\n All conditions must match. Leave empty to match every event.\n </p>\n <ConditionsEditor\n conditions={form.conditions}\n onChange={(conditions) => onChange({ ...form, conditions })}\n />\n </div>\n <div>\n <p className=\"text-sm font-medium\">Actions</p>\n <p className=\"mb-2 text-xs text-muted-foreground\">\n Run in order when the conditions match.\n </p>\n <ActionsEditor\n actions={form.actions}\n onChange={(actions) => onChange({ ...form, actions })}\n />\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AAmCA,IAAM,IACJ;AAEF,SAAS,EAAkB,EACzB,WACA,eAIC;AACD,SAAQ,EAAO,MAAf;EACE,KAAK,iBACH,QAAO,kBAAC,GAAD;GAAgB,OAAO,EAAO;GAAiB;GAAY,CAAA;EACpE,KAAK,aACH,QACE,kBAAC,UAAD;GACE,WAAW;GACX,OAAO,EAAO;GACd,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;aAH3C,CAKE,kBAAC,UAAD;IAAQ,OAAM;cAAG;IAAwB,CAAA,EACxC,EAAmB,KAAK,MACvB,kBAAC,UAAD;IAAgB,OAAO;cACpB,EAAU,EAAE;IACN,EAFI,EAEJ,CACT,CACK;;EAEb,KAAK,eACH,QACE,kBAAC,UAAD;GACE,WAAW;GACX,OAAO,EAAO;GACd,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;aAH3C,CAKE,kBAAC,UAAD;IAAQ,OAAM;cAAG;IAA0B,CAAA,EAC1C,EAAqB,KAAK,MACzB,kBAAC,UAAD;IAAgB,OAAO;cACpB,EAAU,EAAE;IACN,EAFI,EAEJ,CACT,CACK;;EAGb,QACE,QACE,kBAAC,GAAD;GACE,cAAW;GACX,aAAY;GACZ,OAAO,EAAO;GACd,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;GACzC,CAAA;;;AAMV,SAAgB,EAAc,EAC5B,YACA,eAIC;CACD,IAAM,KAAU,GAAe,MAC7B,EAAS,EAAQ,KAAK,GAAG,MAAO,MAAM,IAAQ;EAAE,GAAG;EAAG,GAAG;EAAO,GAAG,EAAG,CAAC,EACnE,KAAU,MAAkB,EAAS,EAAQ,QAAQ,GAAG,MAAM,MAAM,EAAM,CAAC;AAGjF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACG,EAAQ,KAAK,GAAQ,MAAU;IAK9B,IAAM,IAAS,EAAmC,SAAS,EAAO,KAAK,EACjE,IAAc,IAAQ,IAAe,CAAC,EAAO,MAAM,GAAG,EAAa;AACzE,WACE,kBAAC,OAAD;KAAiB,WAAU;eAA3B,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,UAAD;QACE,cAAW;QACX,WAAW,GAAG,EAAW;QACzB,OAAO,EAAO;QACd,WAAW,MACT,EAAO,GAAO;SACZ,MAAM,EAAE,OAAO;SACf,OAAO,EAAE,OAAO,UAAU,EAAO,OAAO,EAAO,QAAQ;SACxD,CAAC;kBAGH,EAAY,KAAK,MAChB,kBAAC,UAAD;SAAgB,OAAO;mBACpB,KAAS,MAAM,EAAO,OAAQ,EAAkB,MAAoB,IAAK;SACnE,EAFI,EAEJ,CACT;QACK,CAAA;OACT,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD;SAA2B;SAAQ,WAAW,MAAU,EAAO,GAAO,EAAE,UAAO,CAAC;SAAI,CAAA;QAChF,CAAA;OACN,kBAAC,GAAD;QACE,MAAK;QACL,MAAK;QACL,SAAQ;QACR,cAAW;QACX,eAAe,EAAO,EAAM;kBAE5B,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;QAClB,CAAA;OACL;SACL,CAAC,KACA,kBAAC,KAAD;MAAG,WAAU;gBAAgC;MAGzC,CAAA,CAEF;OAtCI,EAsCJ;KAER;GACF,kBAAC,GAAD;IACE,MAAK;IACL,MAAK;IACL,SAAQ;IACR,eAzDY,EAAS,CAAC,GAAG,GAAS;KAAE,MAAM;KAAkB,OAAO;KAAI,CAAC,CAAC;IA0DzE,eAAY;cALd,CAOE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,aAE1B;;GACR,EAAQ,WAAW,KAClB,kBAAC,KAAD;IAAG,WAAU;cAAgC;IAEzC,CAAA;GAEF;;;AAKV,SAAgB,EAAiB,EAC/B,eACA,eAIC;CACD,IAAM,KAAU,GAAe,MAC7B,EAAS,EAAW,KAAK,GAAG,MAAO,MAAM,IAAQ;EAAE,GAAG;EAAG,GAAG;EAAO,GAAG,EAAG,CAAC,EACtE,KAAU,MAAkB,EAAS,EAAW,QAAQ,GAAG,MAAM,MAAM,EAAM,CAAC;AAGpF,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACG,EAAW,KAAK,GAAW,MAC1B,kBAAC,OAAD;IAAiB,WAAU;cAA3B;KACE,kBAAC,GAAD;MACE,cAAW;MACX,MAAK;MACL,WAAU;MACV,aAAY;MACZ,OAAO,EAAU;MACjB,WAAW,MAAM,EAAO,GAAO,EAAE,OAAO,EAAE,OAAO,OAAO,CAAC;MACzD,CAAA;KACF,kBAAC,UAAD;MACE,cAAW;MACX,WAAW,GAAG,EAAW;MACzB,OAAO,EAAU;MACjB,WAAW,MAAM,EAAO,GAAO,EAAE,UAAU,EAAE,OAAO,OAA4B,CAAC;gBAEhF,EAAoB,KAAK,MACxB,kBAAC,UAAD;OAAiB,OAAO;iBACrB,EAAyB;OACnB,EAFI,EAEJ,CACT;MACK,CAAA;KACR,EAAU,aAAa,YACtB,kBAAC,GAAD;MACE,cAAW;MACX,WAAU;MACV,aACE,EAAU,aAAa,QAAQ,EAAU,aAAa,UAClD,6BACA;MAEN,OAAO,EAAU;MACjB,WAAW,MAAM,EAAO,GAAO,EAAE,OAAO,EAAE,OAAO,OAAO,CAAC;MACzD,CAAA;KAEJ,kBAAC,GAAD;MACE,MAAK;MACL,MAAK;MACL,SAAQ;MACR,cAAW;MACX,eAAe,EAAO,EAAM;gBAE5B,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;MAClB,CAAA;KACL;MA3CI,EA2CJ,CACN;GACF,kBAAC,YAAD;IAAU,IAAG;cACV,EAAiB,KAAK,MACrB,kBAAC,UAAD,EAAgB,OAAO,GAAK,EAAf,EAAe,CAC5B;IACO,CAAA;GACX,kBAAC,GAAD;IACE,MAAK;IACL,MAAK;IACL,SAAQ;IACR,eA3DY,EAAS,CAAC,GAAG,GAAY;KAAE,OAAO;KAAU,UAAU;KAAM,OAAO;KAAI,CAAC,CAAC;IA4DrF,eAAY;cALd,CAOE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,gBAE1B;;GACR,EAAW,WAAW,KACrB,kBAAC,KAAD;IAAG,WAAU;cAAgC;IAEzC,CAAA;GAEF;;;AAKV,SAAgB,EAAqB,EACnC,SACA,aACA,mBAAgB,MAMf;AACD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,SAAQ;IAAkB,WAAU;cAAsB;IAEzD,CAAA,EACR,kBAAC,GAAD;IACE,IAAG;IACH,WAAU;IACV,OAAO,EAAK;IACZ,WAAW,MAAM,EAAS;KAAE,GAAG;KAAM,MAAM,EAAE,OAAO;KAAO,CAAC;IAC5D,aAAY;IACZ,CAAA,CACE,EAAA,CAAA;GACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;IAAO,SAAQ;IAAyB,WAAU;cAAsB;IAEhE,CAAA,EACR,kBAAC,YAAD;IACE,IAAG;IACH,WAAU;IACV,OAAO,EAAK;IACZ,WAAW,MAAM,EAAS;KAAE,GAAG;KAAM,aAAa,EAAE,OAAO;KAAO,CAAC;IACnE,aAAY;IACZ,CAAA,CACE,EAAA,CAAA;GACN,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;KAAO,SAAQ;KAAqB,WAAU;eAAsB;KAE5D,CAAA,EACP,IACC,kBAAC,KAAD;KAAG,WAAU;eAAqC;KAE9C,CAAA,GAEJ,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MACE,IAAG;MACH,OAAO,EAAK;MACZ,WAAW,MAAc,EAAS;OAAE,GAAG;OAAM;OAAW,CAAC;MACzD,CAAA;KACE,CAAA,CAEJ,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA;KACE,kBAAC,SAAD;MAAO,SAAQ;MAAqB,WAAU;gBAAsB;MAE5D,CAAA;KACR,kBAAC,UAAD;MACE,IAAG;MACH,WAAW;MACX,OAAO,EAAK;MACZ,WAAW,MAAM,EAAS;OAAE,GAAG;OAAM,aAAa,EAAE,OAAO;OAAsB,CAAC;gBAEjF,EAAc,KAAK,MAClB,kBAAC,UAAD;OAAgB,OAAO;iBAAvB,CACG,EAAmB,IACnB,EAAwB,IAAI,EAAE,GAAG,KAAK,uBAChC;SAHI,EAGJ,CACT;MACK,CAAA;KACR,CAAC,EAAwB,IAAI,EAAK,YAAY,IAC7C,kBAAC,KAAD;MAAG,WAAU;gBAAb;OAAkD;OACa;OAC7D,kBAAC,QAAD;QAAM,WAAU;kBAAc;QAAc,CAAA;;OAC1C;;KAEF,EAAA,CAAA,CACF;;GACN,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,KAAD;KAAG,WAAU;eAAsB;KAAc,CAAA;IACjD,kBAAC,KAAD;KAAG,WAAU;eAAqC;KAE9C,CAAA;IACJ,kBAAC,GAAD;KACE,YAAY,EAAK;KACjB,WAAW,MAAe,EAAS;MAAE,GAAG;MAAM;MAAY,CAAC;KAC3D,CAAA;IACE,EAAA,CAAA;GACN,kBAAC,OAAD,EAAA,UAAA;IACE,kBAAC,KAAD;KAAG,WAAU;eAAsB;KAAW,CAAA;IAC9C,kBAAC,KAAD;KAAG,WAAU;eAAqC;KAE9C,CAAA;IACJ,kBAAC,GAAD;KACE,SAAS,EAAK;KACd,WAAW,MAAY,EAAS;MAAE,GAAG;MAAM;MAAS,CAAC;KACrD,CAAA;IACE,EAAA,CAAA;GACF"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automation rules (BOFF-8047). Shared trigger/condition/action vocabulary, kept in one place so the create
|
|
3
|
+
* page, the edit page and the list's summaries can never drift from each other or from the engine.
|
|
4
|
+
*
|
|
5
|
+
* Scope note (from `automation-engine.ts`, the source of truth): only two triggers fire automatically today —
|
|
6
|
+
* `WORK_ITEM_CREATED` and `WORK_ITEM_STATUS_CHANGED` — and only four action types can be dispatched —
|
|
7
|
+
* `ASSIGN_TO_USER`, `ADD_LABEL`, `SET_STATUS`, `SET_PRIORITY`. The other five trigger types are real schema
|
|
8
|
+
* values the service accepts and stores (so a rule can be prepared ahead of a future engine change), but they
|
|
9
|
+
* never fire on their own; "Run now" (`planmagnetExecuteAutomationRule`) works for a rule of ANY trigger type,
|
|
10
|
+
* including `MANUAL`, because it targets one named work item directly rather than listening for an event.
|
|
11
|
+
*
|
|
12
|
+
* The actions builder below offers ONLY the four dispatchable types: offering the others would create a rule
|
|
13
|
+
* whose own execution log immediately reports "declared action(s) are not supported" — a UI that can build a
|
|
14
|
+
* rule the backend documents as silently dropping is worse than not offering the option.
|
|
15
|
+
*/
|
|
16
|
+
export declare const AUTOMATIC_TRIGGER_TYPES: Set<string>;
|
|
17
|
+
export declare const TRIGGER_TYPES: readonly ["WORK_ITEM_CREATED", "WORK_ITEM_STATUS_CHANGED", "WORK_ITEM_UPDATED", "WORK_ITEM_ASSIGNED", "SPRINT_STARTED", "SPRINT_COMPLETED", "MILESTONE_DUE", "SCHEDULE", "WEBHOOK", "MANUAL"];
|
|
18
|
+
export type TriggerType = (typeof TRIGGER_TYPES)[number];
|
|
19
|
+
export declare const TRIGGER_TYPE_LABEL: Record<TriggerType, string>;
|
|
20
|
+
/** Looks up a trigger type's label; falls back to the raw value for one this UI does not yet know (forward
|
|
21
|
+
* compatible with a value the service adds later). Cast: `TRIGGER_TYPE_LABEL` is keyed by the known union, but
|
|
22
|
+
* a value read back from the API is a plain string. */
|
|
23
|
+
export declare function triggerTypeLabel(value: string): string;
|
|
24
|
+
export declare const RULE_STATUSES: readonly ["ACTIVE", "PAUSED", "DISABLED", "ERROR"];
|
|
25
|
+
export type RuleStatus = (typeof RULE_STATUSES)[number];
|
|
26
|
+
export declare const ACTION_TYPES: readonly ["ASSIGN_TO_USER", "ADD_LABEL", "SET_STATUS", "SET_PRIORITY"];
|
|
27
|
+
export type ActionType = (typeof ACTION_TYPES)[number];
|
|
28
|
+
export declare const ACTION_TYPE_LABEL: Record<ActionType, string>;
|
|
29
|
+
export interface RuleAction {
|
|
30
|
+
type: ActionType;
|
|
31
|
+
value: string;
|
|
32
|
+
}
|
|
33
|
+
export declare const CONDITION_OPERATORS: readonly ["eq", "neq", "in", "notIn", "contains", "gt", "gte", "lt", "lte", "exists"];
|
|
34
|
+
export type ConditionOperator = (typeof CONDITION_OPERATORS)[number];
|
|
35
|
+
export declare const CONDITION_OPERATOR_LABEL: Record<ConditionOperator, string>;
|
|
36
|
+
/** Fields present on every automatic trigger's snapshot (`TriggerData` in automation-engine.ts). */
|
|
37
|
+
export declare const CONDITION_FIELDS: readonly ["status", "previousStatus", "priority", "type", "assigneeId", "title", "labels", "sprintId", "projectId"];
|
|
38
|
+
export interface RuleCondition {
|
|
39
|
+
field: string;
|
|
40
|
+
operator: ConditionOperator;
|
|
41
|
+
/** Raw editor value; for `in`/`notIn` this is a comma-separated list, converted to an array on submit. */
|
|
42
|
+
value: string;
|
|
43
|
+
}
|
|
44
|
+
/** actions[] (form shape) -> actions JSON the API accepts. */
|
|
45
|
+
export declare function actionsToApi(actions: RuleAction[]): {
|
|
46
|
+
type: ActionType;
|
|
47
|
+
value: string;
|
|
48
|
+
}[];
|
|
49
|
+
/** conditions[] (form shape) -> conditions JSON the API accepts, or undefined when there are none. */
|
|
50
|
+
export declare function conditionsToApi(conditions: RuleCondition[]): {
|
|
51
|
+
field: string;
|
|
52
|
+
operator: ConditionOperator;
|
|
53
|
+
value?: unknown;
|
|
54
|
+
}[] | undefined;
|
|
55
|
+
/** API conditions JSON -> form shape, for the edit page. Unrecognised shapes are dropped rather than crashing the form. */
|
|
56
|
+
export declare function conditionsFromApi(raw: unknown): RuleCondition[];
|
|
57
|
+
/** API actions JSON -> form shape, for the edit page. Action types this builder does not offer are kept (so an
|
|
58
|
+
* existing rule's own configuration is never silently dropped by opening the edit page) but shown as read-only. */
|
|
59
|
+
export declare function actionsFromApi(raw: unknown): RuleAction[];
|
|
60
|
+
//# sourceMappingURL=automationRuleTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automationRuleTypes.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/automation/automationRuleTypes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,eAAO,MAAM,uBAAuB,aAA6D,CAAC;AAElG,eAAO,MAAM,aAAa,+LAWhB,CAAC;AACX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAW1D,CAAC;AAEF;;uDAEuD;AACvD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,eAAO,MAAM,aAAa,oDAAqD,CAAC;AAChF,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAExD,eAAO,MAAM,YAAY,wEAAyE,CAAC;AACnG,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAKxD,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,mBAAmB,uFAWtB,CAAC;AACX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAErE,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAWtE,CAAC;AAEF,oGAAoG;AACpG,eAAO,MAAM,gBAAgB,qHAUnB,CAAC;AAEX,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,0GAA0G;IAC1G,KAAK,EAAE,MAAM,CAAC;CACf;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAIzF;AAED,sGAAsG;AACtG,wBAAgB,eAAe,CAC7B,UAAU,EAAE,aAAa,EAAE,GAC1B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,GAAG,SAAS,CAiB/E;AAED,2HAA2H;AAC3H,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,EAAE,CAc/D;AAED;mHACmH;AACnH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,EAAE,CAQzD"}
|