var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    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;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
/**
 * @fileoverview Knowledge Hub Scheduled Pipelines Dashboard Tab
 *
 * Full-page resource component for managing scheduled pipelines within the
 * Knowledge Hub application. Displays job cards in a compact grid, recent
 * activity table, and provides create/edit via the reusable
 * ScheduledJobDialogComponent from @memberjunction/ng-scheduling.
 *
 * Registered as BaseResourceComponent for the Knowledge Hub application.
 */
import { Component, Input, ChangeDetectorRef, inject } from '@angular/core';
import { Subject } from 'rxjs';
import { RunView, CompositeKey } from '@memberjunction/core';
import { RegisterClass } from '@memberjunction/global';
import { BaseResourceComponent, NavigationService } from '@memberjunction/ng-shared';
import { MJNotificationService } from '@memberjunction/ng-notifications';
import { ScheduledJobService } from '@memberjunction/ng-scheduling';
import { buildSchedulingAgentContext, resolveScheduledJob, buildScheduleNotFoundError, VALID_SCHEDULE_STATUSES, } from './scheduling-agent-context';
import { validateStringParam } from '../../../shared/agent-tool-validation';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@angular/forms";
import * as i3 from "@memberjunction/ng-shared-generic";
import * as i4 from "@memberjunction/ng-ui-components";
import * as i5 from "@memberjunction/ng-scheduling";
const _forTrack0 = ($index, $item) => $item.ID;
function SchedulingResourceComponent_Conditional_0_Conditional_3_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "mj-stat-badge", 3);
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext(2);
    i0.ɵɵproperty("Count", ctx_r1.ActiveCount);
} }
function SchedulingResourceComponent_Conditional_0_Conditional_4_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "mj-stat-badge", 4);
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext(2);
    i0.ɵɵproperty("Count", ctx_r1.PausedCount);
} }
function SchedulingResourceComponent_Conditional_0_ng_container_24_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementContainer(0);
} }
function SchedulingResourceComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
    const _r1 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "mj-page-layout")(1, "mj-page-header", 1)(2, "div", 2);
    i0.ɵɵconditionalCreate(3, SchedulingResourceComponent_Conditional_0_Conditional_3_Template, 1, 1, "mj-stat-badge", 3);
    i0.ɵɵconditionalCreate(4, SchedulingResourceComponent_Conditional_0_Conditional_4_Template, 1, 1, "mj-stat-badge", 4);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(5, "div", 5)(6, "button", 6);
    i0.ɵɵlistener("click", function SchedulingResourceComponent_Conditional_0_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnNewSchedule()); });
    i0.ɵɵelement(7, "i", 7);
    i0.ɵɵelementStart(8, "span", 8);
    i0.ɵɵtext(9, "New Schedule");
    i0.ɵɵelementEnd()()();
    i0.ɵɵelementStart(10, "div", 9)(11, "mj-page-search", 10);
    i0.ɵɵlistener("ValueChange", function SchedulingResourceComponent_Conditional_0_Template_mj_page_search_ValueChange_11_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.SearchQuery = $event; return i0.ɵɵresetView(ctx_r1.OnSearchChanged()); });
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(12, "select", 11);
    i0.ɵɵtwoWayListener("ngModelChange", function SchedulingResourceComponent_Conditional_0_Template_select_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.StatusFilter, $event) || (ctx_r1.StatusFilter = $event); return i0.ɵɵresetView($event); });
    i0.ɵɵlistener("ngModelChange", function SchedulingResourceComponent_Conditional_0_Template_select_ngModelChange_12_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFilterChanged()); });
    i0.ɵɵelementStart(13, "option", 12);
    i0.ɵɵtext(14, "All Statuses");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(15, "option", 13);
    i0.ɵɵtext(16, "Active");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(17, "option", 14);
    i0.ɵɵtext(18, "Paused");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(19, "option", 15);
    i0.ɵɵtext(20, "Disabled");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(21, "option", 16);
    i0.ɵɵtext(22, "Pending");
    i0.ɵɵelementEnd()()()();
    i0.ɵɵelementStart(23, "mj-page-body");
    i0.ɵɵtemplate(24, SchedulingResourceComponent_Conditional_0_ng_container_24_Template, 1, 0, "ng-container", 17);
    i0.ɵɵelementEnd()();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    const schedulingBody_r3 = i0.ɵɵreference(3);
    i0.ɵɵadvance(3);
    i0.ɵɵconditional(ctx_r1.ActiveCount > 0 ? 3 : -1);
    i0.ɵɵadvance();
    i0.ɵɵconditional(ctx_r1.PausedCount > 0 ? 4 : -1);
    i0.ɵɵadvance(7);
    i0.ɵɵproperty("Value", ctx_r1.SearchQuery);
    i0.ɵɵadvance();
    i0.ɵɵtwoWayProperty("ngModel", ctx_r1.StatusFilter);
    i0.ɵɵadvance(12);
    i0.ɵɵproperty("ngTemplateOutlet", schedulingBody_r3);
} }
function SchedulingResourceComponent_Conditional_1_ng_container_17_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementContainer(0);
} }
function SchedulingResourceComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
    const _r4 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "div", 18)(1, "input", 19);
    i0.ɵɵtwoWayListener("ngModelChange", function SchedulingResourceComponent_Conditional_1_Template_input_ngModelChange_1_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.SearchQuery, $event) || (ctx_r1.SearchQuery = $event); return i0.ɵɵresetView($event); });
    i0.ɵɵlistener("ngModelChange", function SchedulingResourceComponent_Conditional_1_Template_input_ngModelChange_1_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnSearchChanged()); });
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(2, "select", 11);
    i0.ɵɵtwoWayListener("ngModelChange", function SchedulingResourceComponent_Conditional_1_Template_select_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r1.StatusFilter, $event) || (ctx_r1.StatusFilter = $event); return i0.ɵɵresetView($event); });
    i0.ɵɵlistener("ngModelChange", function SchedulingResourceComponent_Conditional_1_Template_select_ngModelChange_2_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnFilterChanged()); });
    i0.ɵɵelementStart(3, "option", 12);
    i0.ɵɵtext(4, "All Statuses");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(5, "option", 13);
    i0.ɵɵtext(6, "Active");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(7, "option", 14);
    i0.ɵɵtext(8, "Paused");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(9, "option", 15);
    i0.ɵɵtext(10, "Disabled");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(11, "option", 16);
    i0.ɵɵtext(12, "Pending");
    i0.ɵɵelementEnd()();
    i0.ɵɵelement(13, "span", 20);
    i0.ɵɵelementStart(14, "button", 6);
    i0.ɵɵlistener("click", function SchedulingResourceComponent_Conditional_1_Template_button_click_14_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnNewSchedule()); });
    i0.ɵɵelement(15, "i", 7);
    i0.ɵɵtext(16, " New Schedule ");
    i0.ɵɵelementEnd()();
    i0.ɵɵtemplate(17, SchedulingResourceComponent_Conditional_1_ng_container_17_Template, 1, 0, "ng-container", 17);
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    const schedulingBody_r3 = i0.ɵɵreference(3);
    i0.ɵɵadvance();
    i0.ɵɵtwoWayProperty("ngModel", ctx_r1.SearchQuery);
    i0.ɵɵadvance();
    i0.ɵɵtwoWayProperty("ngModel", ctx_r1.StatusFilter);
    i0.ɵɵadvance(15);
    i0.ɵɵproperty("ngTemplateOutlet", schedulingBody_r3);
} }
function SchedulingResourceComponent_ng_template_2_Conditional_0_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 21);
    i0.ɵɵelement(1, "mj-loading", 22);
    i0.ɵɵelementEnd();
} }
function SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_0_For_2_For_11_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "span", 45);
} if (rf & 2) {
    const dotClass_r8 = ctx.$implicit;
    i0.ɵɵclassMap(dotClass_r8);
} }
function SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_0_For_2_Template(rf, ctx) { if (rf & 1) {
    const _r6 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "div", 31);
    i0.ɵɵlistener("click", function SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_0_For_2_Template_div_click_0_listener() { const job_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r1.OnEditJob(job_r7)); });
    i0.ɵɵelementStart(1, "div", 32);
    i0.ɵɵelement(2, "span", 33);
    i0.ɵɵelementStart(3, "div", 34)(4, "div", 35);
    i0.ɵɵtext(5);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(6, "div", 36);
    i0.ɵɵelement(7, "i", 37);
    i0.ɵɵtext(8);
    i0.ɵɵelementEnd()()();
    i0.ɵɵelementStart(9, "div", 38);
    i0.ɵɵrepeaterCreate(10, SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_0_For_2_For_11_Template, 1, 2, "span", 39, i0.ɵɵrepeaterTrackByIndex);
    i0.ɵɵelementStart(12, "span", 40);
    i0.ɵɵtext(13, "last 7 runs");
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(14, "div", 41)(15, "span", 42);
    i0.ɵɵelement(16, "i", 37);
    i0.ɵɵtext(17, " Last: ");
    i0.ɵɵelementStart(18, "strong");
    i0.ɵɵtext(19);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(20, "span", 42);
    i0.ɵɵelement(21, "i", 43);
    i0.ɵɵelementStart(22, "strong");
    i0.ɵɵtext(23);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(24, "span", 42);
    i0.ɵɵelement(25, "i", 44);
    i0.ɵɵtext(26, " Next: ");
    i0.ɵɵelementStart(27, "strong");
    i0.ɵɵtext(28);
    i0.ɵɵelementEnd()()()();
} if (rf & 2) {
    const job_r7 = ctx.$implicit;
    const ctx_r1 = i0.ɵɵnextContext(4);
    i0.ɵɵclassProp("paused", job_r7.Status === "Paused")("disabled", job_r7.Status === "Disabled");
    i0.ɵɵadvance(2);
    i0.ɵɵclassProp("dot-active", job_r7.Status === "Active")("dot-paused", job_r7.Status === "Paused")("dot-disabled", job_r7.Status === "Disabled");
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(job_r7.Name);
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate1(" ", ctx_r1.GetCronDescription(job_r7.CronExpression), " ");
    i0.ɵɵadvance(2);
    i0.ɵɵrepeater(ctx_r1.GetSparkline(job_r7.ID));
    i0.ɵɵadvance(9);
    i0.ɵɵtextInterpolate(ctx_r1.GetTimeAgo(job_r7.LastRunAt));
    i0.ɵɵadvance(4);
    i0.ɵɵtextInterpolate(ctx_r1.GetSuccessRate(job_r7));
    i0.ɵɵadvance(5);
    i0.ɵɵtextInterpolate(ctx_r1.GetTimeUntil(job_r7.NextRunAt));
} }
function SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 23);
    i0.ɵɵrepeaterCreate(1, SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_0_For_2_Template, 29, 15, "div", 30, _forTrack0);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext(3);
    i0.ɵɵadvance();
    i0.ɵɵrepeater(ctx_r1.FilteredJobs);
} }
function SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_1_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelement(0, "mj-empty-state", 24);
} }
function SchedulingResourceComponent_ng_template_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
    const _r5 = i0.ɵɵgetCurrentView();
    i0.ɵɵconditionalCreate(0, SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_0_Template, 3, 0, "div", 23)(1, SchedulingResourceComponent_ng_template_2_Conditional_1_Conditional_1_Template, 1, 0, "mj-empty-state", 24);
    i0.ɵɵelementStart(2, "div", 25)(3, "button", 26);
    i0.ɵɵlistener("click", function SchedulingResourceComponent_ng_template_2_Conditional_1_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.GoToSchedulingApp()); });
    i0.ɵɵelement(4, "i", 27);
    i0.ɵɵtext(5, " Open Scheduling App ");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(6, "span", 28);
    i0.ɵɵtext(7, "Manage all scheduled jobs across the system");
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(8, "mj-scheduled-job-dialog", 29);
    i0.ɵɵlistener("Close", function SchedulingResourceComponent_ng_template_2_Conditional_1_Template_mj_scheduled_job_dialog_Close_8_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.OnDialogClosed($event)); });
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext(2);
    i0.ɵɵconditional(ctx_r1.FilteredJobs.length > 0 ? 0 : 1);
    i0.ɵɵadvance(8);
    i0.ɵɵproperty("Visible", ctx_r1.ShowEditDialog)("ScheduledJobID", ctx_r1.EditingJobID);
} }
function SchedulingResourceComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵconditionalCreate(0, SchedulingResourceComponent_ng_template_2_Conditional_0_Template, 2, 0, "div", 21)(1, SchedulingResourceComponent_ng_template_2_Conditional_1_Template, 9, 3);
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    i0.ɵɵconditional(ctx_r1.IsLoading ? 0 : 1);
} }
let SchedulingResourceComponent = class SchedulingResourceComponent extends BaseResourceComponent {
    /**
     * When true, renders only the body content (no <mj-page-layout> + <mj-page-header>
     * chrome). Used when embedded inside another resource page (e.g. KH Configuration's
     * Scheduling section) so we don't get nested page-layouts that trap click events.
     *
     * Named `HideToolbar` for cross-section consistency with Scheduling/Testing inner
     * components — see plans/explorer-chrome-conventions.md Section 5. The name is
     * narrower than its actual behavior (suppresses entire chrome, not just the toolbar)
     * but matches the documented convention.
     */
    HideToolbar = false;
    cdr = inject(ChangeDetectorRef);
    navigationService = inject(NavigationService);
    scheduledJobService = inject(ScheduledJobService);
    destroy$ = new Subject();
    // ================================================================
    // Resource overrides
    // ================================================================
    async GetResourceDisplayName(_data) {
        return 'Schedules';
    }
    async GetResourceIconClass(_data) {
        return 'fa-solid fa-clock';
    }
    // ================================================================
    // State
    // ================================================================
    IsLoading = true;
    AllJobs = [];
    FilteredJobs = [];
    RecentRuns = [];
    StatusFilter = '';
    SearchQuery = '';
    /** Map of jobID -> last 7 run statuses for sparkline display */
    sparklineCache = new Map();
    // Edit dialog
    ShowEditDialog = false;
    EditingJobID = null;
    // ================================================================
    // Computed
    // ================================================================
    get ActiveCount() {
        return this.AllJobs.filter(j => j.Status === 'Active').length;
    }
    get PausedCount() {
        return this.AllJobs.filter(j => j.Status === 'Paused').length;
    }
    get DisabledCount() {
        return this.AllJobs.filter(j => j.Status === 'Disabled').length;
    }
    // ================================================================
    // Lifecycle
    // ================================================================
    async ngAfterViewInit() {
        await this.loadData();
        // When embedded in KH Configuration's Scheduling section, that host owns
        // agent reporting; skip here to avoid double-registration.
        if (!this.HideToolbar) {
            this.emitAgentContext();
            this.registerAgentTools();
        }
        this.NotifyLoadComplete();
    }
    // ================================================================
    // Agent context + client tools
    // ================================================================
    /**
     * 🔒 SAFETY BOUNDARY (Knowledge Hub Scheduling surface)
     * -----------------------------------------------------
     * EXPOSED to the agent: idempotent refresh, read-only filter (by status) +
     * search, selection, opening a job's record for VIEWING, and navigation to
     * the full Scheduling application. All resolve job references tolerantly
     * (id → name → contains) and never throw.
     *
     * NEVER EXPOSED (operational mutations — deliberate UI actions only):
     * create a job (OnNewSchedule), edit/save a job (OnEditJob via the dialog),
     * trigger a run (OnRunNow), pause/resume, or delete. The agent may *navigate
     * to* and *open* these, never commit them.
     *
     * No-op when embedded (HideToolbar) — the host surface owns agent reporting.
     */
    /**
     * Publish the scheduling surface state to the AI agent. Re-emitted whenever
     * jobs reload or the filter/search changes, so the streamed context tracks
     * the visible job set. Deep context is shaped by the pure
     * {@link buildSchedulingAgentContext}. No-op when embedded.
     */
    emitAgentContext() {
        if (this.HideToolbar) {
            return;
        }
        this.navigationService.SetAgentContext(this, buildSchedulingAgentContext({
            AllJobs: this.AllJobs.map(j => ({
                ID: j.ID,
                Name: j.Name,
                Description: j.Description,
                Status: j.Status,
                CronExpression: j.CronExpression,
                NextRunAt: j.NextRunAt,
                LastRunAt: j.LastRunAt,
                RunCount: j.RunCount,
                SuccessCount: j.SuccessCount,
            })),
            FilteredJobs: this.FilteredJobs.map(j => ({
                ID: j.ID,
                Name: j.Name,
                Description: j.Description,
                Status: j.Status,
                CronExpression: j.CronExpression,
                NextRunAt: j.NextRunAt,
                LastRunAt: j.LastRunAt,
                RunCount: j.RunCount,
                SuccessCount: j.SuccessCount,
            })),
            StatusFilter: this.StatusFilter,
            SearchQuery: this.SearchQuery,
            RecentRunCount: this.RecentRuns.length,
            IsLoading: this.IsLoading,
        }));
    }
    /**
     * Register the SAFE, agent-actionable operations for the scheduling surface:
     * refresh, filter by status, search, select/open a job (view only), and open
     * the full Scheduling application. All wire to existing methods, resolve job
     * references tolerantly, and never throw. See the SAFETY BOUNDARY above.
     */
    registerAgentTools() {
        this.navigationService.SetAgentClientTools(this, [
            {
                Name: 'RefreshSchedules',
                Description: 'Reload the scheduled jobs and recent run history from the server. Idempotent.',
                ParameterSchema: { type: 'object', properties: {} },
                Handler: async () => {
                    await this.loadData();
                    this.emitAgentContext();
                    return { Success: true, Data: { TotalJobs: this.AllJobs.length } };
                },
            },
            {
                Name: 'FilterSchedulesByStatus',
                Description: 'Filter the scheduled jobs by status. Pass an empty string to clear. Valid statuses: Active, Paused, Disabled. Read-only.',
                ParameterSchema: {
                    type: 'object',
                    properties: { status: { type: 'string', enum: ['', ...VALID_SCHEDULE_STATUSES] } },
                    required: ['status'],
                },
                Handler: async (params) => {
                    const status = String(params['status'] ?? '');
                    if (status && !VALID_SCHEDULE_STATUSES.includes(status)) {
                        return { Success: false, ErrorMessage: `Unknown status "${status}". Expected one of: ${VALID_SCHEDULE_STATUSES.join(', ')}.` };
                    }
                    this.StatusFilter = status;
                    this.OnFilterChanged();
                    return { Success: true, Data: { VisibleJobs: this.FilteredJobs.length } };
                },
            },
            {
                Name: 'SearchSchedules',
                Description: 'Filter the scheduled jobs by a search term (name / description). Pass empty to clear. Read-only.',
                ParameterSchema: {
                    type: 'object',
                    properties: { query: { type: 'string' } },
                    required: ['query'],
                },
                Handler: async (params) => {
                    const v = validateStringParam(params['query'], 'query');
                    if (!v.ok)
                        return v.result;
                    this.SearchQuery = v.value;
                    this.OnSearchChanged();
                    return { Success: true, Data: { VisibleJobs: this.FilteredJobs.length } };
                },
            },
            {
                Name: 'OpenScheduleRecord',
                Description: 'Open a scheduled job\'s record by id or name in a new tab for VIEWING (does NOT edit, run, pause, or delete).',
                ParameterSchema: {
                    type: 'object',
                    properties: { job: { type: 'string', description: 'Scheduled job id or name' } },
                    required: ['job'],
                },
                Handler: async (params) => {
                    const v = validateStringParam(params['job'], 'job');
                    if (!v.ok)
                        return v.result;
                    const match = resolveScheduledJob(v.value, this.AllJobs);
                    if (!match) {
                        return {
                            Success: false,
                            ErrorMessage: buildScheduleNotFoundError(v.value, this.AllJobs.map(j => j.Name)),
                        };
                    }
                    const pkey = new CompositeKey([{ FieldName: 'ID', Value: match.ID }]);
                    this.navigationService.OpenEntityRecord('MJ: Scheduled Jobs', pkey);
                    return { Success: true, Data: { Job: match.Name } };
                },
            },
            {
                Name: 'OpenSchedulingApp',
                Description: 'Navigate to the full Scheduling application to manage all scheduled jobs.',
                ParameterSchema: { type: 'object', properties: {} },
                Handler: async () => {
                    this.GoToSchedulingApp();
                    return { Success: true };
                },
            },
        ]);
    }
    ngOnDestroy() {
        super.ngOnDestroy();
        this.destroy$.next();
        this.destroy$.complete();
    }
    // ================================================================
    // Public Methods — Toolbar
    // ================================================================
    OnNewSchedule() {
        this.EditingJobID = null;
        this.ShowEditDialog = true;
        this.cdr.detectChanges();
    }
    OnFilterChanged() {
        this.applyFilters();
        this.emitAgentContext();
        this.cdr.detectChanges();
    }
    OnSearchChanged() {
        this.applyFilters();
        this.emitAgentContext();
        this.cdr.detectChanges();
    }
    // ================================================================
    // Public Methods — Card Actions
    // ================================================================
    OnEditJob(job) {
        this.EditingJobID = job.ID;
        this.ShowEditDialog = true;
        this.cdr.detectChanges();
    }
    async OnRunNow(job) {
        MJNotificationService.Instance.CreateSimpleNotification(`Triggering "${job.Name}" — this feature requires server-side support.`, 'info', 4000);
    }
    // ================================================================
    // Public Methods — Dialog
    // ================================================================
    async OnDialogClosed(result) {
        this.ShowEditDialog = false;
        this.EditingJobID = null;
        if (result.Saved || result.Deleted) {
            await this.loadData();
            this.emitAgentContext();
        }
        this.cdr.detectChanges();
    }
    /** Navigate to the full Scheduling application */
    GoToSchedulingApp() {
        const md = this.ProviderToUse;
        const schedulingApp = md.Applications.find(a => a.Name === 'Scheduling');
        if (schedulingApp) {
            this.navigationService.SwitchToApp(schedulingApp.ID);
        }
        else {
            MJNotificationService.Instance.CreateSimpleNotification('Scheduling app not found. Check application configuration.', 'warning', 3000);
        }
    }
    // ================================================================
    // Public Methods — Card Display Helpers
    // ================================================================
    GetStatusDotClass(job) {
        return (job.Status ?? 'pending').toLowerCase();
    }
    GetCronDescription(cron) {
        if (!cron)
            return 'No schedule';
        const parts = this.parseCron(cron);
        if (!parts)
            return cron;
        return this.cronToHuman(parts);
    }
    GetSparkline(jobID) {
        return this.sparklineCache.get(jobID) ?? [];
    }
    GetTimeAgo(date) {
        if (!date)
            return 'Never';
        const now = new Date();
        const d = new Date(date);
        const diffMs = now.getTime() - d.getTime();
        return this.formatDuration(diffMs);
    }
    GetTimeUntil(date) {
        if (!date)
            return '--';
        const now = new Date();
        const d = new Date(date);
        const diffMs = d.getTime() - now.getTime();
        if (diffMs <= 0)
            return 'Due';
        return this.formatDuration(diffMs);
    }
    GetSuccessRate(job) {
        if (job.RunCount === 0)
            return 'N/A';
        return Math.round((job.SuccessCount / job.RunCount) * 100) + '%';
    }
    GetSuccessRateClass(job) {
        if (job.RunCount === 0)
            return '';
        const rate = job.SuccessCount / job.RunCount;
        if (rate >= 0.95)
            return 'high';
        if (rate >= 0.80)
            return 'mid';
        return '';
    }
    GetDuration(run) {
        if (!run.StartedAt || !run.CompletedAt)
            return '--';
        const start = new Date(run.StartedAt).getTime();
        const end = new Date(run.CompletedAt).getTime();
        const diffMs = end - start;
        return this.formatDurationShort(diffMs);
    }
    GetItemsProcessed(run) {
        if (!run.Details)
            return '--';
        try {
            const details = JSON.parse(run.Details);
            if (details['ItemsProcessed'] != null) {
                const total = details['TotalItems'];
                const processed = details['ItemsProcessed'];
                if (run.Status === 'Failed' && total != null) {
                    return `${this.formatNumber(processed)} / ${this.formatNumber(total)}`;
                }
                return this.formatNumber(processed);
            }
        }
        catch {
            // details not parseable
        }
        return '--';
    }
    // ================================================================
    // Private Methods
    // ================================================================
    async loadData() {
        this.IsLoading = true;
        this.cdr.detectChanges();
        try {
            const rv = RunView.FromMetadataProvider(this.ProviderToUse);
            const [jobsResult, runsResult] = await rv.RunViews([
                {
                    EntityName: 'MJ: Scheduled Jobs',
                    ExtraFilter: `Name LIKE '%Autotag%' OR Name LIKE '%Vector%' OR Name LIKE '%Content%' OR Name LIKE '%Knowledge%' OR Name LIKE '%Tag%'`,
                    OrderBy: 'Name',
                    ResultType: 'entity_object',
                },
                {
                    EntityName: 'MJ: Scheduled Job Runs',
                    ExtraFilter: '',
                    OrderBy: 'StartedAt DESC',
                    MaxRows: 100,
                    ResultType: 'entity_object',
                },
            ]);
            if (jobsResult.Success) {
                this.AllJobs = jobsResult.Results;
            }
            else {
                this.AllJobs = [];
            }
            const allRuns = runsResult.Success
                ? runsResult.Results
                : [];
            this.RecentRuns = allRuns.slice(0, 10);
            this.buildSparklineCache(allRuns);
            this.applyFilters();
        }
        catch (error) {
            console.error('[SchedulingResource] Error loading data:', error);
            this.AllJobs = [];
            this.FilteredJobs = [];
            this.RecentRuns = [];
        }
        finally {
            this.IsLoading = false;
            this.cdr.detectChanges();
        }
    }
    applyFilters() {
        let jobs = this.AllJobs;
        if (this.StatusFilter) {
            jobs = jobs.filter(j => j.Status === this.StatusFilter);
        }
        if (this.SearchQuery.trim()) {
            const query = this.SearchQuery.trim().toLowerCase();
            jobs = jobs.filter(j => j.Name.toLowerCase().includes(query) ||
                (j.Description ?? '').toLowerCase().includes(query));
        }
        this.FilteredJobs = jobs;
    }
    /**
     * Build sparkline data for each job from the last 7 runs.
     * Each dot is 'ok', 'fail', or 'skip'.
     */
    buildSparklineCache(allRuns) {
        this.sparklineCache.clear();
        // Group runs by job ID
        const runsByJob = new Map();
        for (const run of allRuns) {
            const jobID = run.ScheduledJobID;
            if (!runsByJob.has(jobID)) {
                runsByJob.set(jobID, []);
            }
            runsByJob.get(jobID).push(run);
        }
        // Build sparkline for each job (up to 7 most recent runs)
        for (const job of this.AllJobs) {
            const runs = runsByJob.get(job.ID) ?? [];
            const last7 = runs.slice(0, 7);
            const dots = last7.map(r => this.runStatusToDot(r));
            // Pad to 7 with 'skip' dots if fewer runs
            while (dots.length < 7) {
                dots.push('skip');
            }
            this.sparklineCache.set(job.ID, dots);
        }
    }
    runStatusToDot(run) {
        if (run.Status === 'Completed' && run.Success)
            return 'ok';
        if (run.Status === 'Failed' || (run.Status === 'Completed' && !run.Success))
            return 'fail';
        if (run.Status === 'Running')
            return 'ok'; // treat in-progress as OK
        return 'skip';
    }
    // ================================================================
    // Cron Parsing
    // ================================================================
    parseCron(cron) {
        const parts = cron.trim().split(/\s+/);
        // Support 5-part (no seconds) and 6-part (with seconds) cron
        if (parts.length === 5) {
            return {
                Second: '0',
                Minute: parts[0],
                Hour: parts[1],
                DayOfMonth: parts[2],
                Month: parts[3],
                DayOfWeek: parts[4],
            };
        }
        if (parts.length === 6) {
            return {
                Second: parts[0],
                Minute: parts[1],
                Hour: parts[2],
                DayOfMonth: parts[3],
                Month: parts[4],
                DayOfWeek: parts[5],
            };
        }
        return null;
    }
    cronToHuman(p) {
        // Every N minutes: */N * * * *
        if (p.Minute.startsWith('*/') && p.Hour === '*' && p.DayOfMonth === '*' && p.Month === '*' && p.DayOfWeek === '*') {
            const interval = parseInt(p.Minute.slice(2), 10);
            if (interval === 1)
                return 'Every minute';
            return `Every ${interval} minutes`;
        }
        // Every N hours: 0 */N * * *
        if (p.Minute !== '*' && !p.Minute.includes('/') && p.Hour.startsWith('*/') && p.DayOfMonth === '*') {
            const interval = parseInt(p.Hour.slice(2), 10);
            if (interval === 1)
                return 'Every hour';
            return `Every ${interval} hours`;
        }
        // Specific hour with specific or wildcard day fields
        if (!p.Minute.includes('*') && !p.Minute.includes('/') &&
            !p.Hour.includes('*') && !p.Hour.includes('/') &&
            p.Month === '*') {
            const hour = parseInt(p.Hour, 10);
            const minute = parseInt(p.Minute, 10);
            const timeStr = this.formatTime(hour, minute);
            // Weekly: specific day of week
            if (p.DayOfWeek !== '*' && p.DayOfMonth === '*') {
                const dayName = this.dayOfWeekName(p.DayOfWeek);
                return `Weekly on ${dayName} at ${timeStr}`;
            }
            // Monthly: specific day of month
            if (p.DayOfMonth !== '*' && p.DayOfWeek === '*') {
                return `Monthly on day ${p.DayOfMonth} at ${timeStr}`;
            }
            // Daily
            if (p.DayOfMonth === '*' && p.DayOfWeek === '*') {
                return `Daily at ${timeStr}`;
            }
        }
        // Fallback: return the raw cron expression
        return `${p.Minute} ${p.Hour} ${p.DayOfMonth} ${p.Month} ${p.DayOfWeek}`;
    }
    formatTime(hour, minute) {
        const ampm = hour >= 12 ? 'PM' : 'AM';
        const h = hour === 0 ? 12 : hour > 12 ? hour - 12 : hour;
        const m = minute.toString().padStart(2, '0');
        return `${h}:${m} ${ampm}`;
    }
    dayOfWeekName(dow) {
        const names = {
            '0': 'Sunday', '1': 'Monday', '2': 'Tuesday',
            '3': 'Wednesday', '4': 'Thursday', '5': 'Friday',
            '6': 'Saturday', '7': 'Sunday',
            'SUN': 'Sunday', 'MON': 'Monday', 'TUE': 'Tuesday',
            'WED': 'Wednesday', 'THU': 'Thursday', 'FRI': 'Friday',
            'SAT': 'Saturday',
        };
        return names[dow.toUpperCase()] ?? dow;
    }
    // ================================================================
    // Formatting Helpers
    // ================================================================
    formatDuration(ms) {
        const seconds = Math.floor(ms / 1000);
        const minutes = Math.floor(seconds / 60);
        const hours = Math.floor(minutes / 60);
        const days = Math.floor(hours / 24);
        if (days > 0)
            return `${days}d ago`;
        if (hours > 0)
            return `${hours}h ago`;
        if (minutes > 0)
            return `${minutes}m ago`;
        return 'Just now';
    }
    formatDurationShort(ms) {
        const totalSeconds = Math.floor(ms / 1000);
        const minutes = Math.floor(totalSeconds / 60);
        const seconds = totalSeconds % 60;
        if (minutes >= 60) {
            const hours = Math.floor(minutes / 60);
            const remainMinutes = minutes % 60;
            return `${hours}h ${remainMinutes}m`;
        }
        return `${minutes}m ${seconds.toString().padStart(2, '0')}s`;
    }
    formatNumber(n) {
        return n.toLocaleString();
    }
    static ɵfac = /*@__PURE__*/ (() => { let ɵSchedulingResourceComponent_BaseFactory; return function SchedulingResourceComponent_Factory(__ngFactoryType__) { return (ɵSchedulingResourceComponent_BaseFactory || (ɵSchedulingResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(SchedulingResourceComponent)))(__ngFactoryType__ || SchedulingResourceComponent); }; })();
    static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SchedulingResourceComponent, selectors: [["app-scheduling-resource"]], inputs: { HideToolbar: "HideToolbar" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 4, vars: 2, consts: [["schedulingBody", ""], ["Title", "Knowledge Pipelines", "Icon", "fa-solid fa-calendar-check", "Subtitle", "Scheduled knowledge ingestion, autotagging, and embedding pipelines"], ["meta", ""], ["Label", "active", "Variant", "success", 3, "Count"], ["Label", "paused", "Variant", "warning", 3, "Count"], ["actions", ""], ["mjButton", "", "variant", "primary", "size", "sm", 3, "click"], [1, "fa-solid", "fa-plus"], [1, "action-btn-label"], ["toolbar", ""], ["Placeholder", "Search pipelines...", 3, "ValueChange", "Value"], [1, "mj-input", "kh-toolbar-select", 3, "ngModelChange", "ngModel"], ["value", ""], ["value", "Active"], ["value", "Paused"], ["value", "Disabled"], ["value", "Pending"], [4, "ngTemplateOutlet"], [1, "embedded-controls"], ["type", "text", "placeholder", "Search pipelines...", 1, "mj-input", "embedded-search", 3, "ngModelChange", "ngModel"], [1, "embedded-spacer"], [1, "loading-container"], ["text", "Loading scheduled pipelines..."], [1, "cards-grid"], ["Icon", "fa-regular fa-calendar-xmark", "Title", "No Knowledge Hub schedules found", "Message", "Create a new schedule to automate classification and vector sync"], [1, "scheduling-app-link"], [1, "btn-secondary", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], [1, "link-hint"], [3, "Close", "Visible", "ScheduledJobID"], [1, "job-card", 3, "paused", "disabled"], [1, "job-card", 3, "click"], [1, "card-top"], [1, "status-dot"], [1, "card-title-area"], [1, "card-name"], [1, "card-cron"], [1, "fa-regular", "fa-clock"], [1, "sparkline"], [1, "spark-dot", 3, "class"], [1, "sparkline-label"], [1, "card-stats"], [1, "stat"], [1, "fa-solid", "fa-chart-simple"], [1, "fa-regular", "fa-calendar"], [1, "spark-dot"]], template: function SchedulingResourceComponent_Template(rf, ctx) { if (rf & 1) {
            i0.ɵɵconditionalCreate(0, SchedulingResourceComponent_Conditional_0_Template, 25, 5, "mj-page-layout");
            i0.ɵɵconditionalCreate(1, SchedulingResourceComponent_Conditional_1_Template, 18, 3);
            i0.ɵɵtemplate(2, SchedulingResourceComponent_ng_template_2_Template, 2, 1, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
        } if (rf & 2) {
            i0.ɵɵconditional(!ctx.HideToolbar ? 0 : -1);
            i0.ɵɵadvance();
            i0.ɵɵconditional(ctx.HideToolbar ? 1 : -1);
        } }, dependencies: [i1.NgTemplateOutlet, i2.NgSelectOption, i2.ɵNgSelectMultipleOption, i2.DefaultValueAccessor, i2.SelectControlValueAccessor, i2.NgControlStatus, i2.NgModel, i3.LoadingComponent, i4.MJButtonDirective, i4.MJPageHeaderComponent, i4.MJPageLayoutComponent, i4.MJPageBodyComponent, i4.MJPageSearchComponent, i4.MJStatBadgeComponent, i4.MJEmptyStateComponent, i5.ScheduledJobDialogComponent], styles: ["\n\n[_nghost-%COMP%] {\n    display: flex;\n    flex-direction: column;\n    height: 100%;\n    min-width: 0;\n}\n\n\n\n.embedded-controls[_ngcontent-%COMP%] {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    margin-bottom: 16px;\n}\n\n.embedded-search[_ngcontent-%COMP%] {\n    flex: 1;\n    max-width: 320px;\n}\n\n.embedded-spacer[_ngcontent-%COMP%] {\n    flex: 1;\n}\n\n\n\n.kh-toolbar-select[_ngcontent-%COMP%] {\n    width: auto;\n    min-width: 140px;\n    min-height: 32px;\n    padding: 4px 28px 4px 12px;\n    font-size: 0.8125rem;\n}\n\n\n\n.page-header[_ngcontent-%COMP%] {\n    margin-bottom: 24px;\n}\n.page-header[_ngcontent-%COMP%]   h1[_ngcontent-%COMP%] {\n    font-size: 22px;\n    font-weight: 700;\n    color: var(--mj-text-primary);\n    margin-bottom: 4px;\n}\n.page-header[_ngcontent-%COMP%]   p[_ngcontent-%COMP%] {\n    font-size: 13px;\n    color: var(--mj-text-secondary);\n}\n\n\n\n.toolbar[_ngcontent-%COMP%] {\n    display: flex;\n    align-items: center;\n    gap: 12px;\n    margin-bottom: 20px;\n    flex-wrap: wrap;\n}\n.btn-primary[_ngcontent-%COMP%] {\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n    padding: 8px 16px;\n    background: var(--mj-brand-primary);\n    color: var(--mj-text-inverse);\n    border: none;\n    border-radius: var(--mj-radius-sm, 6px);\n    font-size: 13px;\n    font-weight: 600;\n    cursor: pointer;\n    transition: background 0.15s;\n    white-space: nowrap;\n}\n.btn-primary[_ngcontent-%COMP%]:hover {\n    background: var(--mj-brand-primary-hover);\n}\n.filter-select[_ngcontent-%COMP%] {\n    padding: 7px 32px 7px 12px;\n    border: 1px solid var(--mj-border-default);\n    border-radius: var(--mj-radius-sm, 6px);\n    font-size: 13px;\n    color: var(--mj-text-primary);\n    background: var(--mj-bg-surface);\n    appearance: none;\n    background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2394a3b8'/%3E%3C/svg%3E\");\n    background-repeat: no-repeat;\n    background-position: right 10px center;\n    cursor: pointer;\n}\n.search-input[_ngcontent-%COMP%] {\n    padding: 7px 12px 7px 32px;\n    border: 1px solid var(--mj-border-default);\n    border-radius: var(--mj-radius-sm, 6px);\n    font-size: 13px;\n    color: var(--mj-text-primary);\n    background: var(--mj-bg-surface);\n    width: 220px;\n    background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='%2394a3b8'%3E%3Cpath d='M10 6.5a3.5 3.5 0 11-7 0 3.5 3.5 0 017 0zm-.3 3.9a5.5 5.5 0 111.1-1.1l3.1 3.1a.75.75 0 01-1.1 1.1L9.7 10.4z'/%3E%3C/svg%3E\");\n    background-repeat: no-repeat;\n    background-position: 10px center;\n}\n.search-input[_ngcontent-%COMP%]::placeholder {\n    color: var(--mj-text-muted);\n}\n.toolbar-spacer[_ngcontent-%COMP%] {\n    flex: 1;\n}\n.toolbar-stat[_ngcontent-%COMP%] {\n    font-size: 12px;\n    color: var(--mj-text-muted);\n}\n.toolbar-stat[_ngcontent-%COMP%]   strong[_ngcontent-%COMP%] {\n    color: var(--mj-text-secondary);\n    font-weight: 600;\n}\n\n\n\n.card-grid[_ngcontent-%COMP%] {\n    display: grid;\n    grid-template-columns: repeat(3, 1fr);\n    gap: 14px;\n    margin-bottom: 32px;\n}\n@media (max-width: 1024px) {\n    .card-grid[_ngcontent-%COMP%] { grid-template-columns: repeat(2, 1fr); }\n}\n@media (max-width: 640px) {\n    .card-grid[_ngcontent-%COMP%] { grid-template-columns: 1fr; }\n}\n\n\n\n.job-card[_ngcontent-%COMP%] {\n    background: var(--mj-bg-surface);\n    border: 1px solid var(--mj-border-default);\n    border-radius: var(--mj-radius-md, 8px);\n    padding: 14px 16px;\n    box-shadow: var(--mj-shadow-card, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));\n    position: relative;\n    cursor: pointer;\n    transition: box-shadow 0.2s, border-color 0.2s;\n    height: 132px;\n    display: flex;\n    flex-direction: column;\n    justify-content: space-between;\n}\n.job-card[_ngcontent-%COMP%]:hover {\n    box-shadow: var(--mj-shadow-card-hover, 0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04));\n    border-color: var(--mj-border-strong);\n}\n.job-card[_ngcontent-%COMP%]:hover   .card-actions[_ngcontent-%COMP%] {\n    opacity: 1;\n}\n.job-card.disabled-card[_ngcontent-%COMP%] {\n    opacity: 0.65;\n}\n\n.card-top[_ngcontent-%COMP%] {\n    display: flex;\n    align-items: flex-start;\n    gap: 8px;\n}\n.status-dot[_ngcontent-%COMP%] {\n    width: 9px;\n    height: 9px;\n    border-radius: 50%;\n    flex-shrink: 0;\n    margin-top: 4px;\n}\n.status-dot.active[_ngcontent-%COMP%] {\n    background: var(--mj-status-success);\n    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 18%, transparent);\n}\n.status-dot.paused[_ngcontent-%COMP%] {\n    background: var(--mj-status-warning);\n    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 18%, transparent);\n}\n.status-dot.disabled[_ngcontent-%COMP%], \n.status-dot.pending[_ngcontent-%COMP%], \n.status-dot.expired[_ngcontent-%COMP%] {\n    background: var(--mj-border-strong);\n}\n\n.card-title-area[_ngcontent-%COMP%] {\n    flex: 1;\n    min-width: 0;\n}\n.card-title[_ngcontent-%COMP%] {\n    font-size: 13.5px;\n    font-weight: 650;\n    color: var(--mj-text-primary);\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    line-height: 1.3;\n}\n.card-cron[_ngcontent-%COMP%] {\n    font-size: 12px;\n    color: var(--mj-text-secondary);\n    margin-top: 1px;\n    display: flex;\n    align-items: center;\n    gap: 5px;\n}\n.card-cron[_ngcontent-%COMP%]   i[_ngcontent-%COMP%] {\n    font-size: 11px;\n    color: var(--mj-text-muted);\n}\n\n\n\n.card-stats[_ngcontent-%COMP%] {\n    display: flex;\n    align-items: center;\n    gap: 16px;\n    font-size: 11.5px;\n    color: var(--mj-text-muted);\n}\n.card-stat[_ngcontent-%COMP%] {\n    display: flex;\n    align-items: center;\n    gap: 4px;\n}\n.card-stat[_ngcontent-%COMP%]   i[_ngcontent-%COMP%] {\n    font-size: 10px;\n}\n.card-stat[_ngcontent-%COMP%]   .value[_ngcontent-%COMP%] {\n    color: var(--mj-text-secondary);\n    font-weight: 600;\n}\n.success-rate[_ngcontent-%COMP%] {\n    font-weight: 700;\n}\n.success-rate.high[_ngcontent-%COMP%] {\n    color: var(--mj-status-success);\n}\n.success-rate.mid[_ngcontent-%COMP%] {\n    color: var(--mj-status-warning);\n}\n\n\n\n.sparkline[_ngcontent-%COMP%] {\n    display: flex;\n    align-items: center;\n    gap: 3px;\n    margin-top: 8px;\n}\n.spark-dot[_ngcontent-%COMP%] {\n    width: 7px;\n    height: 7px;\n    border-radius: 50%;\n}\n.spark-dot.ok[_ngcontent-%COMP%] {\n    background: color-mix(in srgb, var(--mj-status-success) 65%, transparent);\n}\n.spark-dot.fail[_ngcontent-%COMP%] {\n    background: color-mix(in srgb, var(--mj-status-error) 65%, transparent);\n}\n.spark-dot.skip[_ngcontent-%COMP%] {\n    background: var(--mj-border-default);\n}\n.sparkline-label[_ngcontent-%COMP%] {\n    font-size: 10px;\n    color: var(--mj-text-muted);\n    margin-left: 4px;\n}\n\n\n\n.card-actions[_ngcontent-%COMP%] {\n    position: absolute;\n    top: 10px;\n    right: 10px;\n    display: flex;\n    gap: 6px;\n    opacity: 0;\n    transition: opacity 0.15s;\n}\n.card-action-btn[_ngcontent-%COMP%] {\n    padding: 4px 10px;\n    font-size: 11px;\n    font-weight: 600;\n    border-radius: 4px;\n    border: 1px solid var(--mj-border-default);\n    background: var(--mj-bg-surface);\n    color: var(--mj-text-secondary);\n    cursor: pointer;\n    transition: all 0.12s;\n    box-shadow: 0 1px 2px rgba(0,0,0,0.06);\n}\n.card-action-btn[_ngcontent-%COMP%]:hover {\n    background: var(--mj-bg-surface-hover);\n    color: var(--mj-text-primary);\n    border-color: var(--mj-border-strong);\n}\n.card-action-btn.run-now[_ngcontent-%COMP%] {\n    background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n    color: var(--mj-brand-primary);\n    border-color: color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-border-default));\n}\n.card-action-btn.run-now[_ngcontent-%COMP%]:hover {\n    background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n}\n\n\n\n.card-status-label[_ngcontent-%COMP%] {\n    font-weight: 600;\n    font-size: 11.5px;\n    display: flex;\n    align-items: center;\n    gap: 4px;\n}\n.card-status-label.paused[_ngcontent-%COMP%] {\n    color: var(--mj-status-warning);\n}\n.card-status-label.disabled[_ngcontent-%COMP%] {\n    color: var(--mj-text-muted);\n}\n\n\n\n.section-header[_ngcontent-%COMP%] {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    margin-bottom: 14px;\n}\n.section-header[_ngcontent-%COMP%]   h2[_ngcontent-%COMP%] {\n    font-size: 15px;\n    font-weight: 650;\n    color: var(--mj-text-primary);\n}\n.section-header[_ngcontent-%COMP%]   .badge[_ngcontent-%COMP%] {\n    font-size: 11px;\n    font-weight: 600;\n    color: var(--mj-text-muted);\n    background: var(--mj-bg-surface-sunken);\n    padding: 2px 8px;\n    border-radius: 10px;\n}\n\n\n\n.activity-table[_ngcontent-%COMP%] {\n    width: 100%;\n    background: var(--mj-bg-surface);\n    border: 1px solid var(--mj-border-default);\n    border-radius: var(--mj-radius-md, 8px);\n    box-shadow: var(--mj-shadow-card, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));\n    overflow: hidden;\n}\n.activity-table[_ngcontent-%COMP%]   table[_ngcontent-%COMP%] {\n    width: 100%;\n    border-collapse: collapse;\n    font-size: 13px;\n}\n.activity-table[_ngcontent-%COMP%]   thead[_ngcontent-%COMP%]   th[_ngcontent-%COMP%] {\n    background: var(--mj-bg-surface-card);\n    padding: 10px 14px;\n    text-align: left;\n    font-weight: 600;\n    color: var(--mj-text-secondary);\n    font-size: 11.5px;\n    text-transform: uppercase;\n    letter-spacing: 0.04em;\n    border-bottom: 1px solid var(--mj-border-default);\n}\n.activity-table[_ngcontent-%COMP%]   tbody[_ngcontent-%COMP%]   td[_ngcontent-%COMP%] {\n    padding: 9px 14px;\n    border-bottom: 1px solid var(--mj-border-subtle);\n    color: var(--mj-text-primary);\n}\n.activity-table[_ngcontent-%COMP%]   tbody[_ngcontent-%COMP%]   tr[_ngcontent-%COMP%]:last-child   td[_ngcontent-%COMP%] {\n    border-bottom: none;\n}\n.activity-table[_ngcontent-%COMP%]   tbody[_ngcontent-%COMP%]   tr[_ngcontent-%COMP%]:hover {\n    background: var(--mj-bg-surface-hover);\n}\n.activity-table[_ngcontent-%COMP%]   .job-name-cell[_ngcontent-%COMP%] {\n    font-weight: 600;\n    color: var(--mj-text-primary);\n}\n.activity-table[_ngcontent-%COMP%]   .time-cell[_ngcontent-%COMP%] {\n    color: var(--mj-text-secondary);\n    font-size: 12.5px;\n}\n.items-cell[_ngcontent-%COMP%] {\n    text-align: right;\n    font-weight: 600;\n}\n.items-cell.failed[_ngcontent-%COMP%] {\n    color: var(--mj-status-error);\n}\n\n\n\n.status-badge[_ngcontent-%COMP%] {\n    display: inline-flex;\n    align-items: center;\n    gap: 4px;\n    padding: 2px 10px;\n    border-radius: 10px;\n    font-size: 11.5px;\n    font-weight: 600;\n}\n.status-badge.success[_ngcontent-%COMP%] {\n    background: var(--mj-status-success-bg);\n    color: var(--mj-status-success);\n}\n.status-badge.failed[_ngcontent-%COMP%] {\n    background: var(--mj-status-error-bg);\n    color: var(--mj-status-error);\n}\n.status-badge.running[_ngcontent-%COMP%] {\n    background: var(--mj-status-info-bg);\n    color: var(--mj-status-info);\n}\n.status-badge[_ngcontent-%COMP%]   i[_ngcontent-%COMP%] {\n    font-size: 9px;\n}\n\n\n\n.loading-container[_ngcontent-%COMP%] {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    padding: 60px;\n}\n\n\n\n.scheduling-app-link[_ngcontent-%COMP%] {\n    display: flex;\n    align-items: center;\n    gap: 12px;\n    margin-top: 20px;\n    padding-top: 16px;\n    border-top: 1px solid var(--mj-border-default);\n}\n\n.btn-secondary[_ngcontent-%COMP%] {\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n    padding: 7px 14px;\n    border: 1px solid var(--mj-border-default);\n    border-radius: 6px;\n    background: var(--mj-bg-surface);\n    color: var(--mj-text-secondary);\n    font-size: 12px;\n    font-weight: 500;\n    cursor: pointer;\n    transition: all 0.15s ease;\n}\n\n.btn-secondary[_ngcontent-%COMP%]:hover {\n    border-color: var(--mj-brand-primary);\n    color: var(--mj-brand-primary);\n    background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.link-hint[_ngcontent-%COMP%] {\n    font-size: 11px;\n    color: var(--mj-text-muted);\n}"] });
};
SchedulingResourceComponent = __decorate([
    RegisterClass(BaseResourceComponent, 'SchedulingResource')
], SchedulingResourceComponent);
export { SchedulingResourceComponent };
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SchedulingResourceComponent, [{
        type: Component,
        args: [{ standalone: false, selector: 'app-scheduling-resource', template: "@if (!HideToolbar) {\n<mj-page-layout>\n  <mj-page-header\n    Title=\"Knowledge Pipelines\"\n    Icon=\"fa-solid fa-calendar-check\"\n    Subtitle=\"Scheduled knowledge ingestion, autotagging, and embedding pipelines\">\n    <div meta>\n      @if (ActiveCount > 0) {\n        <mj-stat-badge [Count]=\"ActiveCount\" Label=\"active\" Variant=\"success\"></mj-stat-badge>\n      }\n      @if (PausedCount > 0) {\n        <mj-stat-badge [Count]=\"PausedCount\" Label=\"paused\" Variant=\"warning\"></mj-stat-badge>\n      }\n    </div>\n    <div actions>\n      <button mjButton variant=\"primary\" size=\"sm\" (click)=\"OnNewSchedule()\">\n        <i class=\"fa-solid fa-plus\"></i> <span class=\"action-btn-label\">New Schedule</span>\n      </button>\n    </div>\n    <div toolbar>\n      <mj-page-search\n        Placeholder=\"Search pipelines...\"\n        [Value]=\"SearchQuery\"\n        (ValueChange)=\"SearchQuery = $event; OnSearchChanged()\">\n      </mj-page-search>\n      <select class=\"mj-input kh-toolbar-select\" [(ngModel)]=\"StatusFilter\" (ngModelChange)=\"OnFilterChanged()\">\n        <option value=\"\">All Statuses</option>\n        <option value=\"Active\">Active</option>\n        <option value=\"Paused\">Paused</option>\n        <option value=\"Disabled\">Disabled</option>\n        <option value=\"Pending\">Pending</option>\n      </select>\n    </div>\n  </mj-page-header>\n\n  <mj-page-body>\n    <ng-container *ngTemplateOutlet=\"schedulingBody\"></ng-container>\n  </mj-page-body>\n</mj-page-layout>\n}\n@if (HideToolbar) {\n  <div class=\"embedded-controls\">\n    <input\n      type=\"text\"\n      class=\"mj-input embedded-search\"\n      placeholder=\"Search pipelines...\"\n      [(ngModel)]=\"SearchQuery\"\n      (ngModelChange)=\"OnSearchChanged()\" />\n    <select class=\"mj-input kh-toolbar-select\" [(ngModel)]=\"StatusFilter\" (ngModelChange)=\"OnFilterChanged()\">\n      <option value=\"\">All Statuses</option>\n      <option value=\"Active\">Active</option>\n      <option value=\"Paused\">Paused</option>\n      <option value=\"Disabled\">Disabled</option>\n      <option value=\"Pending\">Pending</option>\n    </select>\n    <span class=\"embedded-spacer\"></span>\n    <button mjButton variant=\"primary\" size=\"sm\" (click)=\"OnNewSchedule()\">\n      <i class=\"fa-solid fa-plus\"></i> New Schedule\n    </button>\n  </div>\n  <ng-container *ngTemplateOutlet=\"schedulingBody\"></ng-container>\n}\n\n<ng-template #schedulingBody>\n@if (IsLoading) {\n    <div class=\"loading-container\">\n        <mj-loading text=\"Loading scheduled pipelines...\"></mj-loading>\n    </div>\n} @else {\n    <!-- Job Cards Grid -->\n    @if (FilteredJobs.length > 0) {\n        <div class=\"cards-grid\">\n            @for (job of FilteredJobs; track job.ID) {\n                <div class=\"job-card\"\n                     [class.paused]=\"job.Status === 'Paused'\"\n                     [class.disabled]=\"job.Status === 'Disabled'\"\n                     (click)=\"OnEditJob(job)\">\n                    <div class=\"card-top\">\n                        <span class=\"status-dot\"\n                              [class.dot-active]=\"job.Status === 'Active'\"\n                              [class.dot-paused]=\"job.Status === 'Paused'\"\n                              [class.dot-disabled]=\"job.Status === 'Disabled'\"></span>\n                        <div class=\"card-title-area\">\n                            <div class=\"card-name\">{{ job.Name }}</div>\n                            <div class=\"card-cron\">\n                                <i class=\"fa-regular fa-clock\"></i>\n                                {{ GetCronDescription(job.CronExpression) }}\n                            </div>\n                        </div>\n                    </div>\n                    <div class=\"sparkline\">\n                        @for (dotClass of GetSparkline(job.ID); track $index) {\n                            <span class=\"spark-dot\" [class]=\"dotClass\"></span>\n                        }\n                        <span class=\"sparkline-label\">last 7 runs</span>\n                    </div>\n                    <div class=\"card-stats\">\n                        <span class=\"stat\">\n                            <i class=\"fa-regular fa-clock\"></i>\n                            Last: <strong>{{ GetTimeAgo(job.LastRunAt) }}</strong>\n                        </span>\n                        <span class=\"stat\">\n                            <i class=\"fa-solid fa-chart-simple\"></i>\n                            <strong>{{ GetSuccessRate(job) }}</strong>\n                        </span>\n                        <span class=\"stat\">\n                            <i class=\"fa-regular fa-calendar\"></i>\n                            Next: <strong>{{ GetTimeUntil(job.NextRunAt) }}</strong>\n                        </span>\n                    </div>\n                </div>\n            }\n        </div>\n    } @else {\n        <mj-empty-state Icon=\"fa-regular fa-calendar-xmark\"\n            Title=\"No Knowledge Hub schedules found\"\n            Message=\"Create a new schedule to automate classification and vector sync\" />\n    }\n\n    <!-- Link to full Scheduling App -->\n    <div class=\"scheduling-app-link\">\n        <button class=\"btn-secondary\" (click)=\"GoToSchedulingApp()\">\n            <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open Scheduling App\n        </button>\n        <span class=\"link-hint\">Manage all scheduled jobs across the system</span>\n    </div>\n\n    <!-- Edit Dialog -->\n    <mj-scheduled-job-dialog\n        [Visible]=\"ShowEditDialog\"\n        [ScheduledJobID]=\"EditingJobID\"\n        (Close)=\"OnDialogClosed($event)\">\n    </mj-scheduled-job-dialog>\n}\n</ng-template>\n", styles: ["/* \u2500\u2500 Host \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host {\n    display: flex;\n    flex-direction: column;\n    height: 100%;\n    min-width: 0;\n}\n\n/* Embedded mode: inline controls row instead of <mj-page-header>. */\n.embedded-controls {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    margin-bottom: 16px;\n}\n\n.embedded-search {\n    flex: 1;\n    max-width: 320px;\n}\n\n.embedded-spacer {\n    flex: 1;\n}\n\n/* Status select used in the [toolbar] slot. */\n.kh-toolbar-select {\n    width: auto;\n    min-width: 140px;\n    min-height: 32px;\n    padding: 4px 28px 4px 12px;\n    font-size: 0.8125rem;\n}\n\n/* \u2500\u2500 Page Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.page-header {\n    margin-bottom: 24px;\n}\n.page-header h1 {\n    font-size: 22px;\n    font-weight: 700;\n    color: var(--mj-text-primary);\n    margin-bottom: 4px;\n}\n.page-header p {\n    font-size: 13px;\n    color: var(--mj-text-secondary);\n}\n\n/* \u2500\u2500 Toolbar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.toolbar {\n    display: flex;\n    align-items: center;\n    gap: 12px;\n    margin-bottom: 20px;\n    flex-wrap: wrap;\n}\n.btn-primary {\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n    padding: 8px 16px;\n    background: var(--mj-brand-primary);\n    color: var(--mj-text-inverse);\n    border: none;\n    border-radius: var(--mj-radius-sm, 6px);\n    font-size: 13px;\n    font-weight: 600;\n    cursor: pointer;\n    transition: background 0.15s;\n    white-space: nowrap;\n}\n.btn-primary:hover {\n    background: var(--mj-brand-primary-hover);\n}\n.filter-select {\n    padding: 7px 32px 7px 12px;\n    border: 1px solid var(--mj-border-default);\n    border-radius: var(--mj-radius-sm, 6px);\n    font-size: 13px;\n    color: var(--mj-text-primary);\n    background: var(--mj-bg-surface);\n    appearance: none;\n    background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2394a3b8'/%3E%3C/svg%3E\");\n    background-repeat: no-repeat;\n    background-position: right 10px center;\n    cursor: pointer;\n}\n.search-input {\n    padding: 7px 12px 7px 32px;\n    border: 1px solid var(--mj-border-default);\n    border-radius: var(--mj-radius-sm, 6px);\n    font-size: 13px;\n    color: var(--mj-text-primary);\n    background: var(--mj-bg-surface);\n    width: 220px;\n    background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' fill='%2394a3b8'%3E%3Cpath d='M10 6.5a3.5 3.5 0 11-7 0 3.5 3.5 0 017 0zm-.3 3.9a5.5 5.5 0 111.1-1.1l3.1 3.1a.75.75 0 01-1.1 1.1L9.7 10.4z'/%3E%3C/svg%3E\");\n    background-repeat: no-repeat;\n    background-position: 10px center;\n}\n.search-input::placeholder {\n    color: var(--mj-text-muted);\n}\n.toolbar-spacer {\n    flex: 1;\n}\n.toolbar-stat {\n    font-size: 12px;\n    color: var(--mj-text-muted);\n}\n.toolbar-stat strong {\n    color: var(--mj-text-secondary);\n    font-weight: 600;\n}\n\n/* \u2500\u2500 Card Grid \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.card-grid {\n    display: grid;\n    grid-template-columns: repeat(3, 1fr);\n    gap: 14px;\n    margin-bottom: 32px;\n}\n@media (max-width: 1024px) {\n    .card-grid { grid-template-columns: repeat(2, 1fr); }\n}\n@media (max-width: 640px) {\n    .card-grid { grid-template-columns: 1fr; }\n}\n\n/* \u2500\u2500 Job Card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.job-card {\n    background: var(--mj-bg-surface);\n    border: 1px solid var(--mj-border-default);\n    border-radius: var(--mj-radius-md, 8px);\n    padding: 14px 16px;\n    box-shadow: var(--mj-shadow-card, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));\n    position: relative;\n    cursor: pointer;\n    transition: box-shadow 0.2s, border-color 0.2s;\n    height: 132px;\n    display: flex;\n    flex-direction: column;\n    justify-content: space-between;\n}\n.job-card:hover {\n    box-shadow: var(--mj-shadow-card-hover, 0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04));\n    border-color: var(--mj-border-strong);\n}\n.job-card:hover .card-actions {\n    opacity: 1;\n}\n.job-card.disabled-card {\n    opacity: 0.65;\n}\n\n.card-top {\n    display: flex;\n    align-items: flex-start;\n    gap: 8px;\n}\n.status-dot {\n    width: 9px;\n    height: 9px;\n    border-radius: 50%;\n    flex-shrink: 0;\n    margin-top: 4px;\n}\n.status-dot.active {\n    background: var(--mj-status-success);\n    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-success) 18%, transparent);\n}\n.status-dot.paused {\n    background: var(--mj-status-warning);\n    box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-status-warning) 18%, transparent);\n}\n.status-dot.disabled,\n.status-dot.pending,\n.status-dot.expired {\n    background: var(--mj-border-strong);\n}\n\n.card-title-area {\n    flex: 1;\n    min-width: 0;\n}\n.card-title {\n    font-size: 13.5px;\n    font-weight: 650;\n    color: var(--mj-text-primary);\n    white-space: nowrap;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    line-height: 1.3;\n}\n.card-cron {\n    font-size: 12px;\n    color: var(--mj-text-secondary);\n    margin-top: 1px;\n    display: flex;\n    align-items: center;\n    gap: 5px;\n}\n.card-cron i {\n    font-size: 11px;\n    color: var(--mj-text-muted);\n}\n\n/* Stats row */\n.card-stats {\n    display: flex;\n    align-items: center;\n    gap: 16px;\n    font-size: 11.5px;\n    color: var(--mj-text-muted);\n}\n.card-stat {\n    display: flex;\n    align-items: center;\n    gap: 4px;\n}\n.card-stat i {\n    font-size: 10px;\n}\n.card-stat .value {\n    color: var(--mj-text-secondary);\n    font-weight: 600;\n}\n.success-rate {\n    font-weight: 700;\n}\n.success-rate.high {\n    color: var(--mj-status-success);\n}\n.success-rate.mid {\n    color: var(--mj-status-warning);\n}\n\n/* Sparkline */\n.sparkline {\n    display: flex;\n    align-items: center;\n    gap: 3px;\n    margin-top: 8px;\n}\n.spark-dot {\n    width: 7px;\n    height: 7px;\n    border-radius: 50%;\n}\n.spark-dot.ok {\n    background: color-mix(in srgb, var(--mj-status-success) 65%, transparent);\n}\n.spark-dot.fail {\n    background: color-mix(in srgb, var(--mj-status-error) 65%, transparent);\n}\n.spark-dot.skip {\n    background: var(--mj-border-default);\n}\n.sparkline-label {\n    font-size: 10px;\n    color: var(--mj-text-muted);\n    margin-left: 4px;\n}\n\n/* Hover actions */\n.card-actions {\n    position: absolute;\n    top: 10px;\n    right: 10px;\n    display: flex;\n    gap: 6px;\n    opacity: 0;\n    transition: opacity 0.15s;\n}\n.card-action-btn {\n    padding: 4px 10px;\n    font-size: 11px;\n    font-weight: 600;\n    border-radius: 4px;\n    border: 1px solid var(--mj-border-default);\n    background: var(--mj-bg-surface);\n    color: var(--mj-text-secondary);\n    cursor: pointer;\n    transition: all 0.12s;\n    box-shadow: 0 1px 2px rgba(0,0,0,0.06);\n}\n.card-action-btn:hover {\n    background: var(--mj-bg-surface-hover);\n    color: var(--mj-text-primary);\n    border-color: var(--mj-border-strong);\n}\n.card-action-btn.run-now {\n    background: color-mix(in srgb, var(--mj-brand-primary) 8%, var(--mj-bg-surface));\n    color: var(--mj-brand-primary);\n    border-color: color-mix(in srgb, var(--mj-brand-primary) 25%, var(--mj-border-default));\n}\n.card-action-btn.run-now:hover {\n    background: color-mix(in srgb, var(--mj-brand-primary) 14%, var(--mj-bg-surface));\n}\n\n/* Paused/disabled status on card */\n.card-status-label {\n    font-weight: 600;\n    font-size: 11.5px;\n    display: flex;\n    align-items: center;\n    gap: 4px;\n}\n.card-status-label.paused {\n    color: var(--mj-status-warning);\n}\n.card-status-label.disabled {\n    color: var(--mj-text-muted);\n}\n\n/* \u2500\u2500 Section Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.section-header {\n    display: flex;\n    align-items: center;\n    gap: 8px;\n    margin-bottom: 14px;\n}\n.section-header h2 {\n    font-size: 15px;\n    font-weight: 650;\n    color: var(--mj-text-primary);\n}\n.section-header .badge {\n    font-size: 11px;\n    font-weight: 600;\n    color: var(--mj-text-muted);\n    background: var(--mj-bg-surface-sunken);\n    padding: 2px 8px;\n    border-radius: 10px;\n}\n\n/* \u2500\u2500 Activity Table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.activity-table {\n    width: 100%;\n    background: var(--mj-bg-surface);\n    border: 1px solid var(--mj-border-default);\n    border-radius: var(--mj-radius-md, 8px);\n    box-shadow: var(--mj-shadow-card, 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04));\n    overflow: hidden;\n}\n.activity-table table {\n    width: 100%;\n    border-collapse: collapse;\n    font-size: 13px;\n}\n.activity-table thead th {\n    background: var(--mj-bg-surface-card);\n    padding: 10px 14px;\n    text-align: left;\n    font-weight: 600;\n    color: var(--mj-text-secondary);\n    font-size: 11.5px;\n    text-transform: uppercase;\n    letter-spacing: 0.04em;\n    border-bottom: 1px solid var(--mj-border-default);\n}\n.activity-table tbody td {\n    padding: 9px 14px;\n    border-bottom: 1px solid var(--mj-border-subtle);\n    color: var(--mj-text-primary);\n}\n.activity-table tbody tr:last-child td {\n    border-bottom: none;\n}\n.activity-table tbody tr:hover {\n    background: var(--mj-bg-surface-hover);\n}\n.activity-table .job-name-cell {\n    font-weight: 600;\n    color: var(--mj-text-primary);\n}\n.activity-table .time-cell {\n    color: var(--mj-text-secondary);\n    font-size: 12.5px;\n}\n.items-cell {\n    text-align: right;\n    font-weight: 600;\n}\n.items-cell.failed {\n    color: var(--mj-status-error);\n}\n\n/* Status badges */\n.status-badge {\n    display: inline-flex;\n    align-items: center;\n    gap: 4px;\n    padding: 2px 10px;\n    border-radius: 10px;\n    font-size: 11.5px;\n    font-weight: 600;\n}\n.status-badge.success {\n    background: var(--mj-status-success-bg);\n    color: var(--mj-status-success);\n}\n.status-badge.failed {\n    background: var(--mj-status-error-bg);\n    color: var(--mj-status-error);\n}\n.status-badge.running {\n    background: var(--mj-status-info-bg);\n    color: var(--mj-status-info);\n}\n.status-badge i {\n    font-size: 9px;\n}\n\n/* \u2500\u2500 Loading \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.loading-container {\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    padding: 60px;\n}\n\n/* Scheduling App Link */\n.scheduling-app-link {\n    display: flex;\n    align-items: center;\n    gap: 12px;\n    margin-top: 20px;\n    padding-top: 16px;\n    border-top: 1px solid var(--mj-border-default);\n}\n\n.btn-secondary {\n    display: inline-flex;\n    align-items: center;\n    gap: 6px;\n    padding: 7px 14px;\n    border: 1px solid var(--mj-border-default);\n    border-radius: 6px;\n    background: var(--mj-bg-surface);\n    color: var(--mj-text-secondary);\n    font-size: 12px;\n    font-weight: 500;\n    cursor: pointer;\n    transition: all 0.15s ease;\n}\n\n.btn-secondary:hover {\n    border-color: var(--mj-brand-primary);\n    color: var(--mj-brand-primary);\n    background: color-mix(in srgb, var(--mj-brand-primary) 5%, var(--mj-bg-surface));\n}\n\n.link-hint {\n    font-size: 11px;\n    color: var(--mj-text-muted);\n}\n"] }]
    }], null, { HideToolbar: [{
            type: Input
        }] }); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SchedulingResourceComponent, { className: "SchedulingResourceComponent", filePath: "src/KnowledgeHub/components/scheduling/scheduling-resource.component.ts", lineNumber: 45 }); })();
/** Tree-shaking prevention */
export function LoadSchedulingResource() {
    // Prevents tree-shaking of the component
}
//# sourceMappingURL=scheduling-resource.component.js.map