@memberjunction/ng-user-routines 0.0.0 → 5.45.1
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/lib/my-routines-list.component.d.ts +119 -0
- package/dist/lib/my-routines-list.component.d.ts.map +1 -0
- package/dist/lib/my-routines-list.component.js +574 -0
- package/dist/lib/my-routines-list.component.js.map +1 -0
- package/dist/lib/new-routine.component.d.ts +182 -0
- package/dist/lib/new-routine.component.d.ts.map +1 -0
- package/dist/lib/new-routine.component.js +1070 -0
- package/dist/lib/new-routine.component.js.map +1 -0
- package/dist/lib/routine-history.component.d.ts +65 -0
- package/dist/lib/routine-history.component.d.ts.map +1 -0
- package/dist/lib/routine-history.component.js +290 -0
- package/dist/lib/routine-history.component.js.map +1 -0
- package/dist/lib/routine-target-catalog.d.ts +48 -0
- package/dist/lib/routine-target-catalog.d.ts.map +1 -0
- package/dist/lib/routine-target-catalog.js +59 -0
- package/dist/lib/routine-target-catalog.js.map +1 -0
- package/dist/lib/routine-ui-helpers.d.ts +49 -0
- package/dist/lib/routine-ui-helpers.d.ts.map +1 -0
- package/dist/lib/routine-ui-helpers.js +174 -0
- package/dist/lib/routine-ui-helpers.js.map +1 -0
- package/dist/lib/user-routines-command-center.component.d.ts +88 -0
- package/dist/lib/user-routines-command-center.component.d.ts.map +1 -0
- package/dist/lib/user-routines-command-center.component.js +372 -0
- package/dist/lib/user-routines-command-center.component.js.map +1 -0
- package/dist/lib/user-routines-events.d.ts +88 -0
- package/dist/lib/user-routines-events.d.ts.map +1 -0
- package/dist/lib/user-routines-events.js +97 -0
- package/dist/lib/user-routines-events.js.map +1 -0
- package/dist/lib/user-routines-slide-in.component.d.ts +57 -0
- package/dist/lib/user-routines-slide-in.component.d.ts.map +1 -0
- package/dist/lib/user-routines-slide-in.component.js +170 -0
- package/dist/lib/user-routines-slide-in.component.js.map +1 -0
- package/dist/lib/user-routines.module.d.ts +37 -0
- package/dist/lib/user-routines.module.d.ts.map +1 -0
- package/dist/lib/user-routines.module.js +113 -0
- package/dist/lib/user-routines.module.js.map +1 -0
- package/dist/public-api.d.ts +10 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +19 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +49 -7
- package/README.md +0 -45
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new-routine.component.js","sourceRoot":"","sources":["../../src/lib/new-routine.component.ts","../../src/lib/new-routine.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, inject } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { CompositeKey, IMetadataProvider, RunView } from '@memberjunction/core';\nimport { AIEngineBase } from '@memberjunction/ai-engine-base';\nimport { MJUserRoutineEntity, MJUserRoutineRecipientEntity, UserRoutineEngine } from '@memberjunction/core-entities';\nimport {\n BuildCronExpression,\n CRON_DAY_NAMES,\n CronPresetKind,\n CronSchedule,\n DescribeCronExpression,\n IsPlausibleCronExpression,\n NormalizeUUID,\n ParseCronExpression,\n} from '@memberjunction/global';\nimport { MJNotificationService } from '@memberjunction/ng-notifications';\nimport { AfterNodeSelectEventArgs, TreeBranchConfig, TreeLeafConfig } from '@memberjunction/ng-trees';\nimport {\n FromDateTimeLocal,\n GetLocalTimezone,\n GetTimezoneOptions,\n IsPlausibleEmail,\n ParseSkillIDs,\n SerializeSkillIDs,\n ToDateTimeLocal,\n ValidateOptionalJson,\n} from './routine-ui-helpers';\nimport { LoadRoutineTargetCatalog, RoutineSkillOption, RoutineTargetCatalog } from './routine-target-catalog';\nimport { AfterRoutineCreatedEventArgs, BeforeRoutineCreatedEventArgs } from './user-routines-events';\n\n/** One editable recipient row (existing rows carry their entity for update/delete). */\ninterface RecipientRow {\n Entity: MJUserRoutineRecipientEntity | null;\n Mode: 'user' | 'email';\n UserID: string | null;\n Email: string;\n Channel: MJUserRoutineRecipientEntity['Channel'];\n}\n\n/** Minimal user shape for the recipient user picker. */\ninterface UserOption {\n ID: string;\n Name: string;\n Email: string | null;\n}\n\n/**\n * Create/edit form for a User Routine. Routines run an AI AGENT on a schedule\n * (TargetType is implicitly 'Agent') — the agent is chosen from a categorical tree\n * grouped by Agent Category, showing each agent's own IconClass, with Realtime-type\n * agents excluded (interactive-only). Also covers the initial message, optional JSON\n * payload, AI Skills pre-activation, cron presets + advanced escape hatch, IANA\n * timezone, activation window, notification settings, and the ordered recipients list.\n *\n * Reusable (Generic) component: no Router, no page chrome. The host mounts it\n * (slide-in / dialog / inline), passes `RoutineID` (null = create), and reacts to\n * `Saved` / `Cancelled` plus the cancelable `BeforeRoutineCreated` /\n * `AfterRoutineCreated` pair for new routines. All persistence flows through MJ\n * entity objects with explicit `Save()` boolean checks; failures surface\n * `LatestResult.CompleteMessage`. Cached routine/recipient data comes from\n * {@link UserRoutineEngine}.\n */\n@Component({\n standalone: false,\n selector: 'mj-new-routine',\n templateUrl: './new-routine.component.html',\n styleUrls: ['./new-routine.component.css'],\n})\nexport class NewRoutineComponent extends BaseAngularComponent implements OnInit {\n private cdr = inject(ChangeDetectorRef);\n private notifications = inject(MJNotificationService);\n\n // ---------------------------------------------------------------\n // Inputs / Outputs\n // ---------------------------------------------------------------\n private _routineID: string | null = null;\n /** ID of the routine to edit, or null to create a new one. */\n @Input()\n public set RoutineID(value: string | null) {\n if (value !== this._routineID) {\n this._routineID = value;\n if (this.initialized) {\n void this.reload();\n }\n }\n }\n public get RoutineID(): string | null {\n return this._routineID;\n }\n\n /** Emitted after a successful save (routine + recipients persisted) — create AND edit. */\n @Output() Saved = new EventEmitter<MJUserRoutineEntity>();\n /** Emitted when the user cancels without saving. */\n @Output() Cancelled = new EventEmitter<void>();\n /** Cancelable: fires before a NEW routine is saved for the first time. */\n @Output() BeforeRoutineCreated = new EventEmitter<BeforeRoutineCreatedEventArgs>();\n /** Informational: fires after a new routine (and its recipients) was persisted. */\n @Output() AfterRoutineCreated = new EventEmitter<AfterRoutineCreatedEventArgs>();\n\n // ---------------------------------------------------------------\n // Form state\n // ---------------------------------------------------------------\n public Name = '';\n public Description = '';\n /** The selected agent's ID (TargetType is implicitly 'Agent'). */\n public TargetID: string | null = null;\n public InitialMessage = '';\n public StartingPayloadText = '';\n public SelectedSkillIDs: string[] = [];\n public RoutineType: MJUserRoutineEntity['RoutineType'] = 'Scheduled';\n\n public ScheduleKind: CronPresetKind = 'daily';\n /** Minute past each hour for the hourly preset. */\n public ScheduleMinute = 0;\n /** \"HH:MM\" run time for daily/weekly/monthly presets. */\n public ScheduleTime = '09:00';\n public ScheduleDayOfWeek = 1;\n public ScheduleDayOfMonth = 1;\n public RawCron = '';\n\n public Timezone: string = GetLocalTimezone();\n public StartAtLocal = '';\n public EndAtLocal = '';\n\n public NotifyCondition: MJUserRoutineEntity['NotifyCondition'] = 'Always';\n public NotifyViaInApp = true;\n public NotifyViaEmail = false;\n public Recipients: RecipientRow[] = [];\n\n // ---------------------------------------------------------------\n // Options / status\n // ---------------------------------------------------------------\n /**\n * Progressive disclosure: the basic view (name / agent / message / frequency)\n * covers the 80% path; everything else lives behind this toggle. Auto-expands\n * when editing a routine that already uses advanced settings.\n */\n public ShowAdvanced = false;\n\n public Catalog: RoutineTargetCatalog | null = null;\n public UserOptions: UserOption[] = [];\n public TimezoneOptions: string[] = GetTimezoneOptions();\n public IsLoading = true;\n public IsSaving = false;\n public ValidationErrors: string[] = [];\n\n /** Tree config for the agent-category branches. */\n public AgentTreeBranchConfig: TreeBranchConfig = {\n EntityName: 'MJ: AI Agent Categories',\n DisplayField: 'Name',\n ParentIDField: 'ParentID',\n DefaultIcon: 'fa-solid fa-folder',\n OrderBy: 'Name ASC',\n };\n /** Tree config for the pickable agents (built at load time — excludes Realtime types). */\n public AgentTreeLeafConfig: TreeLeafConfig | undefined;\n /** Tree selection binding (single agent). */\n public SelectedAgentIDs: string[] = [];\n\n public readonly DayNames = CRON_DAY_NAMES;\n public readonly DayOfWeekOptions = CRON_DAY_NAMES.map((name, i) => ({ text: name, value: i }));\n public readonly DayOfMonthOptions = Array.from({ length: 31 }, (_, i) => ({ text: `${i + 1}`, value: i + 1 }));\n public readonly ScheduleKindOptions: Array<{ Value: CronPresetKind; Label: string }> = [\n { Value: 'hourly', Label: 'Hourly' },\n { Value: 'daily', Label: 'Daily' },\n { Value: 'weekly', Label: 'Weekly' },\n { Value: 'monthly', Label: 'Monthly' },\n { Value: 'advanced', Label: 'Advanced (cron)' },\n ];\n public readonly NotifyConditionOptions = [\n { text: 'Always — after every run', value: 'Always' },\n { text: 'On success only', value: 'OnSuccess' },\n { text: 'On failure only', value: 'OnFailure' },\n { text: 'On change — when the result differs from the prior run', value: 'OnChange' },\n ];\n public readonly ChannelOptions = [\n { text: 'In-app', value: 'InApp' },\n { text: 'Email', value: 'Email' },\n ];\n public readonly RecipientModeOptions = [\n { text: 'MJ user', value: 'user' },\n { text: 'External email', value: 'email' },\n ];\n\n private editingEntity: MJUserRoutineEntity | null = null;\n private deletedRecipients: MJUserRoutineRecipientEntity[] = [];\n private initialized = false;\n\n async ngOnInit(): Promise<void> {\n this.initialized = true;\n await this.reload();\n }\n\n /** True when editing an existing routine (vs. creating a new one). */\n public get IsEdit(): boolean {\n return this._routineID != null;\n }\n\n /** Active skills available for pre-activation. */\n public get SkillOptions(): RoutineSkillOption[] {\n return this.Catalog?.Skills ?? [];\n }\n\n /** Name of the currently selected agent (empty when none). */\n public get SelectedAgentName(): string {\n if (!this.TargetID) {\n return '';\n }\n return this.Catalog?.NameByID.get(NormalizeUUID(this.TargetID)) ?? '';\n }\n\n /** IconClass of the currently selected agent (robot fallback). */\n public get SelectedAgentIcon(): string {\n if (!this.TargetID) {\n return 'fa-solid fa-robot';\n }\n return this.Catalog?.IconByID.get(NormalizeUUID(this.TargetID)) ?? 'fa-solid fa-robot';\n }\n\n /** Live human-readable preview of the schedule being built. */\n public get SchedulePreview(): string {\n return DescribeCronExpression(this.buildCron());\n }\n\n /** Helper text under the RoutineType toggle. */\n public get RoutineTypeHelp(): string {\n return this.RoutineType === 'Scheduled'\n ? 'Runs on the schedule and notifies per the notification condition.'\n : 'Runs on the schedule and hashes each result — pair with the \"On change\" condition to be notified only when the result changes.';\n }\n\n /** Handles agent selection from the category tree (leaf nodes only). */\n /** The selected agent as a CompositeKey for the tree-dropdown's Value binding. */\n public get SelectedAgentKey(): CompositeKey | null {\n return this.TargetID ? CompositeKey.FromID(this.TargetID) : null;\n }\n\n public OnAgentNodeSelected(args: AfterNodeSelectEventArgs): void {\n if (args.Node.Type === 'leaf') {\n this.TargetID = args.Node.ID;\n this.SelectedAgentIDs = [args.Node.ID];\n this.cdr.markForCheck();\n }\n }\n\n public SetScheduleKind(kind: CronPresetKind): void {\n if (kind === this.ScheduleKind) {\n return;\n }\n if (kind === 'advanced' && !this.RawCron.trim()) {\n // Seed the advanced box from the current preset so nothing is lost\n this.RawCron = this.buildCron();\n }\n this.ScheduleKind = kind;\n this.cdr.markForCheck();\n }\n\n /** Toggles a skill in/out of the RequestedSkillIDs selection. */\n public ToggleSkill(skillID: string): void {\n const index = this.SelectedSkillIDs.indexOf(skillID);\n if (index >= 0) {\n this.SelectedSkillIDs = this.SelectedSkillIDs.filter((id) => id !== skillID);\n } else {\n this.SelectedSkillIDs = [...this.SelectedSkillIDs, skillID];\n }\n this.cdr.markForCheck();\n }\n\n public IsSkillSelected(skillID: string): boolean {\n return this.SelectedSkillIDs.includes(skillID);\n }\n\n // ---------------------------------------------------------------\n // Recipients\n // ---------------------------------------------------------------\n public AddRecipient(): void {\n this.Recipients = [\n ...this.Recipients,\n { Entity: null, Mode: 'user', UserID: null, Email: '', Channel: 'InApp' },\n ];\n void this.ensureUserOptions();\n }\n\n public RemoveRecipient(index: number): void {\n const row = this.Recipients[index];\n if (row?.Entity) {\n this.deletedRecipients.push(row.Entity);\n }\n this.Recipients = this.Recipients.filter((_, i) => i !== index);\n }\n\n /** Moves a recipient up/down — the saved Sequence is the row index. */\n public MoveRecipient(index: number, delta: -1 | 1): void {\n const target = index + delta;\n if (target < 0 || target >= this.Recipients.length) {\n return;\n }\n const next = [...this.Recipients];\n [next[index], next[target]] = [next[target], next[index]];\n this.Recipients = next;\n }\n\n /** When the row's mode flips, clear the other identity field. */\n public OnRecipientModeChange(row: RecipientRow): void {\n if (row.Mode === 'user') {\n row.Email = '';\n void this.ensureUserOptions();\n } else {\n row.UserID = null;\n }\n }\n\n // ---------------------------------------------------------------\n // Save / cancel\n // ---------------------------------------------------------------\n public Cancel(): void {\n this.Cancelled.emit();\n }\n\n public async Save(): Promise<void> {\n if (this.IsSaving) {\n return;\n }\n this.ValidationErrors = this.validate();\n if (this.ValidationErrors.length > 0) {\n this.cdr.markForCheck();\n return;\n }\n\n this.IsSaving = true;\n this.cdr.markForCheck();\n try {\n const p = this.ProviderToUse;\n const isNew = !this.IsEdit;\n const routine =\n this.editingEntity ??\n (await p.GetEntityObject<MJUserRoutineEntity>('MJ: User Routines', p.CurrentUser));\n if (isNew) {\n routine.UserID = p.CurrentUser.ID;\n }\n\n routine.Name = this.Name.trim();\n routine.Description = this.Description.trim() || null;\n routine.RoutineType = this.RoutineType;\n routine.TargetType = 'Agent';\n // Validated non-null in validate()\n routine.TargetID = this.TargetID as string;\n routine.InitialMessage = this.InitialMessage.trim() || null;\n routine.StartingPayload = this.StartingPayloadText.trim() || null;\n routine.RequestedSkillIDs = SerializeSkillIDs(this.SelectedSkillIDs);\n routine.CronExpression = this.buildCron();\n routine.Timezone = this.Timezone;\n routine.StartAt = FromDateTimeLocal(this.StartAtLocal);\n routine.EndAt = FromDateTimeLocal(this.EndAtLocal);\n routine.NotifyCondition = this.NotifyCondition;\n routine.NotifyViaInApp = this.NotifyViaInApp;\n routine.NotifyViaEmail = this.NotifyViaEmail;\n\n if (isNew) {\n const beforeArgs = new BeforeRoutineCreatedEventArgs(routine);\n this.BeforeRoutineCreated.emit(beforeArgs);\n if (beforeArgs.Cancel) {\n return;\n }\n }\n\n const saved = await routine.Save();\n if (!saved) {\n this.ValidationErrors = [\n `Save failed: ${routine.LatestResult?.CompleteMessage ?? 'unknown error'}`,\n ];\n return;\n }\n\n const recipientErrors = await this.saveRecipients(routine);\n if (recipientErrors.length > 0) {\n this.ValidationErrors = recipientErrors;\n return;\n }\n\n if (isNew) {\n // Re-scope the engine's dependent (recipients/runs) configs to include\n // the new routine — their client-side filter is a Config-time snapshot.\n await this.engine().Refresh(p.CurrentUser);\n this.AfterRoutineCreated.emit(new AfterRoutineCreatedEventArgs(routine));\n }\n\n this.notifications.CreateSimpleNotification(\n isNew ? `'${routine.Name}' created` : `'${routine.Name}' updated`,\n 'success',\n 3000\n );\n this.Saved.emit(routine);\n } finally {\n this.IsSaving = false;\n this.cdr.markForCheck();\n }\n }\n\n // ---------------------------------------------------------------\n // Internals\n // ---------------------------------------------------------------\n private engine(): UserRoutineEngine {\n return UserRoutineEngine.GetProviderInstance<UserRoutineEngine>(this.ProviderToUse, UserRoutineEngine) as UserRoutineEngine;\n }\n\n /** True when the loaded routine differs from the basic-path defaults in any advanced field. */\n private usesAdvancedSettings(): boolean {\n return this.Description.trim().length > 0\n || this.RoutineType === 'Monitoring'\n || this.StartingPayloadText.trim().length > 0\n || this.SelectedSkillIDs.length > 0\n || this.Timezone !== GetLocalTimezone()\n || this.StartAtLocal.trim().length > 0\n || this.EndAtLocal.trim().length > 0\n || this.NotifyCondition !== 'Always'\n || !this.NotifyViaInApp\n || this.NotifyViaEmail\n || this.Recipients.length > 0;\n }\n\n private async reload(): Promise<void> {\n this.IsLoading = true;\n this.ValidationErrors = [];\n this.deletedRecipients = [];\n this.cdr.markForCheck();\n try {\n const p = this.ProviderToUse;\n const [catalog] = await Promise.all([\n LoadRoutineTargetCatalog(p),\n this.engine().Config(false, p.CurrentUser, p),\n ]);\n this.Catalog = catalog;\n this.buildAgentTreeConfig(p);\n if (this._routineID) {\n await this.loadExisting(this._routineID);\n this.ShowAdvanced = this.usesAdvancedSettings();\n } else {\n this.resetForNew();\n this.ShowAdvanced = false;\n }\n if (this.Recipients.some((r) => r.Mode === 'user')) {\n await this.ensureUserOptions();\n }\n } catch (e) {\n this.ValidationErrors = [\n `Failed to load the editor: ${e instanceof Error ? e.message : 'unknown error'}`,\n ];\n } finally {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n\n /**\n * Builds the agent tree leaf config: Active, root-level agents only, EXCLUDING\n * agents whose type is the Realtime agent type. The exclusion is expressed as an\n * inline NOT IN list of type IDs resolved from metadata BY NAME (never hardcoded).\n */\n private buildAgentTreeConfig(provider: IMetadataProvider): void {\n const realtimeTypeIDs = this.resolveRealtimeTypeIDs(provider);\n const filters = [`Status='Active'`, `ParentID IS NULL`];\n if (realtimeTypeIDs.length > 0) {\n const inList = realtimeTypeIDs.map((id) => `'${id}'`).join(',');\n filters.push(`(TypeID IS NULL OR TypeID NOT IN (${inList}))`);\n }\n this.AgentTreeLeafConfig = {\n EntityName: 'MJ: AI Agents',\n ParentField: 'CategoryID',\n DisplayField: 'Name',\n IconField: 'IconClass',\n DefaultIcon: 'fa-solid fa-robot',\n ExtraFilter: filters.join(' AND '),\n OrderBy: 'Name ASC',\n };\n }\n\n /** Realtime agent-type IDs resolved from the cached AI metadata by type NAME. */\n private resolveRealtimeTypeIDs(provider: IMetadataProvider): string[] {\n // The catalog load above already Config'd AIEngineBase for this provider —\n // reuse its cached AgentTypes through the provider-scoped instance.\n const engine = AIEngineBase.GetProviderInstance<AIEngineBase>(provider, AIEngineBase) as AIEngineBase;\n return engine.AgentTypes\n .filter((t) => t.Name?.trim().toLowerCase() === 'realtime')\n .map((t) => t.ID);\n }\n\n private resetForNew(): void {\n this.editingEntity = null;\n this.Name = '';\n this.Description = '';\n this.TargetID = null;\n this.SelectedAgentIDs = [];\n this.InitialMessage = '';\n this.StartingPayloadText = '';\n this.SelectedSkillIDs = [];\n this.RoutineType = 'Scheduled';\n this.ScheduleKind = 'daily';\n this.ScheduleMinute = 0;\n this.ScheduleTime = '09:00';\n this.ScheduleDayOfWeek = 1;\n this.ScheduleDayOfMonth = 1;\n this.RawCron = '';\n this.Timezone = GetLocalTimezone();\n this.StartAtLocal = '';\n this.EndAtLocal = '';\n this.NotifyCondition = 'Always';\n this.NotifyViaInApp = true;\n this.NotifyViaEmail = false;\n this.Recipients = [];\n }\n\n private async loadExisting(routineID: string): Promise<void> {\n const p = this.ProviderToUse;\n // Prefer the engine's cached entity; fall back to a direct load (e.g., deep link\n // into a routine saved elsewhere before the cache refreshed).\n let routine = this.engine().GetRoutineByID(routineID) ?? null;\n if (!routine) {\n const loadedEntity = await p.GetEntityObject<MJUserRoutineEntity>('MJ: User Routines', p.CurrentUser);\n const loaded = await loadedEntity.Load(routineID);\n routine = loaded ? loadedEntity : null;\n }\n if (!routine) {\n this.ValidationErrors = [`Routine ${routineID} could not be loaded.`];\n this.resetForNew();\n return;\n }\n this.editingEntity = routine;\n this.Name = routine.Name;\n this.Description = routine.Description ?? '';\n this.TargetID = routine.TargetID;\n this.SelectedAgentIDs = routine.TargetID ? [routine.TargetID] : [];\n this.InitialMessage = routine.InitialMessage ?? '';\n this.StartingPayloadText = routine.StartingPayload ?? '';\n this.SelectedSkillIDs = ParseSkillIDs(routine.RequestedSkillIDs);\n this.RoutineType = routine.RoutineType;\n this.applyCron(ParseCronExpression(routine.CronExpression));\n this.Timezone = routine.Timezone;\n this.StartAtLocal = ToDateTimeLocal(routine.StartAt);\n this.EndAtLocal = ToDateTimeLocal(routine.EndAt);\n this.NotifyCondition = routine.NotifyCondition;\n this.NotifyViaInApp = routine.NotifyViaInApp;\n this.NotifyViaEmail = routine.NotifyViaEmail;\n this.loadRecipientRows(routineID);\n }\n\n private applyCron(schedule: CronSchedule): void {\n this.ScheduleKind = schedule.Kind;\n this.ScheduleMinute = schedule.Minute;\n this.ScheduleTime = `${schedule.Hour.toString().padStart(2, '0')}:${schedule.Minute.toString().padStart(2, '0')}`;\n this.ScheduleDayOfWeek = schedule.DayOfWeek;\n this.ScheduleDayOfMonth = schedule.DayOfMonth;\n this.RawCron = schedule.Raw;\n }\n\n private buildCron(): string {\n const { hour, minute } = this.parseScheduleTime();\n const schedule: CronSchedule = {\n Kind: this.ScheduleKind,\n Minute: this.ScheduleKind === 'hourly' ? this.clampMinute(this.ScheduleMinute) : minute,\n Hour: hour,\n DayOfWeek: this.ScheduleDayOfWeek,\n DayOfMonth: this.ScheduleDayOfMonth,\n Raw: this.RawCron,\n };\n return BuildCronExpression(schedule);\n }\n\n private parseScheduleTime(): { hour: number; minute: number } {\n const match = /^(\\d{1,2}):(\\d{2})$/.exec(this.ScheduleTime.trim());\n if (!match) {\n return { hour: 9, minute: 0 };\n }\n return {\n hour: Math.min(23, Math.max(0, parseInt(match[1], 10))),\n minute: this.clampMinute(parseInt(match[2], 10)),\n };\n }\n\n private clampMinute(minute: number): number {\n return Math.min(59, Math.max(0, Math.round(minute ?? 0)));\n }\n\n /** Builds the editable recipient rows from the engine's cached recipients. */\n private loadRecipientRows(routineID: string): void {\n this.Recipients = this.engine()\n .RecipientsForRoutine(routineID)\n .map((entity) => ({\n Entity: entity,\n Mode: entity.UserID ? ('user' as const) : ('email' as const),\n UserID: entity.UserID,\n Email: entity.Email ?? '',\n Channel: entity.Channel,\n }));\n }\n\n /** Lazily loads the user picker options the first time a user-mode row exists. */\n private async ensureUserOptions(): Promise<void> {\n if (this.UserOptions.length > 0) {\n return;\n }\n const p = this.ProviderToUse;\n const rv = RunView.FromMetadataProvider(p);\n const result = await rv.RunView<UserOption>(\n {\n EntityName: 'MJ: Users',\n Fields: ['ID', 'Name', 'Email'],\n ExtraFilter: `IsActive=1`,\n OrderBy: 'Name ASC',\n ResultType: 'simple',\n },\n p.CurrentUser\n );\n if (result.Success) {\n this.UserOptions = result.Results ?? [];\n this.cdr.markForCheck();\n }\n }\n\n private validate(): string[] {\n const errors: string[] = [];\n if (!this.Name.trim()) {\n errors.push('Name is required.');\n }\n if (!this.TargetID) {\n errors.push('Select the agent this routine should run.');\n }\n if (this.ScheduleKind === 'advanced' && !IsPlausibleCronExpression(this.RawCron)) {\n errors.push('The advanced cron expression must have 5 (or 6) space-separated fields.');\n }\n if (!this.Timezone?.trim()) {\n errors.push('Timezone is required.');\n }\n const payloadCheck = ValidateOptionalJson(this.StartingPayloadText);\n if (!payloadCheck.Valid) {\n errors.push(`Starting payload is not valid JSON: ${payloadCheck.Error}`);\n }\n const startAt = FromDateTimeLocal(this.StartAtLocal);\n const endAt = FromDateTimeLocal(this.EndAtLocal);\n if (startAt && endAt && endAt.getTime() <= startAt.getTime()) {\n errors.push('End of the activation window must be after its start.');\n }\n this.Recipients.forEach((row, i) => {\n if (row.Mode === 'user' && !row.UserID) {\n errors.push(`Recipient ${i + 1}: choose a user (or switch the row to an external email).`);\n }\n if (row.Mode === 'email' && !IsPlausibleEmail(row.Email)) {\n errors.push(`Recipient ${i + 1}: enter a valid email address.`);\n }\n });\n return errors;\n }\n\n /** Persists recipient rows in order (Sequence = index) and deletes removed rows. */\n private async saveRecipients(routine: MJUserRoutineEntity): Promise<string[]> {\n const p = this.ProviderToUse;\n const errors: string[] = [];\n\n for (const entity of this.deletedRecipients) {\n const deleted = await entity.Delete();\n if (!deleted) {\n errors.push(\n `Failed to remove a recipient: ${entity.LatestResult?.CompleteMessage ?? 'unknown error'}`\n );\n }\n }\n this.deletedRecipients = [];\n\n for (let i = 0; i < this.Recipients.length; i++) {\n const row = this.Recipients[i];\n const entity =\n row.Entity ??\n (await p.GetEntityObject<MJUserRoutineRecipientEntity>('MJ: User Routine Recipients', p.CurrentUser));\n entity.RoutineID = routine.ID;\n entity.UserID = row.Mode === 'user' ? row.UserID : null;\n entity.Email = row.Mode === 'email' ? row.Email.trim() : null;\n entity.Channel = row.Channel;\n entity.Sequence = i;\n const saved = await entity.Save();\n if (saved) {\n row.Entity = entity;\n } else {\n errors.push(\n `Failed to save recipient ${i + 1}: ${entity.LatestResult?.CompleteMessage ?? 'unknown error'}`\n );\n }\n }\n return errors;\n }\n}\n","@if (IsLoading) {\n <div class=\"editor-loading\">\n <mj-loading text=\"Loading editor...\" size=\"medium\"></mj-loading>\n </div>\n} @else {\n <div class=\"routine-editor\">\n\n @if (ValidationErrors.length > 0) {\n <mj-alert Variant=\"error\">\n <ul class=\"editor-errors\">\n @for (error of ValidationErrors; track error) {\n <li>{{ error }}</li>\n }\n </ul>\n </mj-alert>\n }\n\n <!-- ═══════════ BASICS (the 80% path: name, agent, message, schedule) ═══════════ -->\n <section class=\"editor-section\">\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-name\">Name <span class=\"editor-required\">*</span></label>\n <input id=\"routine-name\" class=\"mj-input\" type=\"text\" [(ngModel)]=\"Name\" placeholder=\"e.g. Morning membership digest\" />\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Which agent should this routine run? <span class=\"editor-required\">*</span></label>\n @if (AgentTreeLeafConfig) {\n <mj-tree-dropdown\n [BranchConfig]=\"AgentTreeBranchConfig\"\n [LeafConfig]=\"AgentTreeLeafConfig\"\n DefaultExpansion=\"all\"\n SelectionMode=\"single\"\n SelectableTypes=\"leaf\"\n [Value]=\"SelectedAgentKey\"\n [Clearable]=\"false\"\n Placeholder=\"Select an agent...\"\n (AfterNodeSelect)=\"OnAgentNodeSelected($event)\">\n </mj-tree-dropdown>\n }\n <div class=\"editor-hint\">Active agents only, grouped by category — realtime (voice) agents are interactive-only and can't be scheduled.</div>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-message\">Message sent on each run</label>\n <!-- Composer mention editor in DISCOVERY mode: trigger providers are ClassFactory-\n discovered (ng-conversations registers '@' agent / '#' record / '/' skill plugins\n when loaded). '@' agent mentions are excluded — the routine's agent is fixed by\n the picker above. With no providers registered this degrades gracefully to a\n plain text editor. -->\n <mj-mention-editor id=\"routine-message\"\n [(ngModel)]=\"InitialMessage\"\n placeholder=\"The message the routine sends to the agent each time it runs\"\n [ExcludedTriggerKeys]=\"['agent-mentions']\"\n [Provider]=\"Provider\"\n [enableAttachments]=\"false\"\n [autoFocus]=\"false\"\n [currentUser]=\"ProviderToUse.CurrentUser\"></mj-mention-editor>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Frequency</label>\n <div class=\"editor-segmented editor-segmented--wrap\" role=\"radiogroup\" aria-label=\"Schedule frequency\">\n @for (option of ScheduleKindOptions; track option.Value) {\n <button type=\"button\" class=\"editor-segment\"\n [class.editor-segment--active]=\"ScheduleKind === option.Value\"\n (click)=\"SetScheduleKind(option.Value)\">\n {{ option.Label }}\n </button>\n }\n </div>\n </div>\n\n <div class=\"editor-schedule-detail\">\n @switch (ScheduleKind) {\n @case ('hourly') {\n <div class=\"editor-field editor-field--inline\">\n <label class=\"editor-label\">At minute</label>\n <mj-numeric-input [(ngModel)]=\"ScheduleMinute\" [Min]=\"0\" [Max]=\"59\" [Step]=\"5\"></mj-numeric-input>\n <span class=\"editor-hint-inline\">past every hour</span>\n </div>\n }\n @case ('daily') {\n <div class=\"editor-field editor-field--inline\">\n <label class=\"editor-label\">At</label>\n <input class=\"mj-input editor-time-input\" type=\"time\" [(ngModel)]=\"ScheduleTime\" />\n <span class=\"editor-hint-inline\">every day</span>\n </div>\n }\n @case ('weekly') {\n <div class=\"editor-field editor-field--inline\">\n <label class=\"editor-label\">Every</label>\n <mj-dropdown class=\"editor-inline-dropdown\" [Data]=\"DayOfWeekOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"ScheduleDayOfWeek\"></mj-dropdown>\n <label class=\"editor-label\">at</label>\n <input class=\"mj-input editor-time-input\" type=\"time\" [(ngModel)]=\"ScheduleTime\" />\n </div>\n }\n @case ('monthly') {\n <div class=\"editor-field editor-field--inline\">\n <label class=\"editor-label\">On day</label>\n <mj-dropdown class=\"editor-inline-dropdown\" [Data]=\"DayOfMonthOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"ScheduleDayOfMonth\"></mj-dropdown>\n <label class=\"editor-label\">at</label>\n <input class=\"mj-input editor-time-input\" type=\"time\" [(ngModel)]=\"ScheduleTime\" />\n </div>\n }\n @case ('advanced') {\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-cron\">Cron expression</label>\n <input id=\"routine-cron\" class=\"mj-input editor-mono\" type=\"text\" [(ngModel)]=\"RawCron\"\n placeholder=\"minute hour day-of-month month day-of-week\" />\n </div>\n }\n }\n <div class=\"editor-schedule-preview\">\n <i class=\"fa-solid fa-calendar-check\"></i> {{ SchedulePreview || 'No schedule yet' }}\n </div>\n </div>\n </section>\n\n <!-- ═══════════ ADVANCED (progressive disclosure — collapsed by default) ═══════════ -->\n <button type=\"button\" class=\"editor-advanced-toggle\" (click)=\"ShowAdvanced = !ShowAdvanced\"\n [attr.aria-expanded]=\"ShowAdvanced\">\n <i class=\"fa-solid\" [class.fa-chevron-right]=\"!ShowAdvanced\" [class.fa-chevron-down]=\"ShowAdvanced\"></i>\n Advanced options\n <span class=\"editor-hint-inline\">description · monitoring · timezone · window · payload · skills · notifications</span>\n </button>\n\n @if (ShowAdvanced) {\n <section class=\"editor-section\">\n <h3 class=\"editor-section-title\"><i class=\"fa-solid fa-circle-info\"></i> Details</h3>\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-description\">Description</label>\n <textarea id=\"routine-description\" class=\"mj-textarea\" rows=\"2\" [(ngModel)]=\"Description\"\n placeholder=\"What does this routine do?\"></textarea>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Routine type</label>\n <div class=\"editor-segmented\" role=\"radiogroup\" aria-label=\"Routine type\">\n <button type=\"button\" class=\"editor-segment\"\n [class.editor-segment--active]=\"RoutineType === 'Scheduled'\"\n (click)=\"RoutineType = 'Scheduled'\">\n <i class=\"fa-solid fa-clock\"></i> Scheduled\n </button>\n <button type=\"button\" class=\"editor-segment\"\n [class.editor-segment--active]=\"RoutineType === 'Monitoring'\"\n (click)=\"RoutineType = 'Monitoring'\">\n <i class=\"fa-solid fa-eye\"></i> Monitoring\n </button>\n </div>\n <div class=\"editor-hint\">{{ RoutineTypeHelp }}</div>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Timezone</label>\n <mj-combobox\n [Data]=\"TimezoneOptions\"\n [ValuePrimitive]=\"true\"\n Placeholder=\"Select an IANA timezone...\"\n [(ngModel)]=\"Timezone\">\n </mj-combobox>\n </div>\n\n <div class=\"editor-field-row\">\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-startat\">Active from (optional)</label>\n <input id=\"routine-startat\" class=\"mj-input\" type=\"datetime-local\" [(ngModel)]=\"StartAtLocal\" />\n </div>\n <div class=\"editor-field\">\n <label class=\"editor-label\" for=\"routine-endat\">Active until (optional)</label>\n <input id=\"routine-endat\" class=\"mj-input\" type=\"datetime-local\" [(ngModel)]=\"EndAtLocal\" />\n </div>\n </div>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Starting payload (JSON, optional)</label>\n <div class=\"editor-code\">\n <mj-code-editor [(ngModel)]=\"StartingPayloadText\" language=\"json\"\n placeholder='{ \"example\": true }'></mj-code-editor>\n </div>\n <div class=\"editor-hint\">Passed to the agent on each run. Leave blank for none.</div>\n </div>\n\n @if (SkillOptions.length > 0) {\n <div class=\"editor-field\">\n <label class=\"editor-label\">Pre-activate skills (optional)</label>\n <div class=\"editor-skills\">\n @for (skill of SkillOptions; track skill.ID) {\n <button type=\"button\" class=\"editor-skill-chip\"\n [class.editor-skill-chip--selected]=\"IsSkillSelected(skill.ID)\"\n [title]=\"skill.Description ?? skill.Name\"\n (click)=\"ToggleSkill(skill.ID)\">\n <i [class]=\"skill.IconClass || 'fa-solid fa-wand-magic-sparkles'\"></i>\n {{ skill.Name }}\n @if (IsSkillSelected(skill.ID)) {\n <i class=\"fa-solid fa-check editor-skill-check\"></i>\n }\n </button>\n }\n </div>\n <div class=\"editor-hint\">Selected skills start every run with their instructions and tools in effect (subject to the agent's skill gates).</div>\n </div>\n }\n </section>\n\n <section class=\"editor-section\">\n <h3 class=\"editor-section-title\"><i class=\"fa-solid fa-bell\"></i> Notifications</h3>\n\n <div class=\"editor-field\">\n <label class=\"editor-label\">Notify me</label>\n <mj-dropdown [Data]=\"NotifyConditionOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"NotifyCondition\"></mj-dropdown>\n </div>\n\n <div class=\"editor-field editor-field--inline editor-switches\">\n <mj-switch [(ngModel)]=\"NotifyViaInApp\" OnLabel=\"In-app\" OffLabel=\"In-app\"></mj-switch>\n <mj-switch [(ngModel)]=\"NotifyViaEmail\" OnLabel=\"Email\" OffLabel=\"Email\"></mj-switch>\n </div>\n\n <div class=\"editor-field\">\n <div class=\"editor-recipients-header\">\n <label class=\"editor-label\">Additional recipients</label>\n <button mjButton variant=\"outline\" size=\"sm\" (click)=\"AddRecipient()\">\n <i class=\"fa-solid fa-plus\"></i> Add recipient\n </button>\n </div>\n @if (Recipients.length === 0) {\n <div class=\"editor-hint\">Only you (the owner) will be notified.</div>\n }\n @for (row of Recipients; track $index; let i = $index; let first = $first; let last = $last) {\n <div class=\"editor-recipient-row\">\n <div class=\"editor-recipient-order\">\n <button mjButton variant=\"icon\" size=\"sm\" title=\"Move up\" [disabled]=\"first\" (click)=\"MoveRecipient(i, -1)\">\n <i class=\"fa-solid fa-chevron-up\"></i>\n </button>\n <button mjButton variant=\"icon\" size=\"sm\" title=\"Move down\" [disabled]=\"last\" (click)=\"MoveRecipient(i, 1)\">\n <i class=\"fa-solid fa-chevron-down\"></i>\n </button>\n </div>\n <mj-dropdown class=\"editor-recipient-mode\" [Data]=\"RecipientModeOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"row.Mode\" (ngModelChange)=\"OnRecipientModeChange(row)\"></mj-dropdown>\n @if (row.Mode === 'user') {\n <mj-combobox class=\"editor-recipient-target\" [Data]=\"UserOptions\" TextField=\"Name\" ValueField=\"ID\"\n [ValuePrimitive]=\"true\" Placeholder=\"Select a user...\" [(ngModel)]=\"row.UserID\"></mj-combobox>\n } @else {\n <input class=\"mj-input editor-recipient-target\" type=\"email\" placeholder=\"name@example.com\" [(ngModel)]=\"row.Email\" />\n }\n <mj-dropdown class=\"editor-recipient-channel\" [Data]=\"ChannelOptions\" TextField=\"text\" ValueField=\"value\"\n [ValuePrimitive]=\"true\" [(ngModel)]=\"row.Channel\"></mj-dropdown>\n <button mjButton variant=\"icon\" size=\"sm\" title=\"Remove recipient\" (click)=\"RemoveRecipient(i)\">\n <i class=\"fa-solid fa-trash-can\"></i>\n </button>\n </div>\n }\n </div>\n </section>\n }\n\n <!-- ======================= Footer (confirm LEFT, cancel RIGHT) ======================= -->\n <div class=\"editor-footer\">\n <button mjButton variant=\"primary\" size=\"md\" [disabled]=\"IsSaving\" (click)=\"Save()\">\n @if (IsSaving) {\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n } @else {\n <i class=\"fa-solid fa-check\"></i>\n }\n {{ IsEdit ? 'Save Changes' : 'Create Routine' }}\n </button>\n <button mjButton variant=\"secondary\" size=\"md\" [disabled]=\"IsSaving\" (click)=\"Cancel()\">Cancel</button>\n </div>\n </div>\n}\n"]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { EventEmitter, OnDestroy } from '@angular/core';
|
|
2
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
|
+
import { MJUserRoutineRunEntity } from '@memberjunction/core-entities';
|
|
4
|
+
import { FormatDuration, FormatRelativeTime, RunStatusVariant } from './routine-ui-helpers';
|
|
5
|
+
import { ConversationOpenedEventArgs, HistoryRecordOpenedEventArgs } from './user-routines-events';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
/** The linked execution record behind a run. */
|
|
8
|
+
export interface RoutineRunLink {
|
|
9
|
+
EntityName: string;
|
|
10
|
+
RecordID: string;
|
|
11
|
+
Label: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Run history for one routine: start time, duration, outcome, result summary, and a
|
|
15
|
+
* link to the underlying execution record (Agent Run / Prompt Run / Action Execution
|
|
16
|
+
* Log) when linked. Data comes from the shared {@link UserRoutineEngine} cache.
|
|
17
|
+
*
|
|
18
|
+
* Reusable (Generic) component: navigation is delegated to the host via the
|
|
19
|
+
* `HistoryRecordOpened` output — no Router usage here.
|
|
20
|
+
*/
|
|
21
|
+
export declare class RoutineHistoryComponent extends BaseAngularComponent implements OnDestroy {
|
|
22
|
+
private cdr;
|
|
23
|
+
private _routineID;
|
|
24
|
+
/** The routine whose runs to show. Setting (or changing) it reloads the list. */
|
|
25
|
+
set RoutineID(value: string | null);
|
|
26
|
+
get RoutineID(): string | null;
|
|
27
|
+
/** Optional display name of the routine (header context only). */
|
|
28
|
+
RoutineName: string | null;
|
|
29
|
+
/** Maximum number of runs to show (most recent first). */
|
|
30
|
+
MaxRuns: number;
|
|
31
|
+
/** The user asked to open the linked execution record — the host owns navigation. */
|
|
32
|
+
HistoryRecordOpened: EventEmitter<HistoryRecordOpenedEventArgs>;
|
|
33
|
+
/** The routine's dedicated conversation was requested from a run row. */
|
|
34
|
+
ConversationOpened: EventEmitter<ConversationOpenedEventArgs>;
|
|
35
|
+
Runs: MJUserRoutineRunEntity[];
|
|
36
|
+
IsLoading: boolean;
|
|
37
|
+
LoadError: string | null;
|
|
38
|
+
readonly RelativeTime: typeof FormatRelativeTime;
|
|
39
|
+
/**
|
|
40
|
+
* Snapshot of each run's relative "started" text (see NG0100 — time-relative
|
|
41
|
+
* values must not be computed inside the template). Rebuilt on load + 30s timer.
|
|
42
|
+
*/
|
|
43
|
+
private startedText;
|
|
44
|
+
private relativeTimer;
|
|
45
|
+
/** Stable-within-a-pass relative "started" text for a run row. */
|
|
46
|
+
StartedText(run: MJUserRoutineRunEntity): string;
|
|
47
|
+
private rebuildRelativeText;
|
|
48
|
+
readonly Duration: typeof FormatDuration;
|
|
49
|
+
readonly RunVariant: typeof RunStatusVariant;
|
|
50
|
+
/** Reloads runs for the current routine from the engine cache. */
|
|
51
|
+
Refresh(forceEngineRefresh?: boolean): Promise<void>;
|
|
52
|
+
/** The linked execution record for a run (null when none of the FKs are set). */
|
|
53
|
+
LinkFor(run: MJUserRoutineRunEntity): RoutineRunLink | null;
|
|
54
|
+
/** The routine's conversation ID, when it has one (agent runs in conversation mode). */
|
|
55
|
+
get RoutineConversationID(): string | null;
|
|
56
|
+
/** Raises ConversationOpened so the host can present the routine's thread. */
|
|
57
|
+
OpenConversation(): void;
|
|
58
|
+
private routine;
|
|
59
|
+
OpenLink(run: MJUserRoutineRunEntity): void;
|
|
60
|
+
ChipClass(status: string | null | undefined): string;
|
|
61
|
+
ngOnDestroy(): void;
|
|
62
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RoutineHistoryComponent, never>;
|
|
63
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RoutineHistoryComponent, "mj-user-routine-history", never, { "RoutineID": { "alias": "RoutineID"; "required": false; }; "RoutineName": { "alias": "RoutineName"; "required": false; }; "MaxRuns": { "alias": "MaxRuns"; "required": false; }; }, { "HistoryRecordOpened": "HistoryRecordOpened"; "ConversationOpened": "ConversationOpened"; }, never, never, false, never>;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=routine-history.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routine-history.component.d.ts","sourceRoot":"","sources":["../../src/lib/routine-history.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgC,YAAY,EAAS,SAAS,EAAkB,MAAM,eAAe,CAAC;AAC7G,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAqB,MAAM,+BAA+B,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;;AAEnG,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,qBAMa,uBAAwB,SAAQ,oBAAqB,YAAW,SAAS;IAClF,OAAO,CAAC,GAAG,CAA6B;IAExC,OAAO,CAAC,UAAU,CAAuB;IACzC,iFAAiF;IACjF,IACW,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAKxC;IACD,IAAW,SAAS,IAAI,MAAM,GAAG,IAAI,CAEpC;IAED,kEAAkE;IACzD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE3C,0DAA0D;IACjD,OAAO,SAAO;IAEvB,qFAAqF;IAC3E,mBAAmB,6CAAoD;IACjF,yEAAyE;IAC/D,kBAAkB,4CAAmD;IAExE,IAAI,EAAE,sBAAsB,EAAE,CAAM;IACpC,SAAS,UAAS;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEvC,SAAgB,YAAY,4BAAsB;IAElD;;;OAGG;IACH,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,aAAa,CAA+C;IAEpE,kEAAkE;IAC3D,WAAW,CAAC,GAAG,EAAE,sBAAsB,GAAG,MAAM;IAIvD,OAAO,CAAC,mBAAmB;IAS3B,SAAgB,QAAQ,wBAAkB;IAC1C,SAAgB,UAAU,0BAAoB;IAE9C,kEAAkE;IACrD,OAAO,CAAC,kBAAkB,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B/D,iFAAiF;IAC1E,OAAO,CAAC,GAAG,EAAE,sBAAsB,GAAG,cAAc,GAAG,IAAI;IAalE,wFAAwF;IACxF,IAAW,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAEhD;IAED,8EAA8E;IACvE,gBAAgB,IAAI,IAAI;IAO/B,OAAO,CAAC,OAAO;IAMR,QAAQ,CAAC,GAAG,EAAE,sBAAsB,GAAG,IAAI;IAU3C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM;IAI3D,WAAW,IAAI,IAAI;yCAvIV,uBAAuB;2CAAvB,uBAAuB;CA4InC"}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { ChangeDetectorRef, Component, EventEmitter, Input, Output, inject } from '@angular/core';
|
|
2
|
+
import { BaseAngularComponent } from '@memberjunction/ng-base-types';
|
|
3
|
+
import { UserRoutineEngine } from '@memberjunction/core-entities';
|
|
4
|
+
import { FormatDuration, FormatRelativeTime, RunStatusVariant } from './routine-ui-helpers';
|
|
5
|
+
import { ConversationOpenedEventArgs, HistoryRecordOpenedEventArgs } from './user-routines-events';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
import * as i1 from "@memberjunction/ng-ui-components";
|
|
8
|
+
import * as i2 from "@memberjunction/ng-shared-generic";
|
|
9
|
+
import * as i3 from "@angular/common";
|
|
10
|
+
const _forTrack0 = ($index, $item) => $item.ID;
|
|
11
|
+
function RoutineHistoryComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
12
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
13
|
+
i0.ɵɵelement(1, "mj-loading", 4);
|
|
14
|
+
i0.ɵɵelementEnd();
|
|
15
|
+
} }
|
|
16
|
+
function RoutineHistoryComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
17
|
+
i0.ɵɵelement(0, "mj-alert", 1);
|
|
18
|
+
} if (rf & 2) {
|
|
19
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
20
|
+
i0.ɵɵproperty("Message", ctx_r0.LoadError);
|
|
21
|
+
} }
|
|
22
|
+
function RoutineHistoryComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
23
|
+
i0.ɵɵelement(0, "mj-empty-state", 2);
|
|
24
|
+
} }
|
|
25
|
+
function RoutineHistoryComponent_Conditional_3_For_2_Conditional_10_Template(rf, ctx) { if (rf & 1) {
|
|
26
|
+
i0.ɵɵelementStart(0, "span", 9);
|
|
27
|
+
i0.ɵɵelement(1, "i", 16);
|
|
28
|
+
i0.ɵɵtext(2);
|
|
29
|
+
i0.ɵɵelementEnd();
|
|
30
|
+
} if (rf & 2) {
|
|
31
|
+
i0.ɵɵadvance(2);
|
|
32
|
+
i0.ɵɵtextInterpolate1(" ", ctx);
|
|
33
|
+
} }
|
|
34
|
+
function RoutineHistoryComponent_Conditional_3_For_2_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
35
|
+
i0.ɵɵelementStart(0, "span", 11);
|
|
36
|
+
i0.ɵɵelement(1, "i", 17);
|
|
37
|
+
i0.ɵɵelementEnd();
|
|
38
|
+
} }
|
|
39
|
+
function RoutineHistoryComponent_Conditional_3_For_2_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
40
|
+
const _r2 = i0.ɵɵgetCurrentView();
|
|
41
|
+
i0.ɵɵelementStart(0, "button", 18);
|
|
42
|
+
i0.ɵɵlistener("click", function RoutineHistoryComponent_Conditional_3_For_2_Conditional_13_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OpenConversation()); });
|
|
43
|
+
i0.ɵɵelement(1, "i", 19);
|
|
44
|
+
i0.ɵɵtext(2, " Conversation ");
|
|
45
|
+
i0.ɵɵelementEnd();
|
|
46
|
+
} }
|
|
47
|
+
function RoutineHistoryComponent_Conditional_3_For_2_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
48
|
+
const _r3 = i0.ɵɵgetCurrentView();
|
|
49
|
+
i0.ɵɵelementStart(0, "button", 20);
|
|
50
|
+
i0.ɵɵlistener("click", function RoutineHistoryComponent_Conditional_3_For_2_Conditional_14_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const run_r4 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OpenLink(run_r4)); });
|
|
51
|
+
i0.ɵɵelement(1, "i", 21);
|
|
52
|
+
i0.ɵɵtext(2);
|
|
53
|
+
i0.ɵɵelementEnd();
|
|
54
|
+
} if (rf & 2) {
|
|
55
|
+
const link_r5 = ctx;
|
|
56
|
+
i0.ɵɵproperty("title", "Open the linked " + link_r5.Label + " record");
|
|
57
|
+
i0.ɵɵadvance(2);
|
|
58
|
+
i0.ɵɵtextInterpolate1(" ", link_r5.Label, " ");
|
|
59
|
+
} }
|
|
60
|
+
function RoutineHistoryComponent_Conditional_3_For_2_Conditional_15_Template(rf, ctx) { if (rf & 1) {
|
|
61
|
+
i0.ɵɵelementStart(0, "div", 14);
|
|
62
|
+
i0.ɵɵtext(1);
|
|
63
|
+
i0.ɵɵelementEnd();
|
|
64
|
+
} if (rf & 2) {
|
|
65
|
+
const run_r4 = i0.ɵɵnextContext().$implicit;
|
|
66
|
+
i0.ɵɵadvance();
|
|
67
|
+
i0.ɵɵtextInterpolate(run_r4.ResultSummary);
|
|
68
|
+
} }
|
|
69
|
+
function RoutineHistoryComponent_Conditional_3_For_2_Conditional_16_Template(rf, ctx) { if (rf & 1) {
|
|
70
|
+
i0.ɵɵelementStart(0, "div", 15);
|
|
71
|
+
i0.ɵɵtext(1);
|
|
72
|
+
i0.ɵɵelementEnd();
|
|
73
|
+
} if (rf & 2) {
|
|
74
|
+
const run_r4 = i0.ɵɵnextContext().$implicit;
|
|
75
|
+
i0.ɵɵadvance();
|
|
76
|
+
i0.ɵɵtextInterpolate(run_r4.ErrorMessage);
|
|
77
|
+
} }
|
|
78
|
+
function RoutineHistoryComponent_Conditional_3_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
79
|
+
i0.ɵɵelementStart(0, "div", 5)(1, "div", 6)(2, "span");
|
|
80
|
+
i0.ɵɵtext(3);
|
|
81
|
+
i0.ɵɵelementEnd();
|
|
82
|
+
i0.ɵɵelementStart(4, "span", 7);
|
|
83
|
+
i0.ɵɵpipe(5, "date");
|
|
84
|
+
i0.ɵɵtext(6);
|
|
85
|
+
i0.ɵɵpipe(7, "date");
|
|
86
|
+
i0.ɵɵelementEnd();
|
|
87
|
+
i0.ɵɵelementStart(8, "span", 8);
|
|
88
|
+
i0.ɵɵtext(9);
|
|
89
|
+
i0.ɵɵelementEnd();
|
|
90
|
+
i0.ɵɵconditionalCreate(10, RoutineHistoryComponent_Conditional_3_For_2_Conditional_10_Template, 3, 1, "span", 9);
|
|
91
|
+
i0.ɵɵelement(11, "span", 10);
|
|
92
|
+
i0.ɵɵconditionalCreate(12, RoutineHistoryComponent_Conditional_3_For_2_Conditional_12_Template, 2, 0, "span", 11);
|
|
93
|
+
i0.ɵɵconditionalCreate(13, RoutineHistoryComponent_Conditional_3_For_2_Conditional_13_Template, 3, 0, "button", 12);
|
|
94
|
+
i0.ɵɵconditionalCreate(14, RoutineHistoryComponent_Conditional_3_For_2_Conditional_14_Template, 3, 2, "button", 13);
|
|
95
|
+
i0.ɵɵelementEnd();
|
|
96
|
+
i0.ɵɵconditionalCreate(15, RoutineHistoryComponent_Conditional_3_For_2_Conditional_15_Template, 2, 1, "div", 14);
|
|
97
|
+
i0.ɵɵconditionalCreate(16, RoutineHistoryComponent_Conditional_3_For_2_Conditional_16_Template, 2, 1, "div", 15);
|
|
98
|
+
i0.ɵɵelementEnd();
|
|
99
|
+
} if (rf & 2) {
|
|
100
|
+
let tmp_16_0;
|
|
101
|
+
let tmp_19_0;
|
|
102
|
+
const run_r4 = ctx.$implicit;
|
|
103
|
+
const ctx_r0 = i0.ɵɵnextContext(2);
|
|
104
|
+
i0.ɵɵadvance(2);
|
|
105
|
+
i0.ɵɵclassMap(ctx_r0.ChipClass(run_r4.Status));
|
|
106
|
+
i0.ɵɵadvance();
|
|
107
|
+
i0.ɵɵtextInterpolate(run_r4.Status);
|
|
108
|
+
i0.ɵɵadvance();
|
|
109
|
+
i0.ɵɵproperty("title", i0.ɵɵpipeBind2(5, 12, run_r4.StartedAt, "long") ?? "");
|
|
110
|
+
i0.ɵɵadvance(2);
|
|
111
|
+
i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(7, 15, run_r4.StartedAt, "medium"));
|
|
112
|
+
i0.ɵɵadvance(3);
|
|
113
|
+
i0.ɵɵtextInterpolate(ctx_r0.StartedText(run_r4));
|
|
114
|
+
i0.ɵɵadvance();
|
|
115
|
+
i0.ɵɵconditional((tmp_16_0 = ctx_r0.Duration(run_r4.StartedAt, run_r4.CompletedAt)) ? 10 : -1, tmp_16_0);
|
|
116
|
+
i0.ɵɵadvance(2);
|
|
117
|
+
i0.ɵɵconditional(run_r4.NotificationSent ? 12 : -1);
|
|
118
|
+
i0.ɵɵadvance();
|
|
119
|
+
i0.ɵɵconditional(ctx_r0.RoutineConversationID ? 13 : -1);
|
|
120
|
+
i0.ɵɵadvance();
|
|
121
|
+
i0.ɵɵconditional((tmp_19_0 = ctx_r0.LinkFor(run_r4)) ? 14 : -1, tmp_19_0);
|
|
122
|
+
i0.ɵɵadvance();
|
|
123
|
+
i0.ɵɵconditional(run_r4.ResultSummary ? 15 : -1);
|
|
124
|
+
i0.ɵɵadvance();
|
|
125
|
+
i0.ɵɵconditional(run_r4.Status === "Failed" && run_r4.ErrorMessage ? 16 : -1);
|
|
126
|
+
} }
|
|
127
|
+
function RoutineHistoryComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
128
|
+
i0.ɵɵelementStart(0, "div", 3);
|
|
129
|
+
i0.ɵɵrepeaterCreate(1, RoutineHistoryComponent_Conditional_3_For_2_Template, 17, 18, "div", 5, _forTrack0);
|
|
130
|
+
i0.ɵɵelementEnd();
|
|
131
|
+
} if (rf & 2) {
|
|
132
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
133
|
+
i0.ɵɵadvance();
|
|
134
|
+
i0.ɵɵrepeater(ctx_r0.Runs);
|
|
135
|
+
} }
|
|
136
|
+
/**
|
|
137
|
+
* Run history for one routine: start time, duration, outcome, result summary, and a
|
|
138
|
+
* link to the underlying execution record (Agent Run / Prompt Run / Action Execution
|
|
139
|
+
* Log) when linked. Data comes from the shared {@link UserRoutineEngine} cache.
|
|
140
|
+
*
|
|
141
|
+
* Reusable (Generic) component: navigation is delegated to the host via the
|
|
142
|
+
* `HistoryRecordOpened` output — no Router usage here.
|
|
143
|
+
*/
|
|
144
|
+
export class RoutineHistoryComponent extends BaseAngularComponent {
|
|
145
|
+
cdr = inject(ChangeDetectorRef);
|
|
146
|
+
_routineID = null;
|
|
147
|
+
/** The routine whose runs to show. Setting (or changing) it reloads the list. */
|
|
148
|
+
set RoutineID(value) {
|
|
149
|
+
if (value !== this._routineID) {
|
|
150
|
+
this._routineID = value;
|
|
151
|
+
void this.Refresh();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
get RoutineID() {
|
|
155
|
+
return this._routineID;
|
|
156
|
+
}
|
|
157
|
+
/** Optional display name of the routine (header context only). */
|
|
158
|
+
RoutineName = null;
|
|
159
|
+
/** Maximum number of runs to show (most recent first). */
|
|
160
|
+
MaxRuns = 100;
|
|
161
|
+
/** The user asked to open the linked execution record — the host owns navigation. */
|
|
162
|
+
HistoryRecordOpened = new EventEmitter();
|
|
163
|
+
/** The routine's dedicated conversation was requested from a run row. */
|
|
164
|
+
ConversationOpened = new EventEmitter();
|
|
165
|
+
Runs = [];
|
|
166
|
+
IsLoading = false;
|
|
167
|
+
LoadError = null;
|
|
168
|
+
RelativeTime = FormatRelativeTime;
|
|
169
|
+
/**
|
|
170
|
+
* Snapshot of each run's relative "started" text (see NG0100 — time-relative
|
|
171
|
+
* values must not be computed inside the template). Rebuilt on load + 30s timer.
|
|
172
|
+
*/
|
|
173
|
+
startedText = new Map();
|
|
174
|
+
relativeTimer = null;
|
|
175
|
+
/** Stable-within-a-pass relative "started" text for a run row. */
|
|
176
|
+
StartedText(run) {
|
|
177
|
+
return this.startedText.get(run.ID) ?? '';
|
|
178
|
+
}
|
|
179
|
+
rebuildRelativeText() {
|
|
180
|
+
this.startedText = new Map(this.Runs.map((r) => [r.ID, FormatRelativeTime(r.StartedAt)]));
|
|
181
|
+
if (this.relativeTimer == null && this.Runs.length > 0) {
|
|
182
|
+
this.relativeTimer = setInterval(() => {
|
|
183
|
+
this.rebuildRelativeText();
|
|
184
|
+
this.cdr.markForCheck();
|
|
185
|
+
}, 30_000);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
Duration = FormatDuration;
|
|
189
|
+
RunVariant = RunStatusVariant;
|
|
190
|
+
/** Reloads runs for the current routine from the engine cache. */
|
|
191
|
+
async Refresh(forceEngineRefresh = false) {
|
|
192
|
+
if (!this._routineID) {
|
|
193
|
+
this.Runs = [];
|
|
194
|
+
this.cdr.markForCheck();
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const routineID = this._routineID;
|
|
198
|
+
this.IsLoading = true;
|
|
199
|
+
this.LoadError = null;
|
|
200
|
+
this.cdr.markForCheck();
|
|
201
|
+
try {
|
|
202
|
+
const p = this.ProviderToUse;
|
|
203
|
+
const engine = UserRoutineEngine.GetProviderInstance(p, UserRoutineEngine);
|
|
204
|
+
await engine.Config(forceEngineRefresh, p.CurrentUser, p);
|
|
205
|
+
if (routineID !== this._routineID) {
|
|
206
|
+
return; // a newer routine selection superseded this load
|
|
207
|
+
}
|
|
208
|
+
this.Runs = engine.RunsForRoutine(routineID, this.MaxRuns);
|
|
209
|
+
this.rebuildRelativeText();
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
this.Runs = [];
|
|
213
|
+
this.LoadError = e instanceof Error ? e.message : 'Failed to load run history.';
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
if (routineID === this._routineID) {
|
|
217
|
+
this.IsLoading = false;
|
|
218
|
+
this.cdr.markForCheck();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/** The linked execution record for a run (null when none of the FKs are set). */
|
|
223
|
+
LinkFor(run) {
|
|
224
|
+
if (run.AgentRunID) {
|
|
225
|
+
return { EntityName: 'MJ: AI Agent Runs', RecordID: run.AgentRunID, Label: 'Agent run' };
|
|
226
|
+
}
|
|
227
|
+
if (run.PromptRunID) {
|
|
228
|
+
return { EntityName: 'MJ: AI Prompt Runs', RecordID: run.PromptRunID, Label: 'Prompt run' };
|
|
229
|
+
}
|
|
230
|
+
if (run.ActionExecutionLogID) {
|
|
231
|
+
return { EntityName: 'MJ: Action Execution Logs', RecordID: run.ActionExecutionLogID, Label: 'Action log' };
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
/** The routine's conversation ID, when it has one (agent runs in conversation mode). */
|
|
236
|
+
get RoutineConversationID() {
|
|
237
|
+
return this.routine()?.ConversationID ?? null;
|
|
238
|
+
}
|
|
239
|
+
/** Raises ConversationOpened so the host can present the routine's thread. */
|
|
240
|
+
OpenConversation() {
|
|
241
|
+
const routine = this.routine();
|
|
242
|
+
if (routine?.ConversationID) {
|
|
243
|
+
this.ConversationOpened.emit(new ConversationOpenedEventArgs(routine.ConversationID, routine));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
routine() {
|
|
247
|
+
const p = this.ProviderToUse;
|
|
248
|
+
const engine = UserRoutineEngine.GetProviderInstance(p, UserRoutineEngine);
|
|
249
|
+
return this._routineID ? (engine.GetRoutineByID(this._routineID) ?? null) : null;
|
|
250
|
+
}
|
|
251
|
+
OpenLink(run) {
|
|
252
|
+
const link = this.LinkFor(run);
|
|
253
|
+
if (link) {
|
|
254
|
+
const p = this.ProviderToUse;
|
|
255
|
+
const engine = UserRoutineEngine.GetProviderInstance(p, UserRoutineEngine);
|
|
256
|
+
const routine = this._routineID ? (engine.GetRoutineByID(this._routineID) ?? null) : null;
|
|
257
|
+
this.HistoryRecordOpened.emit(new HistoryRecordOpenedEventArgs(link.EntityName, link.RecordID, routine));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
ChipClass(status) {
|
|
261
|
+
return `history-chip history-chip--${RunStatusVariant(status)}`;
|
|
262
|
+
}
|
|
263
|
+
ngOnDestroy() {
|
|
264
|
+
if (this.relativeTimer != null) {
|
|
265
|
+
clearInterval(this.relativeTimer);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
static ɵfac = /*@__PURE__*/ (() => { let ɵRoutineHistoryComponent_BaseFactory; return function RoutineHistoryComponent_Factory(__ngFactoryType__) { return (ɵRoutineHistoryComponent_BaseFactory || (ɵRoutineHistoryComponent_BaseFactory = i0.ɵɵgetInheritedFactory(RoutineHistoryComponent)))(__ngFactoryType__ || RoutineHistoryComponent); }; })();
|
|
269
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: RoutineHistoryComponent, selectors: [["mj-user-routine-history"]], inputs: { RoutineID: "RoutineID", RoutineName: "RoutineName", MaxRuns: "MaxRuns" }, outputs: { HistoryRecordOpened: "HistoryRecordOpened", ConversationOpened: "ConversationOpened" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 1, consts: [[1, "history-loading"], ["Variant", "error", 3, "Message"], ["Icon", "fa-solid fa-business-time", "Title", "No Runs Yet", "Message", "This routine hasn't run yet. Once the dispatcher executes it, each run will appear here."], [1, "history-list"], ["text", "Loading run history...", "size", "medium"], [1, "history-row"], [1, "history-row-main"], [1, "history-started", 3, "title"], [1, "history-relative"], [1, "history-duration"], [1, "history-spacer"], ["title", "A notification was sent for this run", 1, "history-notified"], ["mjButton", "", "variant", "outline", "size", "sm", "title", "Open this routine's conversation (all runs appear as turns)"], ["mjButton", "", "variant", "outline", "size", "sm", 3, "title"], [1, "history-summary"], [1, "history-error"], [1, "fa-solid", "fa-stopwatch"], [1, "fa-solid", "fa-bell"], ["mjButton", "", "variant", "outline", "size", "sm", "title", "Open this routine's conversation (all runs appear as turns)", 3, "click"], [1, "fa-solid", "fa-comments"], ["mjButton", "", "variant", "outline", "size", "sm", 3, "click", "title"], [1, "fa-solid", "fa-arrow-up-right-from-square"]], template: function RoutineHistoryComponent_Template(rf, ctx) { if (rf & 1) {
|
|
270
|
+
i0.ɵɵconditionalCreate(0, RoutineHistoryComponent_Conditional_0_Template, 2, 0, "div", 0)(1, RoutineHistoryComponent_Conditional_1_Template, 1, 1, "mj-alert", 1)(2, RoutineHistoryComponent_Conditional_2_Template, 1, 0, "mj-empty-state", 2)(3, RoutineHistoryComponent_Conditional_3_Template, 3, 0, "div", 3);
|
|
271
|
+
} if (rf & 2) {
|
|
272
|
+
i0.ɵɵconditional(ctx.IsLoading ? 0 : ctx.LoadError ? 1 : ctx.Runs.length === 0 ? 2 : 3);
|
|
273
|
+
} }, dependencies: [i1.MJAlertComponent, i1.MJButtonDirective, i1.MJEmptyStateComponent, i2.LoadingComponent, i3.DatePipe], styles: ["[_nghost-%COMP%] {\n display: block;\n}\n\n.history-loading[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n padding: 48px 0;\n}\n\n.history-list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.history-row[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n}\n\n.history-row-main[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.history-started[_ngcontent-%COMP%] {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.history-relative[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.history-duration[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.history-spacer[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n}\n\n.history-notified[_ngcontent-%COMP%] {\n color: var(--mj-status-info);\n font-size: 13px;\n}\n\n.history-summary[_ngcontent-%COMP%] {\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.history-error[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n border: 1px solid var(--mj-status-error-border);\n border-radius: var(--mj-radius-sm, 6px);\n padding: 8px 10px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n\n\n.history-chip[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 11px;\n font-weight: 600;\n white-space: nowrap;\n}\n\n.history-chip--success[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.history-chip--error[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.history-chip--info[_ngcontent-%COMP%] {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n border: 1px solid var(--mj-status-info-border);\n}\n\n.history-chip--muted[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n border: 1px solid var(--mj-border-default);\n}"] });
|
|
274
|
+
}
|
|
275
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(RoutineHistoryComponent, [{
|
|
276
|
+
type: Component,
|
|
277
|
+
args: [{ standalone: false, selector: 'mj-user-routine-history', template: "@if (IsLoading) {\n <div class=\"history-loading\">\n <mj-loading text=\"Loading run history...\" size=\"medium\"></mj-loading>\n </div>\n} @else if (LoadError) {\n <mj-alert Variant=\"error\" [Message]=\"LoadError\"></mj-alert>\n} @else if (Runs.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-business-time\"\n Title=\"No Runs Yet\"\n Message=\"This routine hasn't run yet. Once the dispatcher executes it, each run will appear here.\">\n </mj-empty-state>\n} @else {\n <div class=\"history-list\">\n @for (run of Runs; track run.ID) {\n <div class=\"history-row\">\n <div class=\"history-row-main\">\n <span [class]=\"ChipClass(run.Status)\">{{ run.Status }}</span>\n <span class=\"history-started\" [title]=\"(run.StartedAt | date: 'long') ?? ''\">{{ run.StartedAt | date: 'medium' }}</span>\n <span class=\"history-relative\">{{ StartedText(run) }}</span>\n @if (Duration(run.StartedAt, run.CompletedAt); as duration) {\n <span class=\"history-duration\"><i class=\"fa-solid fa-stopwatch\"></i> {{ duration }}</span>\n }\n <span class=\"history-spacer\"></span>\n @if (run.NotificationSent) {\n <span class=\"history-notified\" title=\"A notification was sent for this run\">\n <i class=\"fa-solid fa-bell\"></i>\n </span>\n }\n @if (RoutineConversationID) {\n <button mjButton variant=\"outline\" size=\"sm\" title=\"Open this routine's conversation (all runs appear as turns)\"\n (click)=\"OpenConversation()\">\n <i class=\"fa-solid fa-comments\"></i> Conversation\n </button>\n }\n @if (LinkFor(run); as link) {\n <button mjButton variant=\"outline\" size=\"sm\" [title]=\"'Open the linked ' + link.Label + ' record'\"\n (click)=\"OpenLink(run)\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> {{ link.Label }}\n </button>\n }\n </div>\n @if (run.ResultSummary) {\n <div class=\"history-summary\">{{ run.ResultSummary }}</div>\n }\n @if (run.Status === 'Failed' && run.ErrorMessage) {\n <div class=\"history-error\">{{ run.ErrorMessage }}</div>\n }\n </div>\n }\n </div>\n}\n", styles: [":host {\n display: block;\n}\n\n.history-loading {\n display: flex;\n justify-content: center;\n padding: 48px 0;\n}\n\n.history-list {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n.history-row {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 14px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md, 8px);\n}\n\n.history-row-main {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n\n.history-started {\n font-size: 13px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\n.history-relative {\n font-size: 12px;\n color: var(--mj-text-muted);\n}\n\n.history-duration {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n color: var(--mj-text-secondary);\n}\n\n.history-spacer {\n flex: 1 1 auto;\n}\n\n.history-notified {\n color: var(--mj-status-info);\n font-size: 13px;\n}\n\n.history-summary {\n font-size: 13px;\n color: var(--mj-text-secondary);\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n.history-error {\n font-size: 12px;\n color: var(--mj-status-error-text);\n background: var(--mj-status-error-bg);\n border: 1px solid var(--mj-status-error-border);\n border-radius: var(--mj-radius-sm, 6px);\n padding: 8px 10px;\n white-space: pre-wrap;\n word-break: break-word;\n}\n\n/* Run status chips */\n.history-chip {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: var(--mj-radius-full, 999px);\n font-size: 11px;\n font-weight: 600;\n white-space: nowrap;\n}\n\n.history-chip--success {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success-text);\n border: 1px solid var(--mj-status-success-border);\n}\n\n.history-chip--error {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error-text);\n border: 1px solid var(--mj-status-error-border);\n}\n\n.history-chip--info {\n background: var(--mj-status-info-bg);\n color: var(--mj-status-info-text);\n border: 1px solid var(--mj-status-info-border);\n}\n\n.history-chip--muted {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n border: 1px solid var(--mj-border-default);\n}\n"] }]
|
|
278
|
+
}], null, { RoutineID: [{
|
|
279
|
+
type: Input
|
|
280
|
+
}], RoutineName: [{
|
|
281
|
+
type: Input
|
|
282
|
+
}], MaxRuns: [{
|
|
283
|
+
type: Input
|
|
284
|
+
}], HistoryRecordOpened: [{
|
|
285
|
+
type: Output
|
|
286
|
+
}], ConversationOpened: [{
|
|
287
|
+
type: Output
|
|
288
|
+
}] }); })();
|
|
289
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(RoutineHistoryComponent, { className: "RoutineHistoryComponent", filePath: "src/lib/routine-history.component.ts", lineNumber: 28 }); })();
|
|
290
|
+
//# sourceMappingURL=routine-history.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routine-history.component.js","sourceRoot":"","sources":["../../src/lib/routine-history.component.ts","../../src/lib/routine-history.component.html"],"names":[],"mappings":"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","sourcesContent":["import { ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, Output, inject } from '@angular/core';\nimport { BaseAngularComponent } from '@memberjunction/ng-base-types';\nimport { MJUserRoutineRunEntity, UserRoutineEngine } from '@memberjunction/core-entities';\nimport { FormatDuration, FormatRelativeTime, RunStatusVariant } from './routine-ui-helpers';\nimport { ConversationOpenedEventArgs, HistoryRecordOpenedEventArgs } from './user-routines-events';\n\n/** The linked execution record behind a run. */\nexport interface RoutineRunLink {\n EntityName: string;\n RecordID: string;\n Label: string;\n}\n\n/**\n * Run history for one routine: start time, duration, outcome, result summary, and a\n * link to the underlying execution record (Agent Run / Prompt Run / Action Execution\n * Log) when linked. Data comes from the shared {@link UserRoutineEngine} cache.\n *\n * Reusable (Generic) component: navigation is delegated to the host via the\n * `HistoryRecordOpened` output — no Router usage here.\n */\n@Component({\n standalone: false,\n selector: 'mj-user-routine-history',\n templateUrl: './routine-history.component.html',\n styleUrls: ['./routine-history.component.css'],\n})\nexport class RoutineHistoryComponent extends BaseAngularComponent implements OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n\n private _routineID: string | null = null;\n /** The routine whose runs to show. Setting (or changing) it reloads the list. */\n @Input()\n public set RoutineID(value: string | null) {\n if (value !== this._routineID) {\n this._routineID = value;\n void this.Refresh();\n }\n }\n public get RoutineID(): string | null {\n return this._routineID;\n }\n\n /** Optional display name of the routine (header context only). */\n @Input() RoutineName: string | null = null;\n\n /** Maximum number of runs to show (most recent first). */\n @Input() MaxRuns = 100;\n\n /** The user asked to open the linked execution record — the host owns navigation. */\n @Output() HistoryRecordOpened = new EventEmitter<HistoryRecordOpenedEventArgs>();\n /** The routine's dedicated conversation was requested from a run row. */\n @Output() ConversationOpened = new EventEmitter<ConversationOpenedEventArgs>();\n\n public Runs: MJUserRoutineRunEntity[] = [];\n public IsLoading = false;\n public LoadError: string | null = null;\n\n public readonly RelativeTime = FormatRelativeTime;\n\n /**\n * Snapshot of each run's relative \"started\" text (see NG0100 — time-relative\n * values must not be computed inside the template). Rebuilt on load + 30s timer.\n */\n private startedText = new Map<string, string>();\n private relativeTimer: ReturnType<typeof setInterval> | null = null;\n\n /** Stable-within-a-pass relative \"started\" text for a run row. */\n public StartedText(run: MJUserRoutineRunEntity): string {\n return this.startedText.get(run.ID) ?? '';\n }\n\n private rebuildRelativeText(): void {\n this.startedText = new Map(this.Runs.map((r) => [r.ID, FormatRelativeTime(r.StartedAt)]));\n if (this.relativeTimer == null && this.Runs.length > 0) {\n this.relativeTimer = setInterval(() => {\n this.rebuildRelativeText();\n this.cdr.markForCheck();\n }, 30_000);\n }\n }\n public readonly Duration = FormatDuration;\n public readonly RunVariant = RunStatusVariant;\n\n /** Reloads runs for the current routine from the engine cache. */\n public async Refresh(forceEngineRefresh = false): Promise<void> {\n if (!this._routineID) {\n this.Runs = [];\n this.cdr.markForCheck();\n return;\n }\n const routineID = this._routineID;\n this.IsLoading = true;\n this.LoadError = null;\n this.cdr.markForCheck();\n try {\n const p = this.ProviderToUse;\n const engine = UserRoutineEngine.GetProviderInstance<UserRoutineEngine>(p, UserRoutineEngine) as UserRoutineEngine;\n await engine.Config(forceEngineRefresh, p.CurrentUser, p);\n if (routineID !== this._routineID) {\n return; // a newer routine selection superseded this load\n }\n this.Runs = engine.RunsForRoutine(routineID, this.MaxRuns);\n this.rebuildRelativeText();\n } catch (e) {\n this.Runs = [];\n this.LoadError = e instanceof Error ? e.message : 'Failed to load run history.';\n } finally {\n if (routineID === this._routineID) {\n this.IsLoading = false;\n this.cdr.markForCheck();\n }\n }\n }\n\n /** The linked execution record for a run (null when none of the FKs are set). */\n public LinkFor(run: MJUserRoutineRunEntity): RoutineRunLink | null {\n if (run.AgentRunID) {\n return { EntityName: 'MJ: AI Agent Runs', RecordID: run.AgentRunID, Label: 'Agent run' };\n }\n if (run.PromptRunID) {\n return { EntityName: 'MJ: AI Prompt Runs', RecordID: run.PromptRunID, Label: 'Prompt run' };\n }\n if (run.ActionExecutionLogID) {\n return { EntityName: 'MJ: Action Execution Logs', RecordID: run.ActionExecutionLogID, Label: 'Action log' };\n }\n return null;\n }\n\n /** The routine's conversation ID, when it has one (agent runs in conversation mode). */\n public get RoutineConversationID(): string | null {\n return this.routine()?.ConversationID ?? null;\n }\n\n /** Raises ConversationOpened so the host can present the routine's thread. */\n public OpenConversation(): void {\n const routine = this.routine();\n if (routine?.ConversationID) {\n this.ConversationOpened.emit(new ConversationOpenedEventArgs(routine.ConversationID, routine));\n }\n }\n\n private routine() {\n const p = this.ProviderToUse;\n const engine = UserRoutineEngine.GetProviderInstance<UserRoutineEngine>(p, UserRoutineEngine) as UserRoutineEngine;\n return this._routineID ? (engine.GetRoutineByID(this._routineID) ?? null) : null;\n }\n\n public OpenLink(run: MJUserRoutineRunEntity): void {\n const link = this.LinkFor(run);\n if (link) {\n const p = this.ProviderToUse;\n const engine = UserRoutineEngine.GetProviderInstance<UserRoutineEngine>(p, UserRoutineEngine) as UserRoutineEngine;\n const routine = this._routineID ? (engine.GetRoutineByID(this._routineID) ?? null) : null;\n this.HistoryRecordOpened.emit(new HistoryRecordOpenedEventArgs(link.EntityName, link.RecordID, routine));\n }\n }\n\n public ChipClass(status: string | null | undefined): string {\n return `history-chip history-chip--${RunStatusVariant(status)}`;\n }\n\n ngOnDestroy(): void {\n if (this.relativeTimer != null) {\n clearInterval(this.relativeTimer);\n }\n }\n}\n","@if (IsLoading) {\n <div class=\"history-loading\">\n <mj-loading text=\"Loading run history...\" size=\"medium\"></mj-loading>\n </div>\n} @else if (LoadError) {\n <mj-alert Variant=\"error\" [Message]=\"LoadError\"></mj-alert>\n} @else if (Runs.length === 0) {\n <mj-empty-state\n Icon=\"fa-solid fa-business-time\"\n Title=\"No Runs Yet\"\n Message=\"This routine hasn't run yet. Once the dispatcher executes it, each run will appear here.\">\n </mj-empty-state>\n} @else {\n <div class=\"history-list\">\n @for (run of Runs; track run.ID) {\n <div class=\"history-row\">\n <div class=\"history-row-main\">\n <span [class]=\"ChipClass(run.Status)\">{{ run.Status }}</span>\n <span class=\"history-started\" [title]=\"(run.StartedAt | date: 'long') ?? ''\">{{ run.StartedAt | date: 'medium' }}</span>\n <span class=\"history-relative\">{{ StartedText(run) }}</span>\n @if (Duration(run.StartedAt, run.CompletedAt); as duration) {\n <span class=\"history-duration\"><i class=\"fa-solid fa-stopwatch\"></i> {{ duration }}</span>\n }\n <span class=\"history-spacer\"></span>\n @if (run.NotificationSent) {\n <span class=\"history-notified\" title=\"A notification was sent for this run\">\n <i class=\"fa-solid fa-bell\"></i>\n </span>\n }\n @if (RoutineConversationID) {\n <button mjButton variant=\"outline\" size=\"sm\" title=\"Open this routine's conversation (all runs appear as turns)\"\n (click)=\"OpenConversation()\">\n <i class=\"fa-solid fa-comments\"></i> Conversation\n </button>\n }\n @if (LinkFor(run); as link) {\n <button mjButton variant=\"outline\" size=\"sm\" [title]=\"'Open the linked ' + link.Label + ' record'\"\n (click)=\"OpenLink(run)\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> {{ link.Label }}\n </button>\n }\n </div>\n @if (run.ResultSummary) {\n <div class=\"history-summary\">{{ run.ResultSummary }}</div>\n }\n @if (run.Status === 'Failed' && run.ErrorMessage) {\n <div class=\"history-error\">{{ run.ErrorMessage }}</div>\n }\n </div>\n }\n </div>\n}\n"]}
|