import { faSave as farSave } from "@fortawesome/free-regular-svg-icons"; import { faDownload, faEdit, faHistory, faMagic, faPencilAlt, faPlay, faPlus, faRecycle, faSave, faSignOutAlt, faSitemap, faWrench, } from "@fortawesome/free-solid-svg-icons"; import { watchImmediate } from "@vueuse/core"; import { faDiagramNext, faSearch } from "font-awesome-6"; import { computed, type ComputedRef, type Ref } from "vue"; import { useActivityStore } from "@/stores/activityStore"; import type { Activity } from "@/stores/activityStoreTypes"; import type { LintData } from "./useLinting"; export function useWorkflowActivities( /** The ID of the activity bar these activities belong to (set to "workflow-editor" for now) */ activityBarId: string, /** Whether the workflow being edited is a new workflow that has not been created/saved yet */ isNewTempWorkflow: Ref, /** Whether the workflow has unsaved changes */ hasChanges: Ref, /** How many changes before we get back to the last saved state */ undoStackLength: Ref, /** Whether the user can use custom tools */ canUseUnprivilegedTools: Ref, ): ComputedRef { const store = useActivityStore(activityBarId); // Disable running the workflow if it is new and has not been created watchImmediate( () => isNewTempWorkflow.value, (value) => { store.setMeta("workflow-run", "disabled", value); }, ); // Disable saving the workflow if there are no changes to save watchImmediate( () => hasChanges.value, (value) => { store.setMeta("save-workflow", "disabled", !value); }, ); // Return a computed list of workflow editor activities return computed(() => [ { title: "Attributes", id: "workflow-editor-attributes", tooltip: "Edit workflow attributes", description: "View and edit the attributes of this workflow.", panel: true, icon: faPencilAlt, visible: true, }, { title: "Search", id: "workflow-editor-search", tooltip: "Search the contents of this workflow", description: "Search the contents of this workflow.", panel: true, icon: faSearch, visible: true, }, { title: "Inputs", id: "workflow-editor-inputs", tooltip: "Add input steps to your workflow", description: "Add input steps to your workflow.", icon: faDiagramNext, panel: true, visible: true, }, { title: "Tools", id: "workflow-editor-tools", description: "Displays the tool panel to search and place all available tools.", icon: faWrench, panel: true, tooltip: "Search tools to use in your workflow", visible: true, }, { title: "Workflows", id: "workflow-editor-workflows", description: "Browse other workflows and add them as sub-workflows.", tooltip: "Search workflows to use in your workflow", icon: faSitemap, panel: true, visible: true, optional: true, }, { title: "Report", id: "workflow-editor-report", description: "Edit the report for this workflow.", tooltip: "Edit workflow report", icon: faEdit, panel: true, visible: true, optional: true, }, { title: "Changes", id: "workflow-undo-redo", description: "View, undo, and redo your latest changes.", tooltip: "Show and manage latest changes", icon: faHistory, panel: true, visible: true, optional: true, indicator: undoStackLength.value, indicatorVariant: "primary", }, { title: "Run", id: "workflow-run", description: "Run this workflow with specific parameters.", tooltip: "Run workflow", icon: faPlay, visible: true, click: true, optional: true, }, { description: "Save this workflow.", icon: faSave, id: "save-workflow", title: "Save", tooltip: hasChanges.value ? "Save current changes" : "No changes to save", visible: true, click: true, optional: true, }, { description: "Save this workflow with a different name and annotation.", icon: farSave, id: "save-workflow-as", title: "Save as", tooltip: "Save a copy of this workflow", visible: true, click: true, optional: true, }, { title: "Upgrade", id: "workflow-upgrade", description: "Update all tools used in this workflow.", tooltip: "Update all tools", icon: faRecycle, visible: true, click: true, optional: true, }, ...(canUseUnprivilegedTools.value ? [ { description: "Insert custom tools.", icon: faWrench, id: "workflow-editor-user-defined-tools", optional: true, panel: true, title: "Custom Tools", to: null, tooltip: "List and create user-defined tools", visible: true, }, ] : []), { title: "Download", id: "workflow-download", description: "Download this workflow in '.ga' format.", tooltip: "Download workflow", icon: faDownload, visible: true, click: true, optional: true, }, { description: "Save this workflow and create a new workflow.", icon: faPlus, title: "Create new", id: "workflow-create", tooltip: "Save this workflow and create a new one", visible: true, click: true, optional: true, }, { description: "Exit the workflow editor and return to the start screen.", icon: faSignOutAlt, id: "exit", title: "Exit", tooltip: "Exit workflow editor", visible: false, click: true, optional: true, }, ]); } interface SpecialActivityOptions { hasInvalidConnections: boolean; lintData: LintData; } export function useSpecialWorkflowActivities(options: Ref) { const saveHover = computed(() => { if (options.value.hasInvalidConnections) { return "Workflow has invalid connections, review and remove invalid connections"; } else { return "Save this workflow, then exit the workflow editor"; } }); /** Indicator for best practices activity * @returns * - `number`: count of critical issues remaining * - `true`: non-critical issues remaining (renders exclamation icon) * - `undefined`: no issues remaining */ const bestPracticesIndicator = computed(() => { const { resolvedPriorityIssues, totalPriorityIssues, resolvedAttributeIssues, totalAttributeIssues } = options.value.lintData; if (totalPriorityIssues.value > resolvedPriorityIssues.value) { return totalPriorityIssues.value - resolvedPriorityIssues.value; } else if (totalAttributeIssues.value > resolvedAttributeIssues.value) { return true; } return undefined; }); /** Helper function to create issue description with proper pluralization */ function getIssueDescription(count: number, type: "critical" | "minor"): string { const issueWord = count === 1 ? "issue" : "issues"; const remainWord = count === 1 ? "remains" : "remain"; return `${count} ${type} best practice ${issueWord} ${remainWord}`; } /** Tooltip for best practices activity */ const bestPracticeHover = computed(() => { const { resolvedPriorityIssues, totalPriorityIssues, resolvedAttributeIssues, totalAttributeIssues } = options.value.lintData; const criticalCount = totalPriorityIssues.value - resolvedPriorityIssues.value; const nonCriticalCount = totalAttributeIssues.value - resolvedAttributeIssues.value; if (criticalCount > 0) { return getIssueDescription(criticalCount, "critical"); } else if (nonCriticalCount > 0) { return getIssueDescription(nonCriticalCount, "minor"); } else { return "Test workflow for best practices"; } }); const specialWorkflowActivities = computed(() => [ { title: "Best Practices", id: "workflow-best-practices", description: "Show and test for the best practices in this workflow.", tooltip: bestPracticeHover.value, indicator: bestPracticesIndicator.value, indicatorVariant: typeof bestPracticesIndicator.value === "number" ? "danger" : "primary", icon: faMagic, panel: true, visible: true, optional: true, }, ]); const exitWorkflowActivity = computed(() => ({ description: "", icon: faSave, id: "save-and-exit", title: "Save + Exit", tooltip: saveHover.value, visible: false, click: true, mutable: false, })); return { specialWorkflowActivities, exitWorkflowActivity, }; }