@memberjunction/ng-dashboards 5.44.0 → 5.45.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/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts +1 -0
- package/dist/AI/components/autotagging/tabs/sources-tab.component.d.ts.map +1 -1
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js +5 -3
- package/dist/AI/components/autotagging/tabs/sources-tab.component.js.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts +4 -2
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js +13 -11
- package/dist/AI/components/prompts/model-prompt-priority-matrix.component.js.map +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.d.ts +3 -1
- package/dist/AI/components/prompts/prompt-version-control.component.d.ts.map +1 -1
- package/dist/AI/components/prompts/prompt-version-control.component.js +12 -10
- package/dist/AI/components/prompts/prompt-version-control.component.js.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.d.ts +1 -0
- package/dist/AI/components/tags/tags-resource.component.d.ts.map +1 -1
- package/dist/AI/components/tags/tags-resource.component.js +10 -8
- package/dist/AI/components/tags/tags-resource.component.js.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts +2 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js +1 -1
- package/dist/ComponentStudio/components/ai-assistant/ai-assistant-panel.component.js.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts +1 -0
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.d.ts.map +1 -1
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js +5 -3
- package/dist/ComponentStudio/components/artifact-selection-dialog.component.js.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.d.ts +3 -1
- package/dist/Credentials/components/credentials-categories-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-categories-resource.component.js +11 -5
- package/dist/Credentials/components/credentials-categories-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.d.ts +3 -2
- package/dist/Credentials/components/credentials-list-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-list-resource.component.js +23 -9
- package/dist/Credentials/components/credentials-list-resource.component.js.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.d.ts +3 -2
- package/dist/Credentials/components/credentials-types-resource.component.d.ts.map +1 -1
- package/dist/Credentials/components/credentials-types-resource.component.js +10 -4
- package/dist/Credentials/components/credentials-types-resource.component.js.map +1 -1
- package/dist/DatabaseDesigner/components/modify/database-modify.component.d.ts +2 -1
- package/dist/DatabaseDesigner/components/modify/database-modify.component.d.ts.map +1 -1
- package/dist/DatabaseDesigner/components/modify/database-modify.component.js +13 -6
- package/dist/DatabaseDesigner/components/modify/database-modify.component.js.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.d.ts +2 -1
- package/dist/FormBuilder/form-builder-resource.component.d.ts.map +1 -1
- package/dist/FormBuilder/form-builder-resource.component.js +10 -8
- package/dist/FormBuilder/form-builder-resource.component.js.map +1 -1
- package/dist/MCP/mcp-dashboard.component.d.ts +3 -1
- package/dist/MCP/mcp-dashboard.component.d.ts.map +1 -1
- package/dist/MCP/mcp-dashboard.component.js +32 -14
- package/dist/MCP/mcp-dashboard.component.js.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.d.ts +4 -2
- package/dist/QueryBrowser/query-browser-resource.component.d.ts.map +1 -1
- package/dist/QueryBrowser/query-browser-resource.component.js +15 -13
- package/dist/QueryBrowser/query-browser-resource.component.js.map +1 -1
- package/dist/UserRoutines/user-routines-agent-context.d.ts +44 -0
- package/dist/UserRoutines/user-routines-agent-context.d.ts.map +1 -0
- package/dist/UserRoutines/user-routines-agent-context.js +81 -0
- package/dist/UserRoutines/user-routines-agent-context.js.map +1 -0
- package/dist/UserRoutines/user-routines-resource.component.d.ts +60 -0
- package/dist/UserRoutines/user-routines-resource.component.d.ts.map +1 -0
- package/dist/UserRoutines/user-routines-resource.component.js +328 -0
- package/dist/UserRoutines/user-routines-resource.component.js.map +1 -0
- package/dist/module.d.ts +16 -15
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +7 -0
- package/dist/module.js.map +1 -1
- package/dist/public-api.d.ts +2 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/dist/routines-dashboards.module.d.ts +17 -0
- package/dist/routines-dashboards.module.d.ts.map +1 -0
- package/dist/routines-dashboards.module.js +65 -0
- package/dist/routines-dashboards.module.js.map +1 -0
- package/package.json +63 -58
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, unit-testable helpers for the Routines dashboard's agent context + tools.
|
|
3
|
+
*
|
|
4
|
+
* 🚨 SAFETY BOUNDARY 🚨
|
|
5
|
+
* The Routines surface exposes ONLY navigation / filter / search / select / refresh
|
|
6
|
+
* tools to the agent. DELIBERATELY NOT exposed (mutations stay human-driven in the
|
|
7
|
+
* UI): create-SAVE / edit-SAVE (the agent may only OPEN the editor), delete,
|
|
8
|
+
* pause/resume (Status writes), and run-now (queues a real dispatcher execution).
|
|
9
|
+
* Context exposes only counts, active filters, view state, and bounded display
|
|
10
|
+
* names — never payloads, messages, or recipient emails.
|
|
11
|
+
*/
|
|
12
|
+
/** Cap applied to every published name list. */
|
|
13
|
+
export declare const USER_ROUTINE_NAME_LIST_CAP = 25;
|
|
14
|
+
/** Minimal routine shape the pure helpers operate on. */
|
|
15
|
+
export interface RoutineSummaryRow {
|
|
16
|
+
ID: string;
|
|
17
|
+
Name: string;
|
|
18
|
+
Status: string;
|
|
19
|
+
}
|
|
20
|
+
/** State snapshot the dashboard passes to the context builder. */
|
|
21
|
+
export interface UserRoutinesAgentState {
|
|
22
|
+
ActiveView: 'list' | 'editor' | 'history';
|
|
23
|
+
SearchText: string;
|
|
24
|
+
StatusFilter: string;
|
|
25
|
+
TotalCount: number;
|
|
26
|
+
FilteredCount: number;
|
|
27
|
+
SelectedRoutineID: string | null;
|
|
28
|
+
Routines: RoutineSummaryRow[];
|
|
29
|
+
}
|
|
30
|
+
/** Bounded, secret-free context published via SetAgentContext. */
|
|
31
|
+
export declare function buildUserRoutinesAgentContext(state: UserRoutinesAgentState): Record<string, unknown>;
|
|
32
|
+
/**
|
|
33
|
+
* Tolerant routine resolver: exact ID → exact name → partial name contains
|
|
34
|
+
* (all case-insensitive). Returns a structured failure listing available names
|
|
35
|
+
* (bounded) on a miss.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveRoutineByIDOrName(routines: RoutineSummaryRow[], rawRef: unknown): {
|
|
38
|
+
ok: true;
|
|
39
|
+
value: RoutineSummaryRow;
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
error: string;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=user-routines-agent-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-routines-agent-context.d.ts","sourceRoot":"","sources":["../../src/UserRoutines/user-routines-agent-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,gDAAgD;AAChD,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,yDAAyD;AACzD,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,kEAAkE;AAClE,MAAM,WAAW,sBAAsB;IACnC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAED,kEAAkE;AAClE,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsBpG;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACpC,QAAQ,EAAE,iBAAiB,EAAE,EAC7B,MAAM,EAAE,OAAO,GAChB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CA2BvE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, unit-testable helpers for the Routines dashboard's agent context + tools.
|
|
3
|
+
*
|
|
4
|
+
* 🚨 SAFETY BOUNDARY 🚨
|
|
5
|
+
* The Routines surface exposes ONLY navigation / filter / search / select / refresh
|
|
6
|
+
* tools to the agent. DELIBERATELY NOT exposed (mutations stay human-driven in the
|
|
7
|
+
* UI): create-SAVE / edit-SAVE (the agent may only OPEN the editor), delete,
|
|
8
|
+
* pause/resume (Status writes), and run-now (queues a real dispatcher execution).
|
|
9
|
+
* Context exposes only counts, active filters, view state, and bounded display
|
|
10
|
+
* names — never payloads, messages, or recipient emails.
|
|
11
|
+
*/
|
|
12
|
+
/** Cap applied to every published name list. */
|
|
13
|
+
export const USER_ROUTINE_NAME_LIST_CAP = 25;
|
|
14
|
+
/** Bounded, secret-free context published via SetAgentContext. */
|
|
15
|
+
export function buildUserRoutinesAgentContext(state) {
|
|
16
|
+
const names = state.Routines.map((r) => r.Name).filter((n) => !!n);
|
|
17
|
+
const bounded = names.slice(0, USER_ROUTINE_NAME_LIST_CAP);
|
|
18
|
+
const selected = state.SelectedRoutineID
|
|
19
|
+
? state.Routines.find((r) => equalsIgnoreCase(r.ID, state.SelectedRoutineID)) ?? null
|
|
20
|
+
: null;
|
|
21
|
+
const context = {
|
|
22
|
+
ActiveView: state.ActiveView,
|
|
23
|
+
SearchText: state.SearchText,
|
|
24
|
+
StatusFilter: state.StatusFilter,
|
|
25
|
+
TotalRoutineCount: state.TotalCount,
|
|
26
|
+
FilteredRoutineCount: state.FilteredCount,
|
|
27
|
+
SelectedRoutineID: state.SelectedRoutineID,
|
|
28
|
+
SelectedRoutineName: selected?.Name ?? null,
|
|
29
|
+
VisibleRoutineNames: bounded,
|
|
30
|
+
};
|
|
31
|
+
if (names.length > bounded.length) {
|
|
32
|
+
context['VisibleRoutineNamesTruncated'] = true;
|
|
33
|
+
context['VisibleRoutineNamesTotal'] = names.length;
|
|
34
|
+
}
|
|
35
|
+
return context;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Tolerant routine resolver: exact ID → exact name → partial name contains
|
|
39
|
+
* (all case-insensitive). Returns a structured failure listing available names
|
|
40
|
+
* (bounded) on a miss.
|
|
41
|
+
*/
|
|
42
|
+
export function resolveRoutineByIDOrName(routines, rawRef) {
|
|
43
|
+
if (typeof rawRef !== 'string' || rawRef.trim().length === 0) {
|
|
44
|
+
return { ok: false, error: `Provide the routine's ID or name. ${availableNames(routines)}` };
|
|
45
|
+
}
|
|
46
|
+
const ref = rawRef.trim();
|
|
47
|
+
const byId = routines.find((r) => equalsIgnoreCase(r.ID, ref));
|
|
48
|
+
if (byId) {
|
|
49
|
+
return { ok: true, value: byId };
|
|
50
|
+
}
|
|
51
|
+
const byName = routines.find((r) => equalsIgnoreCase(r.Name, ref));
|
|
52
|
+
if (byName) {
|
|
53
|
+
return { ok: true, value: byName };
|
|
54
|
+
}
|
|
55
|
+
const contains = routines.filter((r) => r.Name.toLowerCase().includes(ref.toLowerCase()));
|
|
56
|
+
if (contains.length === 1) {
|
|
57
|
+
return { ok: true, value: contains[0] };
|
|
58
|
+
}
|
|
59
|
+
if (contains.length > 1) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
error: `'${ref}' matches multiple routines: ${contains
|
|
63
|
+
.slice(0, USER_ROUTINE_NAME_LIST_CAP)
|
|
64
|
+
.map((r) => r.Name)
|
|
65
|
+
.join(', ')}. Be more specific.`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return { ok: false, error: `No routine matches '${ref}'. ${availableNames(routines)}` };
|
|
69
|
+
}
|
|
70
|
+
function availableNames(routines) {
|
|
71
|
+
if (routines.length === 0) {
|
|
72
|
+
return 'There are no routines yet.';
|
|
73
|
+
}
|
|
74
|
+
const names = routines.slice(0, USER_ROUTINE_NAME_LIST_CAP).map((r) => r.Name);
|
|
75
|
+
const suffix = routines.length > USER_ROUTINE_NAME_LIST_CAP ? ', …' : '';
|
|
76
|
+
return `Available routines: ${names.join(', ')}${suffix}`;
|
|
77
|
+
}
|
|
78
|
+
function equalsIgnoreCase(a, b) {
|
|
79
|
+
return a.trim().toLowerCase() === b.trim().toLowerCase();
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=user-routines-agent-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-routines-agent-context.js","sourceRoot":"","sources":["../../src/UserRoutines/user-routines-agent-context.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure, unit-testable helpers for the Routines dashboard's agent context + tools.\n *\n * 🚨 SAFETY BOUNDARY 🚨\n * The Routines surface exposes ONLY navigation / filter / search / select / refresh\n * tools to the agent. DELIBERATELY NOT exposed (mutations stay human-driven in the\n * UI): create-SAVE / edit-SAVE (the agent may only OPEN the editor), delete,\n * pause/resume (Status writes), and run-now (queues a real dispatcher execution).\n * Context exposes only counts, active filters, view state, and bounded display\n * names — never payloads, messages, or recipient emails.\n */\n\n/** Cap applied to every published name list. */\nexport const USER_ROUTINE_NAME_LIST_CAP = 25;\n\n/** Minimal routine shape the pure helpers operate on. */\nexport interface RoutineSummaryRow {\n ID: string;\n Name: string;\n Status: string;\n}\n\n/** State snapshot the dashboard passes to the context builder. */\nexport interface UserRoutinesAgentState {\n ActiveView: 'list' | 'editor' | 'history';\n SearchText: string;\n StatusFilter: string;\n TotalCount: number;\n FilteredCount: number;\n SelectedRoutineID: string | null;\n Routines: RoutineSummaryRow[];\n}\n\n/** Bounded, secret-free context published via SetAgentContext. */\nexport function buildUserRoutinesAgentContext(state: UserRoutinesAgentState): Record<string, unknown> {\n const names = state.Routines.map((r) => r.Name).filter((n) => !!n);\n const bounded = names.slice(0, USER_ROUTINE_NAME_LIST_CAP);\n const selected = state.SelectedRoutineID\n ? state.Routines.find((r) => equalsIgnoreCase(r.ID, state.SelectedRoutineID as string)) ?? null\n : null;\n\n const context: Record<string, unknown> = {\n ActiveView: state.ActiveView,\n SearchText: state.SearchText,\n StatusFilter: state.StatusFilter,\n TotalRoutineCount: state.TotalCount,\n FilteredRoutineCount: state.FilteredCount,\n SelectedRoutineID: state.SelectedRoutineID,\n SelectedRoutineName: selected?.Name ?? null,\n VisibleRoutineNames: bounded,\n };\n if (names.length > bounded.length) {\n context['VisibleRoutineNamesTruncated'] = true;\n context['VisibleRoutineNamesTotal'] = names.length;\n }\n return context;\n}\n\n/**\n * Tolerant routine resolver: exact ID → exact name → partial name contains\n * (all case-insensitive). Returns a structured failure listing available names\n * (bounded) on a miss.\n */\nexport function resolveRoutineByIDOrName(\n routines: RoutineSummaryRow[],\n rawRef: unknown\n): { ok: true; value: RoutineSummaryRow } | { ok: false; error: string } {\n if (typeof rawRef !== 'string' || rawRef.trim().length === 0) {\n return { ok: false, error: `Provide the routine's ID or name. ${availableNames(routines)}` };\n }\n const ref = rawRef.trim();\n const byId = routines.find((r) => equalsIgnoreCase(r.ID, ref));\n if (byId) {\n return { ok: true, value: byId };\n }\n const byName = routines.find((r) => equalsIgnoreCase(r.Name, ref));\n if (byName) {\n return { ok: true, value: byName };\n }\n const contains = routines.filter((r) => r.Name.toLowerCase().includes(ref.toLowerCase()));\n if (contains.length === 1) {\n return { ok: true, value: contains[0] };\n }\n if (contains.length > 1) {\n return {\n ok: false,\n error: `'${ref}' matches multiple routines: ${contains\n .slice(0, USER_ROUTINE_NAME_LIST_CAP)\n .map((r) => r.Name)\n .join(', ')}. Be more specific.`,\n };\n }\n return { ok: false, error: `No routine matches '${ref}'. ${availableNames(routines)}` };\n}\n\nfunction availableNames(routines: RoutineSummaryRow[]): string {\n if (routines.length === 0) {\n return 'There are no routines yet.';\n }\n const names = routines.slice(0, USER_ROUTINE_NAME_LIST_CAP).map((r) => r.Name);\n const suffix = routines.length > USER_ROUTINE_NAME_LIST_CAP ? ', …' : '';\n return `Available routines: ${names.join(', ')}${suffix}`;\n}\n\nfunction equalsIgnoreCase(a: string, b: string): boolean {\n return a.trim().toLowerCase() === b.trim().toLowerCase();\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';
|
|
2
|
+
import { ResourceData } from '@memberjunction/core-entities';
|
|
3
|
+
import { FilterFieldConfig } from '@memberjunction/ng-ui-components';
|
|
4
|
+
import { HistoryRecordOpenedEventArgs, RoutineCounts, RoutineStatusFilter, UserRoutinesView } from '@memberjunction/ng-user-routines';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
/**
|
|
7
|
+
* Routines app — full-page Explorer host for the User Routines command center
|
|
8
|
+
* (list / create-edit / run history). Thin chrome-trio wrapper over the generic
|
|
9
|
+
* `<mj-user-routines-command-center>` from `@memberjunction/ng-user-routines`.
|
|
10
|
+
*
|
|
11
|
+
* Query-param round trip: `routine=<id>` opens that routine's history view; the pair
|
|
12
|
+
* `initial read` + `OnQueryParamsChanged` keeps deep links, Home pins, and
|
|
13
|
+
* back/forward working on cached instances.
|
|
14
|
+
*
|
|
15
|
+
* 🚨 SAFETY BOUNDARY 🚨 (see user-routines-agent-context.ts for the full statement)
|
|
16
|
+
* Agent tools here are navigation / filter / search / select / refresh ONLY. The
|
|
17
|
+
* agent may OPEN the editor (CreateRoutine / OpenRoutineEditor) but can never save,
|
|
18
|
+
* delete, pause/resume, or run-now a routine — those stay human-driven in the UI.
|
|
19
|
+
*/
|
|
20
|
+
export declare class UserRoutinesResourceComponent extends BaseResourceComponent {
|
|
21
|
+
protected navigationService: NavigationService;
|
|
22
|
+
private commandCenter?;
|
|
23
|
+
SearchText: string;
|
|
24
|
+
StatusFilter: RoutineStatusFilter;
|
|
25
|
+
TotalCount: number;
|
|
26
|
+
FilteredCount: number;
|
|
27
|
+
ActiveView: UserRoutinesView;
|
|
28
|
+
SelectedRoutineID: string | null;
|
|
29
|
+
readonly FilterFields: FilterFieldConfig[];
|
|
30
|
+
FilterValues: Record<string, unknown>;
|
|
31
|
+
get ActiveFilterCount(): number;
|
|
32
|
+
ngOnInit(): Promise<void>;
|
|
33
|
+
GetResourceDisplayName(_data: ResourceData): Promise<string>;
|
|
34
|
+
GetResourceIconClass(_data: ResourceData): Promise<string>;
|
|
35
|
+
/** 2) React to later query-param changes (back/forward, pins, cached re-focus). */
|
|
36
|
+
protected OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void;
|
|
37
|
+
OnSelectedRoutineIDChange(routineId: string | null): void;
|
|
38
|
+
OnViewChanged(view: UserRoutinesView): void;
|
|
39
|
+
OnCountsChanged(counts: RoutineCounts): void;
|
|
40
|
+
/** Opens the linked execution record (Agent Run / Prompt Run / Action Log) in a tab. */
|
|
41
|
+
OnHistoryRecordOpened(args: HistoryRecordOpenedEventArgs): void;
|
|
42
|
+
OnSearchChange(value: string): void;
|
|
43
|
+
OnFilterValuesChange(values: Record<string, unknown>): void;
|
|
44
|
+
ResetFilters(): void;
|
|
45
|
+
NewRoutine(): void;
|
|
46
|
+
BackToList(): void;
|
|
47
|
+
RefreshData(): Promise<void>;
|
|
48
|
+
private publishAgentContext;
|
|
49
|
+
private routineRows;
|
|
50
|
+
private registerAgentTools;
|
|
51
|
+
private handleSearch;
|
|
52
|
+
private handleStatusFilter;
|
|
53
|
+
private handleSelect;
|
|
54
|
+
private handleEdit;
|
|
55
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<UserRoutinesResourceComponent, never>;
|
|
56
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<UserRoutinesResourceComponent, "mj-user-routines-resource", never, {}, {}, never, never, false, never>;
|
|
57
|
+
}
|
|
58
|
+
/** Tree-shaking prevention — referenced from the package public API. */
|
|
59
|
+
export declare function LoadUserRoutinesResource(): void;
|
|
60
|
+
//# sourceMappingURL=user-routines-resource.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-routines-resource.component.d.ts","sourceRoot":"","sources":["../../src/UserRoutines/user-routines-resource.component.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,YAAY,EAAqB,MAAM,+BAA+B,CAAC;AAEhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EACH,4BAA4B,EAC5B,aAAa,EACb,mBAAmB,EAEnB,gBAAgB,EACnB,MAAM,kCAAkC,CAAC;;AAI1C;;;;;;;;;;;;;GAaG;AACH,qBAOa,6BAA8B,SAAQ,qBAAqB;IACpE,UAAmB,iBAAiB,oBAA6B;IAErC,OAAO,CAAC,aAAa,CAAC,CAAqC;IAEhF,UAAU,SAAM;IAChB,YAAY,EAAE,mBAAmB,CAAS;IAC1C,UAAU,SAAK;IACf,aAAa,SAAK;IAClB,UAAU,EAAE,gBAAgB,CAAU;IACtC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE/C,SAAgB,YAAY,EAAE,iBAAiB,EAAE,CAa/C;IACK,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAqB;IAEjE,IAAW,iBAAiB,IAAI,MAAM,CAErC;IAEc,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAYzB,sBAAsB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAI5D,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAIzE,mFAAmF;cAChE,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,GAAG,IAAI;IAUxG,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAMzD,aAAa,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAK3C,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAMnD,wFAAwF;IACjF,qBAAqB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI;IAI/D,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKnC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAO3D,YAAY,IAAI,IAAI;IAIpB,UAAU,IAAI,IAAI;IAIlB,UAAU,IAAI,IAAI;IAIZ,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzC,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,kBAAkB;YA2EZ,YAAY;YASZ,kBAAkB;YAclB,YAAY;YAUZ,UAAU;yCArPf,6BAA6B;2CAA7B,6BAA6B;CA8PzC;AAED,wEAAwE;AACxE,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { Component, ViewChild, inject } from '@angular/core';
|
|
8
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
9
|
+
import { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';
|
|
10
|
+
import { UserRoutineEngine } from '@memberjunction/core-entities';
|
|
11
|
+
import { CompositeKey } from '@memberjunction/core';
|
|
12
|
+
import { validateStringParam } from '../shared/agent-tool-validation';
|
|
13
|
+
import { buildUserRoutinesAgentContext, resolveRoutineByIDOrName } from './user-routines-agent-context';
|
|
14
|
+
import * as i0 from "@angular/core";
|
|
15
|
+
import * as i1 from "@memberjunction/ng-ui-components";
|
|
16
|
+
import * as i2 from "@memberjunction/ng-user-routines";
|
|
17
|
+
const _c0 = ["commandCenter"];
|
|
18
|
+
function UserRoutinesResourceComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
19
|
+
const _r2 = i0.ɵɵgetCurrentView();
|
|
20
|
+
i0.ɵɵelementStart(0, "button", 14);
|
|
21
|
+
i0.ɵɵlistener("click", function UserRoutinesResourceComponent_Conditional_5_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.BackToList()); });
|
|
22
|
+
i0.ɵɵelement(1, "i", 15);
|
|
23
|
+
i0.ɵɵtext(2, " Back to list ");
|
|
24
|
+
i0.ɵɵelementEnd();
|
|
25
|
+
} }
|
|
26
|
+
/**
|
|
27
|
+
* Routines app — full-page Explorer host for the User Routines command center
|
|
28
|
+
* (list / create-edit / run history). Thin chrome-trio wrapper over the generic
|
|
29
|
+
* `<mj-user-routines-command-center>` from `@memberjunction/ng-user-routines`.
|
|
30
|
+
*
|
|
31
|
+
* Query-param round trip: `routine=<id>` opens that routine's history view; the pair
|
|
32
|
+
* `initial read` + `OnQueryParamsChanged` keeps deep links, Home pins, and
|
|
33
|
+
* back/forward working on cached instances.
|
|
34
|
+
*
|
|
35
|
+
* 🚨 SAFETY BOUNDARY 🚨 (see user-routines-agent-context.ts for the full statement)
|
|
36
|
+
* Agent tools here are navigation / filter / search / select / refresh ONLY. The
|
|
37
|
+
* agent may OPEN the editor (CreateRoutine / OpenRoutineEditor) but can never save,
|
|
38
|
+
* delete, pause/resume, or run-now a routine — those stay human-driven in the UI.
|
|
39
|
+
*/
|
|
40
|
+
let UserRoutinesResourceComponent = class UserRoutinesResourceComponent extends BaseResourceComponent {
|
|
41
|
+
navigationService = inject(NavigationService);
|
|
42
|
+
commandCenter;
|
|
43
|
+
SearchText = '';
|
|
44
|
+
StatusFilter = 'all';
|
|
45
|
+
TotalCount = 0;
|
|
46
|
+
FilteredCount = 0;
|
|
47
|
+
ActiveView = 'list';
|
|
48
|
+
SelectedRoutineID = null;
|
|
49
|
+
FilterFields = [
|
|
50
|
+
{
|
|
51
|
+
key: 'status',
|
|
52
|
+
type: 'dropdown',
|
|
53
|
+
label: 'Status',
|
|
54
|
+
icon: 'fa-solid fa-circle-half-stroke',
|
|
55
|
+
options: [
|
|
56
|
+
{ text: 'All statuses', value: 'all' },
|
|
57
|
+
{ text: 'Active', value: 'Active' },
|
|
58
|
+
{ text: 'Paused', value: 'Paused' },
|
|
59
|
+
{ text: 'Disabled', value: 'Disabled' },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
FilterValues = { status: 'all' };
|
|
64
|
+
get ActiveFilterCount() {
|
|
65
|
+
return this.StatusFilter === 'all' ? 0 : 1;
|
|
66
|
+
}
|
|
67
|
+
async ngOnInit() {
|
|
68
|
+
super.ngOnInit();
|
|
69
|
+
// 1) Initial query-param read (deep links)
|
|
70
|
+
const params = this.GetQueryParams();
|
|
71
|
+
if (params['routine']) {
|
|
72
|
+
this.SelectedRoutineID = params['routine'];
|
|
73
|
+
}
|
|
74
|
+
this.registerAgentTools();
|
|
75
|
+
this.publishAgentContext();
|
|
76
|
+
this.NotifyLoadComplete();
|
|
77
|
+
}
|
|
78
|
+
async GetResourceDisplayName(_data) {
|
|
79
|
+
return 'Routines';
|
|
80
|
+
}
|
|
81
|
+
async GetResourceIconClass(_data) {
|
|
82
|
+
return 'fa-solid fa-business-time';
|
|
83
|
+
}
|
|
84
|
+
/** 2) React to later query-param changes (back/forward, pins, cached re-focus). */
|
|
85
|
+
OnQueryParamsChanged(params, _source) {
|
|
86
|
+
const routineId = params['routine'] || null;
|
|
87
|
+
if (routineId !== this.SelectedRoutineID) {
|
|
88
|
+
this.SelectedRoutineID = routineId;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------
|
|
92
|
+
// Command-center wiring
|
|
93
|
+
// ---------------------------------------------------------------
|
|
94
|
+
OnSelectedRoutineIDChange(routineId) {
|
|
95
|
+
this.SelectedRoutineID = routineId;
|
|
96
|
+
this.UpdateQueryParams({ routine: routineId });
|
|
97
|
+
this.publishAgentContext();
|
|
98
|
+
}
|
|
99
|
+
OnViewChanged(view) {
|
|
100
|
+
this.ActiveView = view;
|
|
101
|
+
this.publishAgentContext();
|
|
102
|
+
}
|
|
103
|
+
OnCountsChanged(counts) {
|
|
104
|
+
this.TotalCount = counts.Total;
|
|
105
|
+
this.FilteredCount = counts.Filtered;
|
|
106
|
+
this.publishAgentContext();
|
|
107
|
+
}
|
|
108
|
+
/** Opens the linked execution record (Agent Run / Prompt Run / Action Log) in a tab. */
|
|
109
|
+
OnHistoryRecordOpened(args) {
|
|
110
|
+
this.navigationService.OpenEntityRecord(args.EntityName, CompositeKey.FromID(args.RecordID));
|
|
111
|
+
}
|
|
112
|
+
OnSearchChange(value) {
|
|
113
|
+
this.SearchText = value;
|
|
114
|
+
this.publishAgentContext();
|
|
115
|
+
}
|
|
116
|
+
OnFilterValuesChange(values) {
|
|
117
|
+
this.FilterValues = values;
|
|
118
|
+
const status = values['status'];
|
|
119
|
+
this.StatusFilter = (status === 'Active' || status === 'Paused' || status === 'Disabled') ? status : 'all';
|
|
120
|
+
this.publishAgentContext();
|
|
121
|
+
}
|
|
122
|
+
ResetFilters() {
|
|
123
|
+
this.OnFilterValuesChange({ status: 'all' });
|
|
124
|
+
}
|
|
125
|
+
NewRoutine() {
|
|
126
|
+
this.commandCenter?.ShowNewRoutine();
|
|
127
|
+
}
|
|
128
|
+
BackToList() {
|
|
129
|
+
this.commandCenter?.ShowList();
|
|
130
|
+
}
|
|
131
|
+
async RefreshData() {
|
|
132
|
+
await this.commandCenter?.Refresh();
|
|
133
|
+
this.publishAgentContext();
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------
|
|
136
|
+
// Agent context + tools (navigation/read-only — see SAFETY BOUNDARY)
|
|
137
|
+
// ---------------------------------------------------------------
|
|
138
|
+
publishAgentContext() {
|
|
139
|
+
this.navigationService.SetAgentContext(this, buildUserRoutinesAgentContext({
|
|
140
|
+
ActiveView: this.ActiveView,
|
|
141
|
+
SearchText: this.SearchText,
|
|
142
|
+
StatusFilter: this.StatusFilter,
|
|
143
|
+
TotalCount: this.TotalCount,
|
|
144
|
+
FilteredCount: this.FilteredCount,
|
|
145
|
+
SelectedRoutineID: this.SelectedRoutineID,
|
|
146
|
+
Routines: this.routineRows(),
|
|
147
|
+
}));
|
|
148
|
+
}
|
|
149
|
+
routineRows() {
|
|
150
|
+
const engine = UserRoutineEngine.GetProviderInstance(this.ProviderToUse, UserRoutineEngine);
|
|
151
|
+
return engine.Routines.map((r) => ({ ID: r.ID, Name: r.Name, Status: r.Status }));
|
|
152
|
+
}
|
|
153
|
+
registerAgentTools() {
|
|
154
|
+
this.navigationService.SetAgentClientTools(this, [
|
|
155
|
+
{
|
|
156
|
+
Name: 'RefreshRoutines',
|
|
157
|
+
Description: 'Reload the routines list from the server.',
|
|
158
|
+
ParameterSchema: { type: 'object', properties: {} },
|
|
159
|
+
Handler: async () => {
|
|
160
|
+
await this.RefreshData();
|
|
161
|
+
return { Success: true, Data: { TotalRoutineCount: this.TotalCount } };
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
Name: 'SearchRoutines',
|
|
166
|
+
Description: 'Filter the routines list by a search query (name, description, or agent). Pass an empty string to clear.',
|
|
167
|
+
ParameterSchema: {
|
|
168
|
+
type: 'object',
|
|
169
|
+
properties: { query: { type: 'string', description: 'Text to filter by; empty clears.' } },
|
|
170
|
+
required: ['query'],
|
|
171
|
+
},
|
|
172
|
+
Handler: async (params) => this.handleSearch(params),
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
Name: 'FilterRoutinesByStatus',
|
|
176
|
+
Description: "Filter routines by lifecycle status: 'Active', 'Paused', 'Disabled', or 'all'.",
|
|
177
|
+
ParameterSchema: {
|
|
178
|
+
type: 'object',
|
|
179
|
+
properties: { status: { type: 'string', description: "'Active' | 'Paused' | 'Disabled' | 'all'" } },
|
|
180
|
+
required: ['status'],
|
|
181
|
+
},
|
|
182
|
+
Handler: async (params) => this.handleStatusFilter(params),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
Name: 'SelectRoutine',
|
|
186
|
+
Description: "Open a routine's run history, referenced by ID or name (partial, case-insensitive match accepted).",
|
|
187
|
+
ParameterSchema: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: { routine: { type: 'string', description: 'The routine ID or name.' } },
|
|
190
|
+
required: ['routine'],
|
|
191
|
+
},
|
|
192
|
+
Handler: async (params) => this.handleSelect(params),
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
Name: 'OpenRoutineEditor',
|
|
196
|
+
Description: 'Open the editor for an existing routine (by ID or name). This only opens the editor for the user — it does NOT save anything.',
|
|
197
|
+
ParameterSchema: {
|
|
198
|
+
type: 'object',
|
|
199
|
+
properties: { routine: { type: 'string', description: 'The routine ID or name.' } },
|
|
200
|
+
required: ['routine'],
|
|
201
|
+
},
|
|
202
|
+
Handler: async (params) => this.handleEdit(params),
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
Name: 'CreateRoutine',
|
|
206
|
+
Description: 'Open the New Routine editor. This only opens the editor for the user — it does NOT save anything.',
|
|
207
|
+
ParameterSchema: { type: 'object', properties: {} },
|
|
208
|
+
Handler: async () => {
|
|
209
|
+
this.NewRoutine();
|
|
210
|
+
this.publishAgentContext();
|
|
211
|
+
return { Success: true };
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
Name: 'BackToRoutinesList',
|
|
216
|
+
Description: 'Return from the editor or history view to the routines list.',
|
|
217
|
+
ParameterSchema: { type: 'object', properties: {} },
|
|
218
|
+
Handler: async () => {
|
|
219
|
+
this.BackToList();
|
|
220
|
+
this.publishAgentContext();
|
|
221
|
+
return { Success: true };
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
226
|
+
async handleSearch(params) {
|
|
227
|
+
const check = validateStringParam(params['query'], 'query');
|
|
228
|
+
if (!check.ok) {
|
|
229
|
+
return check.result;
|
|
230
|
+
}
|
|
231
|
+
this.OnSearchChange(check.value);
|
|
232
|
+
return { Success: true, Data: { FilteredRoutineCount: this.FilteredCount } };
|
|
233
|
+
}
|
|
234
|
+
async handleStatusFilter(params) {
|
|
235
|
+
const check = validateStringParam(params['status'], 'status');
|
|
236
|
+
if (!check.ok) {
|
|
237
|
+
return check.result;
|
|
238
|
+
}
|
|
239
|
+
const value = check.value.trim();
|
|
240
|
+
const normalized = ['Active', 'Paused', 'Disabled'].find((s) => s.toLowerCase() === value.toLowerCase());
|
|
241
|
+
if (!normalized && value.toLowerCase() !== 'all') {
|
|
242
|
+
return { Success: false, ErrorMessage: `'${value}' is not a valid status. Use 'Active', 'Paused', 'Disabled', or 'all'.` };
|
|
243
|
+
}
|
|
244
|
+
this.OnFilterValuesChange({ status: normalized ?? 'all' });
|
|
245
|
+
return { Success: true };
|
|
246
|
+
}
|
|
247
|
+
async handleSelect(params) {
|
|
248
|
+
const resolved = resolveRoutineByIDOrName(this.routineRows(), params['routine']);
|
|
249
|
+
if (!resolved.ok) {
|
|
250
|
+
return { Success: false, ErrorMessage: resolved.error };
|
|
251
|
+
}
|
|
252
|
+
this.commandCenter?.ShowHistory(resolved.value.ID);
|
|
253
|
+
this.publishAgentContext();
|
|
254
|
+
return { Success: true, Data: { RoutineID: resolved.value.ID, RoutineName: resolved.value.Name } };
|
|
255
|
+
}
|
|
256
|
+
async handleEdit(params) {
|
|
257
|
+
const resolved = resolveRoutineByIDOrName(this.routineRows(), params['routine']);
|
|
258
|
+
if (!resolved.ok) {
|
|
259
|
+
return { Success: false, ErrorMessage: resolved.error };
|
|
260
|
+
}
|
|
261
|
+
this.commandCenter?.ShowEditRoutine(resolved.value.ID);
|
|
262
|
+
this.publishAgentContext();
|
|
263
|
+
return { Success: true, Data: { RoutineID: resolved.value.ID, RoutineName: resolved.value.Name } };
|
|
264
|
+
}
|
|
265
|
+
static ɵfac = /*@__PURE__*/ (() => { let ɵUserRoutinesResourceComponent_BaseFactory; return function UserRoutinesResourceComponent_Factory(__ngFactoryType__) { return (ɵUserRoutinesResourceComponent_BaseFactory || (ɵUserRoutinesResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(UserRoutinesResourceComponent)))(__ngFactoryType__ || UserRoutinesResourceComponent); }; })();
|
|
266
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UserRoutinesResourceComponent, selectors: [["mj-user-routines-resource"]], viewQuery: function UserRoutinesResourceComponent_Query(rf, ctx) { if (rf & 1) {
|
|
267
|
+
i0.ɵɵviewQuery(_c0, 5);
|
|
268
|
+
} if (rf & 2) {
|
|
269
|
+
let _t;
|
|
270
|
+
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.commandCenter = _t.first);
|
|
271
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 17, vars: 13, consts: [["commandCenter", ""], ["Title", "Routines", "Icon", "fa-solid fa-business-time", "Subtitle", "Schedule AI agents to run for you \u2014 and get notified about the results"], ["meta", ""], ["Label", "routines", 3, "Count", "Total"], ["actions", ""], ["mjButton", "", "variant", "outline", "size", "sm"], [3, "Clicked"], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-plus"], ["toolbar", ""], ["Placeholder", "Search routines...", 3, "ValueChange", "Value"], ["Label", "Filters", "Icon", "fa-solid fa-filter", 3, "ClearAllRequested", "ActiveCount", "ShowClearAll"], [3, "ValuesChange", "Reset", "Fields", "Values"], [1, "routines-cc", 3, "SelectedRoutineIDChange", "ViewChanged", "CountsChanged", "HistoryRecordOpened", "Provider", "ShowHeader", "SearchText", "StatusFilter", "SelectedRoutineID"], ["mjButton", "", "variant", "outline", "size", "sm", 3, "click"], [1, "fa-solid", "fa-arrow-left"]], template: function UserRoutinesResourceComponent_Template(rf, ctx) { if (rf & 1) {
|
|
272
|
+
const _r1 = i0.ɵɵgetCurrentView();
|
|
273
|
+
i0.ɵɵelementStart(0, "mj-page-layout")(1, "mj-page-header", 1)(2, "div", 2);
|
|
274
|
+
i0.ɵɵelement(3, "mj-stat-badge", 3);
|
|
275
|
+
i0.ɵɵelementEnd();
|
|
276
|
+
i0.ɵɵelementStart(4, "div", 4);
|
|
277
|
+
i0.ɵɵconditionalCreate(5, UserRoutinesResourceComponent_Conditional_5_Template, 3, 0, "button", 5);
|
|
278
|
+
i0.ɵɵelementStart(6, "mj-refresh-button", 6);
|
|
279
|
+
i0.ɵɵlistener("Clicked", function UserRoutinesResourceComponent_Template_mj_refresh_button_Clicked_6_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.RefreshData()); });
|
|
280
|
+
i0.ɵɵelementEnd();
|
|
281
|
+
i0.ɵɵelementStart(7, "button", 7);
|
|
282
|
+
i0.ɵɵlistener("click", function UserRoutinesResourceComponent_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.NewRoutine()); });
|
|
283
|
+
i0.ɵɵelement(8, "i", 8);
|
|
284
|
+
i0.ɵɵtext(9, " New Routine ");
|
|
285
|
+
i0.ɵɵelementEnd()();
|
|
286
|
+
i0.ɵɵelementStart(10, "div", 9)(11, "mj-page-search", 10);
|
|
287
|
+
i0.ɵɵlistener("ValueChange", function UserRoutinesResourceComponent_Template_mj_page_search_ValueChange_11_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnSearchChange($event)); });
|
|
288
|
+
i0.ɵɵelementEnd();
|
|
289
|
+
i0.ɵɵelementStart(12, "mj-filter-popover", 11);
|
|
290
|
+
i0.ɵɵlistener("ClearAllRequested", function UserRoutinesResourceComponent_Template_mj_filter_popover_ClearAllRequested_12_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.ResetFilters()); });
|
|
291
|
+
i0.ɵɵelementStart(13, "mj-filter-panel", 12);
|
|
292
|
+
i0.ɵɵlistener("ValuesChange", function UserRoutinesResourceComponent_Template_mj_filter_panel_ValuesChange_13_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnFilterValuesChange($event)); })("Reset", function UserRoutinesResourceComponent_Template_mj_filter_panel_Reset_13_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.ResetFilters()); });
|
|
293
|
+
i0.ɵɵelementEnd()()()();
|
|
294
|
+
i0.ɵɵelementStart(14, "mj-page-body")(15, "mj-user-routines-command-center", 13, 0);
|
|
295
|
+
i0.ɵɵlistener("SelectedRoutineIDChange", function UserRoutinesResourceComponent_Template_mj_user_routines_command_center_SelectedRoutineIDChange_15_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnSelectedRoutineIDChange($event)); })("ViewChanged", function UserRoutinesResourceComponent_Template_mj_user_routines_command_center_ViewChanged_15_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnViewChanged($event)); })("CountsChanged", function UserRoutinesResourceComponent_Template_mj_user_routines_command_center_CountsChanged_15_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnCountsChanged($event)); })("HistoryRecordOpened", function UserRoutinesResourceComponent_Template_mj_user_routines_command_center_HistoryRecordOpened_15_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnHistoryRecordOpened($event)); });
|
|
296
|
+
i0.ɵɵelementEnd()()();
|
|
297
|
+
} if (rf & 2) {
|
|
298
|
+
i0.ɵɵadvance(3);
|
|
299
|
+
i0.ɵɵproperty("Count", ctx.FilteredCount)("Total", ctx.TotalCount);
|
|
300
|
+
i0.ɵɵadvance(2);
|
|
301
|
+
i0.ɵɵconditional(ctx.ActiveView !== "list" ? 5 : -1);
|
|
302
|
+
i0.ɵɵadvance(6);
|
|
303
|
+
i0.ɵɵproperty("Value", ctx.SearchText);
|
|
304
|
+
i0.ɵɵadvance();
|
|
305
|
+
i0.ɵɵproperty("ActiveCount", ctx.ActiveFilterCount)("ShowClearAll", ctx.ActiveFilterCount > 0);
|
|
306
|
+
i0.ɵɵadvance();
|
|
307
|
+
i0.ɵɵproperty("Fields", ctx.FilterFields)("Values", ctx.FilterValues);
|
|
308
|
+
i0.ɵɵadvance(2);
|
|
309
|
+
i0.ɵɵproperty("Provider", ctx.ProviderToUse)("ShowHeader", false)("SearchText", ctx.SearchText)("StatusFilter", ctx.StatusFilter)("SelectedRoutineID", ctx.SelectedRoutineID);
|
|
310
|
+
} }, dependencies: [i1.MJButtonDirective, i1.MJPageLayoutComponent, i1.MJPageHeaderComponent, i1.MJPageBodyComponent, i1.MJPageSearchComponent, i1.MJFilterPopoverComponent, i1.MJFilterPanelComponent, i1.MJRefreshButtonComponent, i1.MJStatBadgeComponent, i2.UserRoutinesCommandCenterComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n}\n\n.routines-cc[_ngcontent-%COMP%] {\n display: block;\n height: 100%;\n min-height: 0;\n}"] });
|
|
311
|
+
};
|
|
312
|
+
UserRoutinesResourceComponent = __decorate([
|
|
313
|
+
RegisterClass(BaseResourceComponent, 'UserRoutines')
|
|
314
|
+
], UserRoutinesResourceComponent);
|
|
315
|
+
export { UserRoutinesResourceComponent };
|
|
316
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UserRoutinesResourceComponent, [{
|
|
317
|
+
type: Component,
|
|
318
|
+
args: [{ standalone: false, selector: 'mj-user-routines-resource', template: "<mj-page-layout>\n <mj-page-header Title=\"Routines\" Icon=\"fa-solid fa-business-time\"\n Subtitle=\"Schedule AI agents to run for you \u2014 and get notified about the results\">\n <!-- X-of-Y filtered count earns its meta spot per chrome conventions \u00A72. -->\n <div meta>\n <mj-stat-badge [Count]=\"FilteredCount\" [Total]=\"TotalCount\" Label=\"routines\"></mj-stat-badge>\n </div>\n <div actions>\n @if (ActiveView !== 'list') {\n <button mjButton variant=\"outline\" size=\"sm\" (click)=\"BackToList()\">\n <i class=\"fa-solid fa-arrow-left\"></i> Back to list\n </button>\n }\n <mj-refresh-button (Clicked)=\"RefreshData()\"></mj-refresh-button>\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"NewRoutine()\">\n <i class=\"fa-solid fa-plus\"></i> New Routine\n </button>\n </div>\n <div toolbar>\n <mj-page-search Placeholder=\"Search routines...\" [Value]=\"SearchText\"\n (ValueChange)=\"OnSearchChange($event)\"></mj-page-search>\n <mj-filter-popover Label=\"Filters\" Icon=\"fa-solid fa-filter\"\n [ActiveCount]=\"ActiveFilterCount\" [ShowClearAll]=\"ActiveFilterCount > 0\"\n (ClearAllRequested)=\"ResetFilters()\">\n <mj-filter-panel [Fields]=\"FilterFields\" [Values]=\"FilterValues\"\n (ValuesChange)=\"OnFilterValuesChange($event)\" (Reset)=\"ResetFilters()\"></mj-filter-panel>\n </mj-filter-popover>\n </div>\n </mj-page-header>\n\n <mj-page-body>\n <mj-user-routines-command-center #commandCenter class=\"routines-cc\"\n [Provider]=\"ProviderToUse\"\n [ShowHeader]=\"false\"\n [SearchText]=\"SearchText\"\n [StatusFilter]=\"StatusFilter\"\n [SelectedRoutineID]=\"SelectedRoutineID\"\n (SelectedRoutineIDChange)=\"OnSelectedRoutineIDChange($event)\"\n (ViewChanged)=\"OnViewChanged($event)\"\n (CountsChanged)=\"OnCountsChanged($event)\"\n (HistoryRecordOpened)=\"OnHistoryRecordOpened($event)\">\n </mj-user-routines-command-center>\n </mj-page-body>\n</mj-page-layout>\n", styles: [":host {\n display: block;\n height: 100%;\n}\n\n.routines-cc {\n display: block;\n height: 100%;\n min-height: 0;\n}\n"] }]
|
|
319
|
+
}], null, { commandCenter: [{
|
|
320
|
+
type: ViewChild,
|
|
321
|
+
args: ['commandCenter']
|
|
322
|
+
}] }); })();
|
|
323
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UserRoutinesResourceComponent, { className: "UserRoutinesResourceComponent", filePath: "src/UserRoutines/user-routines-resource.component.ts", lineNumber: 38 }); })();
|
|
324
|
+
/** Tree-shaking prevention — referenced from the package public API. */
|
|
325
|
+
export function LoadUserRoutinesResource() {
|
|
326
|
+
// Intentionally empty: forces inclusion of the @RegisterClass side effect.
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=user-routines-resource.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-routines-resource.component.js","sourceRoot":"","sources":["../../src/UserRoutines/user-routines-resource.component.ts","../../src/UserRoutines/user-routines-resource.component.html"],"names":[],"mappings":"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","sourcesContent":["import { Component, ViewChild, inject } from '@angular/core';\nimport { RegisterClass } from '@memberjunction/global';\nimport { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';\nimport { ResourceData, UserRoutineEngine } from '@memberjunction/core-entities';\nimport { CompositeKey } from '@memberjunction/core';\nimport { FilterFieldConfig } from '@memberjunction/ng-ui-components';\nimport {\n HistoryRecordOpenedEventArgs,\n RoutineCounts,\n RoutineStatusFilter,\n UserRoutinesCommandCenterComponent,\n UserRoutinesView,\n} from '@memberjunction/ng-user-routines';\nimport { AgentToolResult, validateStringParam } from '../shared/agent-tool-validation';\nimport { buildUserRoutinesAgentContext, resolveRoutineByIDOrName, RoutineSummaryRow } from './user-routines-agent-context';\n\n/**\n * Routines app — full-page Explorer host for the User Routines command center\n * (list / create-edit / run history). Thin chrome-trio wrapper over the generic\n * `<mj-user-routines-command-center>` from `@memberjunction/ng-user-routines`.\n *\n * Query-param round trip: `routine=<id>` opens that routine's history view; the pair\n * `initial read` + `OnQueryParamsChanged` keeps deep links, Home pins, and\n * back/forward working on cached instances.\n *\n * 🚨 SAFETY BOUNDARY 🚨 (see user-routines-agent-context.ts for the full statement)\n * Agent tools here are navigation / filter / search / select / refresh ONLY. The\n * agent may OPEN the editor (CreateRoutine / OpenRoutineEditor) but can never save,\n * delete, pause/resume, or run-now a routine — those stay human-driven in the UI.\n */\n@RegisterClass(BaseResourceComponent, 'UserRoutines')\n@Component({\n standalone: false,\n selector: 'mj-user-routines-resource',\n templateUrl: './user-routines-resource.component.html',\n styleUrls: ['./user-routines-resource.component.css'],\n})\nexport class UserRoutinesResourceComponent extends BaseResourceComponent {\n protected override navigationService = inject(NavigationService);\n\n @ViewChild('commandCenter') private commandCenter?: UserRoutinesCommandCenterComponent;\n\n public SearchText = '';\n public StatusFilter: RoutineStatusFilter = 'all';\n public TotalCount = 0;\n public FilteredCount = 0;\n public ActiveView: UserRoutinesView = 'list';\n public SelectedRoutineID: string | null = null;\n\n public readonly FilterFields: FilterFieldConfig[] = [\n {\n key: 'status',\n type: 'dropdown',\n label: 'Status',\n icon: 'fa-solid fa-circle-half-stroke',\n options: [\n { text: 'All statuses', value: 'all' },\n { text: 'Active', value: 'Active' },\n { text: 'Paused', value: 'Paused' },\n { text: 'Disabled', value: 'Disabled' },\n ],\n },\n ];\n public FilterValues: Record<string, unknown> = { status: 'all' };\n\n public get ActiveFilterCount(): number {\n return this.StatusFilter === 'all' ? 0 : 1;\n }\n\n override async ngOnInit(): Promise<void> {\n super.ngOnInit();\n // 1) Initial query-param read (deep links)\n const params = this.GetQueryParams();\n if (params['routine']) {\n this.SelectedRoutineID = params['routine'];\n }\n this.registerAgentTools();\n this.publishAgentContext();\n this.NotifyLoadComplete();\n }\n\n override async GetResourceDisplayName(_data: ResourceData): Promise<string> {\n return 'Routines';\n }\n\n override async GetResourceIconClass(_data: ResourceData): Promise<string> {\n return 'fa-solid fa-business-time';\n }\n\n /** 2) React to later query-param changes (back/forward, pins, cached re-focus). */\n protected override OnQueryParamsChanged(params: Record<string, string>, _source: 'popstate' | 'deeplink'): void {\n const routineId = params['routine'] || null;\n if (routineId !== this.SelectedRoutineID) {\n this.SelectedRoutineID = routineId;\n }\n }\n\n // ---------------------------------------------------------------\n // Command-center wiring\n // ---------------------------------------------------------------\n public OnSelectedRoutineIDChange(routineId: string | null): void {\n this.SelectedRoutineID = routineId;\n this.UpdateQueryParams({ routine: routineId });\n this.publishAgentContext();\n }\n\n public OnViewChanged(view: UserRoutinesView): void {\n this.ActiveView = view;\n this.publishAgentContext();\n }\n\n public OnCountsChanged(counts: RoutineCounts): void {\n this.TotalCount = counts.Total;\n this.FilteredCount = counts.Filtered;\n this.publishAgentContext();\n }\n\n /** Opens the linked execution record (Agent Run / Prompt Run / Action Log) in a tab. */\n public OnHistoryRecordOpened(args: HistoryRecordOpenedEventArgs): void {\n this.navigationService.OpenEntityRecord(args.EntityName, CompositeKey.FromID(args.RecordID));\n }\n\n public OnSearchChange(value: string): void {\n this.SearchText = value;\n this.publishAgentContext();\n }\n\n public OnFilterValuesChange(values: Record<string, unknown>): void {\n this.FilterValues = values;\n const status = values['status'];\n this.StatusFilter = (status === 'Active' || status === 'Paused' || status === 'Disabled') ? status : 'all';\n this.publishAgentContext();\n }\n\n public ResetFilters(): void {\n this.OnFilterValuesChange({ status: 'all' });\n }\n\n public NewRoutine(): void {\n this.commandCenter?.ShowNewRoutine();\n }\n\n public BackToList(): void {\n this.commandCenter?.ShowList();\n }\n\n public async RefreshData(): Promise<void> {\n await this.commandCenter?.Refresh();\n this.publishAgentContext();\n }\n\n // ---------------------------------------------------------------\n // Agent context + tools (navigation/read-only — see SAFETY BOUNDARY)\n // ---------------------------------------------------------------\n private publishAgentContext(): void {\n this.navigationService.SetAgentContext(\n this,\n buildUserRoutinesAgentContext({\n ActiveView: this.ActiveView,\n SearchText: this.SearchText,\n StatusFilter: this.StatusFilter,\n TotalCount: this.TotalCount,\n FilteredCount: this.FilteredCount,\n SelectedRoutineID: this.SelectedRoutineID,\n Routines: this.routineRows(),\n })\n );\n }\n\n private routineRows(): RoutineSummaryRow[] {\n const engine = UserRoutineEngine.GetProviderInstance<UserRoutineEngine>(this.ProviderToUse, UserRoutineEngine) as UserRoutineEngine;\n return engine.Routines.map((r) => ({ ID: r.ID, Name: r.Name, Status: r.Status }));\n }\n\n private registerAgentTools(): void {\n this.navigationService.SetAgentClientTools(this, [\n {\n Name: 'RefreshRoutines',\n Description: 'Reload the routines list from the server.',\n ParameterSchema: { type: 'object', properties: {} },\n Handler: async () => {\n await this.RefreshData();\n return { Success: true, Data: { TotalRoutineCount: this.TotalCount } };\n },\n },\n {\n Name: 'SearchRoutines',\n Description: 'Filter the routines list by a search query (name, description, or agent). Pass an empty string to clear.',\n ParameterSchema: {\n type: 'object',\n properties: { query: { type: 'string', description: 'Text to filter by; empty clears.' } },\n required: ['query'],\n },\n Handler: async (params) => this.handleSearch(params),\n },\n {\n Name: 'FilterRoutinesByStatus',\n Description: \"Filter routines by lifecycle status: 'Active', 'Paused', 'Disabled', or 'all'.\",\n ParameterSchema: {\n type: 'object',\n properties: { status: { type: 'string', description: \"'Active' | 'Paused' | 'Disabled' | 'all'\" } },\n required: ['status'],\n },\n Handler: async (params) => this.handleStatusFilter(params),\n },\n {\n Name: 'SelectRoutine',\n Description: \"Open a routine's run history, referenced by ID or name (partial, case-insensitive match accepted).\",\n ParameterSchema: {\n type: 'object',\n properties: { routine: { type: 'string', description: 'The routine ID or name.' } },\n required: ['routine'],\n },\n Handler: async (params) => this.handleSelect(params),\n },\n {\n Name: 'OpenRoutineEditor',\n Description:\n 'Open the editor for an existing routine (by ID or name). This only opens the editor for the user — it does NOT save anything.',\n ParameterSchema: {\n type: 'object',\n properties: { routine: { type: 'string', description: 'The routine ID or name.' } },\n required: ['routine'],\n },\n Handler: async (params) => this.handleEdit(params),\n },\n {\n Name: 'CreateRoutine',\n Description: 'Open the New Routine editor. This only opens the editor for the user — it does NOT save anything.',\n ParameterSchema: { type: 'object', properties: {} },\n Handler: async () => {\n this.NewRoutine();\n this.publishAgentContext();\n return { Success: true };\n },\n },\n {\n Name: 'BackToRoutinesList',\n Description: 'Return from the editor or history view to the routines list.',\n ParameterSchema: { type: 'object', properties: {} },\n Handler: async () => {\n this.BackToList();\n this.publishAgentContext();\n return { Success: true };\n },\n },\n ]);\n }\n\n private async handleSearch(params: Record<string, unknown>): Promise<AgentToolResult & { Data?: Record<string, unknown> }> {\n const check = validateStringParam(params['query'], 'query');\n if (!check.ok) {\n return check.result;\n }\n this.OnSearchChange(check.value);\n return { Success: true, Data: { FilteredRoutineCount: this.FilteredCount } };\n }\n\n private async handleStatusFilter(params: Record<string, unknown>): Promise<AgentToolResult> {\n const check = validateStringParam(params['status'], 'status');\n if (!check.ok) {\n return check.result;\n }\n const value = check.value.trim();\n const normalized = ['Active', 'Paused', 'Disabled'].find((s) => s.toLowerCase() === value.toLowerCase());\n if (!normalized && value.toLowerCase() !== 'all') {\n return { Success: false, ErrorMessage: `'${value}' is not a valid status. Use 'Active', 'Paused', 'Disabled', or 'all'.` };\n }\n this.OnFilterValuesChange({ status: normalized ?? 'all' });\n return { Success: true };\n }\n\n private async handleSelect(params: Record<string, unknown>): Promise<AgentToolResult & { Data?: Record<string, unknown> }> {\n const resolved = resolveRoutineByIDOrName(this.routineRows(), params['routine']);\n if (!resolved.ok) {\n return { Success: false, ErrorMessage: resolved.error };\n }\n this.commandCenter?.ShowHistory(resolved.value.ID);\n this.publishAgentContext();\n return { Success: true, Data: { RoutineID: resolved.value.ID, RoutineName: resolved.value.Name } };\n }\n\n private async handleEdit(params: Record<string, unknown>): Promise<AgentToolResult & { Data?: Record<string, unknown> }> {\n const resolved = resolveRoutineByIDOrName(this.routineRows(), params['routine']);\n if (!resolved.ok) {\n return { Success: false, ErrorMessage: resolved.error };\n }\n this.commandCenter?.ShowEditRoutine(resolved.value.ID);\n this.publishAgentContext();\n return { Success: true, Data: { RoutineID: resolved.value.ID, RoutineName: resolved.value.Name } };\n }\n}\n\n/** Tree-shaking prevention — referenced from the package public API. */\nexport function LoadUserRoutinesResource(): void {\n // Intentionally empty: forces inclusion of the @RegisterClass side effect.\n}\n","<mj-page-layout>\n <mj-page-header Title=\"Routines\" Icon=\"fa-solid fa-business-time\"\n Subtitle=\"Schedule AI agents to run for you — and get notified about the results\">\n <!-- X-of-Y filtered count earns its meta spot per chrome conventions §2. -->\n <div meta>\n <mj-stat-badge [Count]=\"FilteredCount\" [Total]=\"TotalCount\" Label=\"routines\"></mj-stat-badge>\n </div>\n <div actions>\n @if (ActiveView !== 'list') {\n <button mjButton variant=\"outline\" size=\"sm\" (click)=\"BackToList()\">\n <i class=\"fa-solid fa-arrow-left\"></i> Back to list\n </button>\n }\n <mj-refresh-button (Clicked)=\"RefreshData()\"></mj-refresh-button>\n <button mjButton variant=\"primary\" size=\"sm\" (click)=\"NewRoutine()\">\n <i class=\"fa-solid fa-plus\"></i> New Routine\n </button>\n </div>\n <div toolbar>\n <mj-page-search Placeholder=\"Search routines...\" [Value]=\"SearchText\"\n (ValueChange)=\"OnSearchChange($event)\"></mj-page-search>\n <mj-filter-popover Label=\"Filters\" Icon=\"fa-solid fa-filter\"\n [ActiveCount]=\"ActiveFilterCount\" [ShowClearAll]=\"ActiveFilterCount > 0\"\n (ClearAllRequested)=\"ResetFilters()\">\n <mj-filter-panel [Fields]=\"FilterFields\" [Values]=\"FilterValues\"\n (ValuesChange)=\"OnFilterValuesChange($event)\" (Reset)=\"ResetFilters()\"></mj-filter-panel>\n </mj-filter-popover>\n </div>\n </mj-page-header>\n\n <mj-page-body>\n <mj-user-routines-command-center #commandCenter class=\"routines-cc\"\n [Provider]=\"ProviderToUse\"\n [ShowHeader]=\"false\"\n [SearchText]=\"SearchText\"\n [StatusFilter]=\"StatusFilter\"\n [SelectedRoutineID]=\"SelectedRoutineID\"\n (SelectedRoutineIDChange)=\"OnSelectedRoutineIDChange($event)\"\n (ViewChanged)=\"OnViewChanged($event)\"\n (CountsChanged)=\"OnCountsChanged($event)\"\n (HistoryRecordOpened)=\"OnHistoryRecordOpened($event)\">\n </mj-user-routines-command-center>\n </mj-page-body>\n</mj-page-layout>\n"]}
|