mirror of
https://github.com/nextcloud/server.git
synced 2026-10-31 18:15:57 +01:00
Signed-off-by: nextcloud-command <nextcloud-command@users.noreply.github.com>
1 line
113 KiB
Plaintext
1 line
113 KiB
Plaintext
{"version":3,"file":"workflowengine-workflowengine.mjs","sources":["../build/frontend/apps/workflowengine/src/helpers/contrast.ts","../build/frontend/apps/workflowengine/src/components/Operation.vue","../build/frontend/apps/workflowengine/src/composables/useCustomElementEvents.ts","../build/frontend/apps/workflowengine/src/logger.ts","../build/frontend/apps/workflowengine/src/types.ts","../build/frontend/apps/workflowengine/src/helpers/api.ts","../build/frontend/apps/workflowengine/src/store.ts","../build/frontend/apps/workflowengine/src/components/Check.vue","../build/frontend/apps/workflowengine/src/components/Event.vue","../build/frontend/apps/workflowengine/src/components/Rule.vue","../build/frontend/apps/workflowengine/img/workflow-off.svg?raw","../build/frontend/apps/workflowengine/src/components/Workflow.vue","../build/frontend/apps/workflowengine/src/composables/useCheckValue.ts","../build/frontend/apps/workflowengine/src/components/Checks/SelectWithCustomValue.vue","../build/frontend/apps/workflowengine/src/components/Checks/FileMimeType.vue","../build/frontend/apps/workflowengine/src/components/Checks/FileSystemTag.vue","../build/frontend/apps/workflowengine/src/helpers/customElements.ts","../build/frontend/apps/workflowengine/src/helpers/validators.ts","../build/frontend/apps/workflowengine/src/components/Checks/file.ts","../build/frontend/apps/workflowengine/src/helpers/timezones.ts","../build/frontend/apps/workflowengine/src/components/Checks/RequestTime.vue","../build/frontend/apps/workflowengine/src/components/Checks/RequestURL.vue","../build/frontend/apps/workflowengine/src/components/Checks/RequestUserAgent.vue","../build/frontend/apps/workflowengine/src/components/Checks/RequestUserGroup.vue","../build/frontend/apps/workflowengine/src/components/Checks/request.ts","../build/frontend/apps/workflowengine/src/components/Checks/index.ts","../build/frontend/apps/workflowengine/src/workflowengine.ts"],"sourcesContent":["/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport Color from 'color'\n\n/** Text colour to use when no better one can be determined. */\nexport const DEFAULT_TEXT_COLOR = 'var(--color-main-text)'\n\n/** Smallest contrast ratio that still counts as readable. */\nconst MINIMUM_CONTRAST = 4.5\n\n/**\n * The text colour of a background that is known without resolving it first.\n *\n * Returns `null` for a background whose actual colour only the browser knows,\n * for instance a custom property an app registered its operation with.\n *\n * @param backgroundColor - The background as the operation declares it\n */\nexport function knownTextColor(backgroundColor: string): string | null {\n\tif (backgroundColor === 'transparent') {\n\t\treturn DEFAULT_TEXT_COLOR\n\t}\n\tif (backgroundColor === 'var(--color-primary-element)') {\n\t\treturn 'var(--color-primary-element-text)'\n\t}\n\treturn null\n}\n\n/**\n * The text colour that reads on a resolved background colour.\n *\n * @param backgroundColor - A colour value, e.g. `#ff5900` or `rgb(255, 89, 0)`\n */\nexport function contrastingTextColor(backgroundColor: string): string {\n\ttry {\n\t\tconst contrast = Color(backgroundColor).contrast(Color('#ffffff'))\n\t\treturn contrast > MINIMUM_CONTRAST ? '#ffffff' : '#000000'\n\t} catch {\n\t\treturn DEFAULT_TEXT_COLOR\n\t}\n}\n\n/**\n * The filter that keeps a dark icon visible on its background.\n *\n * @param textColor - The text colour that was picked for the background\n */\nexport function iconFilterFor(textColor: string): string {\n\treturn textColor === '#000000' ? 'invert(100%)' : 'none'\n}\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div\n\t\tref=\"operationElement\"\n\t\t:class=\"[$style.actions__item, { [$style.colored]: colored }]\">\n\t\t<div\n\t\t\t:class=\"[$style.icon, operation.iconClass]\"\n\t\t\t:style=\"{ backgroundImage: operation.iconClass ? '' : `url(${operation.icon})` }\" />\n\t\t<div :class=\"$style.actions__item__description\">\n\t\t\t<h3>{{ operation.name }}</h3>\n\t\t\t<small>{{ operation.description }}</small>\n\t\t\t<NcButton v-if=\"colored\">\n\t\t\t\t{{ t('workflowengine', 'Add new flow') }}\n\t\t\t</NcButton>\n\t\t</div>\n\t\t<div :class=\"$style.actions__item_options\">\n\t\t\t<slot />\n\t\t</div>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\n/* eslint vue/multi-word-component-names: \"warn\" */\n\nimport type { OperationCard } from '../types.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport { computed, nextTick, ref, watch } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport { contrastingTextColor, DEFAULT_TEXT_COLOR, iconFilterFor, knownTextColor } from '../helpers/contrast.ts'\n\nconst props = defineProps<{\n\toperation: OperationCard\n\tcolored?: boolean\n}>()\n\nconst operationElement = ref<HTMLDivElement>()\nconst color = ref(DEFAULT_TEXT_COLOR)\nconst backgroundColor = computed(() => props.colored ? (props.operation.color || 'var(--color-primary-element)') : 'transparent')\n\nwatch(backgroundColor, async () => {\n\tconst known = knownTextColor(backgroundColor.value)\n\tif (known !== null) {\n\t\tcolor.value = known\n\t\treturn\n\t}\n\n\tlet resolved = backgroundColor.value\n\tif (!resolved.startsWith('#')) {\n\t\t// only the browser knows what a custom property resolves to\n\t\tawait nextTick()\n\t\tresolved = window.getComputedStyle(operationElement.value!).backgroundColor\n\t}\n\tcolor.value = contrastingTextColor(resolved)\n}, { immediate: true })\n\n/** Filter to apply to the icon to make it accessible on the given background color. */\nconst iconFilter = computed(() => iconFilterFor(color.value))\n</script>\n\n<style module lang=\"scss\">\n@use \"./../styles/operation.scss\" as *;\n\n.actions__item {\n\tcolor: v-bind('color');\n\tbackground-color: v-bind('backgroundColor');\n\n\th3 {\n\t\tcolor: v-bind('color');\n\t}\n\n\t.icon {\n\t\tfilter: v-bind('iconFilter');\n\t}\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { Ref } from 'vue'\n\nimport { onScopeDispose, watch } from 'vue'\n\ntype CustomElementHandlers = Record<string, (event: CustomEvent<unknown[]>) => void>\n\n/**\n * Listen to the events a custom element dispatches.\n *\n * A template listener would not do: Vue takes every `onUpdate:*` listener for\n * the v-model listener of a component and never attaches it to a DOM element,\n * so `update:model-value` of a custom element would never arrive.\n *\n * @param element - The custom element, as long as it is rendered\n * @param handlers - The handler to run per event name\n */\nexport function useCustomElementEvents(\n\telement: Ref<Element | null | undefined>,\n\thandlers: CustomElementHandlers,\n): void {\n\tconst entries = Object.entries(handlers) as [string, EventListener][]\n\n\tfunction subscribe(target: Element | null | undefined): void {\n\t\tentries.forEach(([name, handler]) => target?.addEventListener(name, handler))\n\t}\n\n\tfunction unsubscribe(target: Element | null | undefined): void {\n\t\tentries.forEach(([name, handler]) => target?.removeEventListener(name, handler))\n\t}\n\n\twatch(element, (current, previous) => {\n\t\tunsubscribe(previous)\n\t\tsubscribe(current)\n\t}, { immediate: true, flush: 'post' })\n\n\tonScopeDispose(() => unsubscribe(element.value))\n}\n","/*!\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport { getLoggerBuilder } from '@nextcloud/logger'\n\nexport const logger = getLoggerBuilder()\n\t.detectLogLevel()\n\t.setApp('workflowengine')\n\t.build()\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\n/** Whether a flow applies to the whole instance or to a single account. */\nexport const Scope = {\n\tADMIN: 0,\n\tPERSONAL: 1,\n} as const\n\nexport type ScopeValue = typeof Scope[keyof typeof Scope]\n\n/** A comparison a check offers, e.g. \"is\" or \"does not match\". */\nexport interface Comparison {\n\t/** Value the comparison is stored as, e.g. `!less` */\n\toperator: string\n\t/** Translated readable text, e.g. \"less or equals\" */\n\tname: string\n}\n\n/** One condition of a flow. */\nexport interface Check {\n\t/** PHP class of the check, `null` while the row is still empty */\n\tclass: string | null\n\toperator: string | null\n\tvalue: string\n\t/** Set by the check editor when the value does not satisfy the check */\n\tinvalid?: boolean\n}\n\n/** A configured flow. Unsaved flows carry a negative id. */\nexport interface Rule {\n\tid: number\n\t/** PHP class of the operation this flow runs */\n\tclass: string\n\tname: string\n\tentity: string\n\tevents: string[]\n\toperation: string\n\tchecks: Check[]\n\tvalid?: boolean\n}\n\n/** A check as the server advertises it. */\nexport interface ServerCheck {\n\tid: string\n\t/** Empty means the check applies to every entity */\n\tsupportedEntities: string[]\n\tsupportedEvents: string[]\n}\n\n/** An event an entity can emit. */\nexport interface EntityEvent {\n\teventName: string\n\tdisplayName: string\n}\n\n/** An entity flows can be triggered by, e.g. a file. */\nexport interface Entity {\n\tid: string\n\ticon: string\n\tname: string\n\tevents: EntityEvent[]\n}\n\n/** An entity event, flattened with the entity it belongs to. */\nexport interface FlatEntityEvent extends EntityEvent {\n\tid: string\n\tentity: Entity\n}\n\n/**\n * A plugin that provides the value editor of a check.\n *\n * Registered through `window.OCA.WorkflowEngine.registerCheck()`.\n */\nexport interface CheckPlugin {\n\t/** PHP class name of the check */\n\tclass: string\n\tname: string\n\t/** Either a fixed list or a function deriving it from the current check */\n\toperators: Comparison[] | ((check: Check) => Comparison[])\n\t/** Placeholder for the plain value input, when no element is provided */\n\tplaceholder?: (check: Check) => string\n\t/** Validates the value, when no element is provided */\n\tvalidate?: (check: Check) => boolean\n\t/**\n\t * Id of a custom element as passed to `window.customElements.define()`,\n\t * prefixed with the app namespace. It receives `model-value`, `operator` and\n\t * `disabled`, and emits `update:model-value`, `valid` and `invalid`.\n\t */\n\telement?: string\n}\n\n/** What the card of an operation shows. */\nexport interface OperationCard {\n\tname: string\n\tdescription: string\n\ticon: string\n\ticonClass?: string\n\t/** Colour of the card, defaults to the primary element colour */\n\tcolor?: string\n}\n\n/**\n * A plugin that describes an operation on the flow settings page.\n *\n * Registered through `window.OCA.WorkflowEngine.registerOperator()`.\n */\nexport interface OperatorPlugin extends OperationCard {\n\t/** PHP class name of the operation */\n\tid: string\n\t/** Default value of the operation field */\n\toperation: string\n\tfixedEntity: string\n\tisComplex: boolean\n\ttriggerHint: string\n\tentities?: string[]\n\t/**\n\t * Id of a custom element as passed to `window.customElements.define()`,\n\t * prefixed with the app namespace. It receives `model-value` and emits\n\t * `update:model-value`.\n\t */\n\telement?: string\n}\n\n/** One of the values a check offers besides free text. */\nexport interface PredefinedValue {\n\t/** The value that gets stored */\n\tid: string\n\tlabel: string\n\t/** A global icon class */\n\ticon?: string\n\t/** An image to show instead of an icon class */\n\ticonUrl?: string\n}\n\n/** The api apps register their plugins through. */\nexport interface WorkflowEngineApi {\n\tregisterCheck(plugin: CheckPlugin): void\n\tregisterOperator(plugin: OperatorPlugin): void\n}\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { ScopeValue } from '../types.ts'\n\nimport { generateOcsUrl } from '@nextcloud/router'\nimport { Scope } from '../types.ts'\n\n/**\n * The OCS endpoint of the flows of a scope.\n *\n * @param scope - Whether to address the instance-wide or the personal flows\n * @param path - Path appended to the endpoint, e.g. `/3` to address one flow\n */\nexport function getApiUrl(scope: ScopeValue, path = ''): string {\n\tconst scopeValue = scope === Scope.ADMIN ? 'global' : 'user'\n\treturn generateOcsUrl('apps/workflowengine/api/v1/workflows/{scopeValue}', { scopeValue }) + path + '?format=json'\n}\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type {\n\tCheck,\n\tCheckPlugin,\n\tEntity,\n\tFlatEntityEvent,\n\tOperatorPlugin,\n\tRule,\n\tScopeValue,\n\tServerCheck,\n} from './types.ts'\n\nimport axios from '@nextcloud/axios'\nimport { loadState } from '@nextcloud/initial-state'\nimport { confirmPassword } from '@nextcloud/password-confirmation'\nimport { defineStore } from 'pinia'\nimport { computed, ref } from 'vue'\nimport { getApiUrl } from './helpers/api.ts'\n\nconst DEFAULT_OPERATOR_COLOR = 'var(--color-primary-element)'\n\ninterface OcsResponse<T> {\n\tocs: { data: T }\n}\n\n/**\n * Flatten the events of every entity into one list, so a trigger can be picked\n * across entities.\n *\n * @param entities - The entities the server advertises\n */\nfunction flattenEvents(entities: Entity[]): FlatEntityEvent[] {\n\treturn entities.flatMap((entity) => entity.events.map((event) => ({\n\t\tid: `${entity.id}::${event.eventName}`,\n\t\tentity,\n\t\t...event,\n\t})))\n}\n\nexport const useWorkflowStore = defineStore('workflowengine', () => {\n\tconst scope = loadState<ScopeValue>('workflowengine', 'scope')\n\tconst appstoreEnabled = loadState<boolean>('workflowengine', 'appstoreenabled')\n\tconst entities = loadState<Entity[]>('workflowengine', 'entities')\n\tconst events = flattenEvents(entities)\n\tconst checks = loadState<Record<string, ServerCheck>>('workflowengine', 'checks')\n\n\tconst rules = ref<Rule[]>([])\n\t/** Operations the server knows, enriched by the plugins apps register. */\n\tconst operations = ref<Record<string, OperatorPlugin>>(loadState<Record<string, OperatorPlugin>>('workflowengine', 'operators'))\n\t/** Check plugins apps register, by check class. */\n\tconst pluginChecks = ref<Record<string, CheckPlugin>>({})\n\n\t/** The flows to display: those whose operation this instance still knows. */\n\tconst configuredRules = computed(() => rules.value\n\t\t.filter((rule) => operations.value[rule.class] !== undefined)\n\t\t.sort((first, second) => first.id - second.id))\n\n\t/**\n\t * The operation a flow runs.\n\t *\n\t * @param rule - The flow to look up\n\t */\n\tfunction operationForRule(rule: Rule): OperatorPlugin | undefined {\n\t\treturn operations.value[rule.class]\n\t}\n\n\t/**\n\t * The entity an operation is fixed to.\n\t *\n\t * @param operation - The operation to look up\n\t */\n\tfunction entityForOperation(operation: OperatorPlugin): Entity | undefined {\n\t\treturn entities.find((entity) => operation.fixedEntity === entity.id)\n\t}\n\n\t/**\n\t * The registered check plugins that apply to an entity, by check class.\n\t * A check without supported entities applies to all of them.\n\t *\n\t * @param entity - Class of the entity to filter by\n\t */\n\tfunction checksForEntity(entity: string): Record<string, CheckPlugin> {\n\t\treturn Object.values(checks)\n\t\t\t.filter((check) => check.supportedEntities.length === 0 || check.supportedEntities.includes(entity))\n\t\t\t.map((check) => pluginChecks.value[check.id])\n\t\t\t.reduce<Record<string, CheckPlugin>>((available, plugin) => {\n\t\t\t\tavailable[plugin.class] = plugin\n\t\t\t\treturn available\n\t\t\t}, {})\n\t}\n\n\t/**\n\t * Register the value editor of a check.\n\t *\n\t * @param plugin - The plugin to register\n\t */\n\tfunction addPluginCheck(plugin: CheckPlugin): void {\n\t\tpluginChecks.value = { ...pluginChecks.value, [plugin.class]: plugin }\n\t}\n\n\t/**\n\t * Enrich a server operation with the plugin an app registered for it.\n\t * Plugins for operations this instance does not have are ignored.\n\t *\n\t * @param plugin - The plugin to register\n\t */\n\tfunction addPluginOperator(plugin: OperatorPlugin): void {\n\t\tconst operation = operations.value[plugin.id]\n\t\tif (operation === undefined) {\n\t\t\treturn\n\t\t}\n\t\t// the server data wins over the plugin, the default only fills a gap\n\t\tconst merged = { ...plugin, ...operation }\n\t\toperations.value = {\n\t\t\t...operations.value,\n\t\t\t[plugin.id]: { ...merged, color: merged.color ?? DEFAULT_OPERATOR_COLOR },\n\t\t}\n\t}\n\n\t/**\n\t * Replace a flow in place, keeping the order of the list.\n\t *\n\t * @param rule - The flow to store\n\t */\n\tfunction updateRule(rule: Rule): void {\n\t\tconst index = rules.value.findIndex((item) => item.id === rule.id)\n\t\tif (index === -1) {\n\t\t\treturn\n\t\t}\n\t\tconst stored = {\n\t\t\t...rule,\n\t\t\tevents: typeof rule.events === 'string' ? JSON.parse(rule.events) : rule.events,\n\t\t}\n\t\trules.value.splice(index, 1, stored)\n\t}\n\n\t/**\n\t * Apply a change to a check. Checks are edited in place, so this is the one\n\t * place that writes to them; persisting the flow stays with the caller.\n\t *\n\t * @param check - The check to change\n\t * @param patch - The fields to change\n\t */\n\tfunction updateCheck(check: Check, patch: Partial<Check>): void {\n\t\tObject.assign(check, patch)\n\t}\n\n\t/**\n\t * Append an empty check to a flow.\n\t *\n\t * @param rule - The flow to extend\n\t */\n\tfunction addCheck(rule: Rule): void {\n\t\trule.checks.push({ class: null, operator: null, value: '' })\n\t}\n\n\t/**\n\t * Drop a check from a flow.\n\t *\n\t * @param rule - The flow to shorten\n\t * @param check - The check to drop\n\t */\n\tfunction removeCheck(rule: Rule, check: Check): void {\n\t\tconst index = rule.checks.indexOf(check)\n\t\tif (index > -1) {\n\t\t\trule.checks.splice(index, 1)\n\t\t}\n\t}\n\n\t/**\n\t * Point a flow at the entity it watches and the events that trigger it.\n\t *\n\t * @param rule - The flow to retrigger\n\t * @param entity - Class of the entity to watch\n\t * @param events - Names of the events to react to\n\t */\n\tfunction setRuleTrigger(rule: Rule, entity: string, events: string[]): void {\n\t\trule.entity = entity\n\t\trule.events = events\n\t}\n\n\t/**\n\t * Store the value the operation's own editor produced.\n\t *\n\t * @param rule - The flow to change\n\t * @param operation - The new operation value\n\t */\n\tfunction setRuleOperation(rule: Rule, operation: string): void {\n\t\trule.operation = operation\n\t}\n\n\t/**\n\t * Drop a flow from the list without deleting it on the server.\n\t *\n\t * @param rule - The flow to drop\n\t */\n\tfunction removeRule(rule: Rule): void {\n\t\tconst index = rules.value.findIndex((item) => item.id === rule.id)\n\t\tif (index === -1) {\n\t\t\treturn\n\t\t}\n\t\trules.value.splice(index, 1)\n\t}\n\n\t/** Load the configured flows of this scope. */\n\tasync function fetchRules(): Promise<void> {\n\t\tconst { data } = await axios.get<OcsResponse<Record<string, Rule[]>>>(getApiUrl(scope))\n\t\trules.value.push(...Object.values(data.ocs.data).flat().map((rule) => ({ ...rule, valid: true })))\n\t}\n\n\t/**\n\t * Start a new, unsaved flow for an operation. Unsaved flows are told apart\n\t * by their negative id.\n\t *\n\t * @param operation - The operation the flow should run\n\t */\n\tasync function createNewRule(operation: OperatorPlugin): Promise<void> {\n\t\tawait confirmPassword()\n\n\t\tlet entity: Entity | undefined\n\t\tlet firstEvent: string[] = []\n\t\tif (operation.isComplex === false && operation.fixedEntity === '') {\n\t\t\tentity = entities.find((item) => operation.entities && operation.entities[0] === item.id) ?? entities[0]\n\t\t\tfirstEvent = [entity.events[0].eventName]\n\t\t}\n\n\t\trules.value.push({\n\t\t\tid: -Date.now(),\n\t\t\tclass: operation.id,\n\t\t\tentity: entity ? entity.id : operation.fixedEntity,\n\t\t\tevents: firstEvent,\n\t\t\tname: '', // unused in the new ui, there for legacy reasons\n\t\t\tchecks: [{ class: null, operator: null, value: '' }],\n\t\t\toperation: operation.operation || '',\n\t\t\tvalid: true,\n\t\t})\n\t}\n\n\t/**\n\t * Persist a flow, creating it when it has not been saved before.\n\t *\n\t * @param rule - The flow to persist\n\t */\n\tasync function pushUpdateRule(rule: Rule): Promise<void> {\n\t\tawait confirmPassword()\n\t\tconst { data } = rule.id < 0\n\t\t\t? await axios.post<OcsResponse<Rule>>(getApiUrl(scope), rule)\n\t\t\t: await axios.put<OcsResponse<Rule>>(getApiUrl(scope, `/${rule.id}`), rule)\n\t\trule.id = data.ocs.data.id\n\t\tupdateRule(rule)\n\t}\n\n\t/**\n\t * Delete a flow on the server and drop it from the list.\n\t *\n\t * @param rule - The flow to delete\n\t */\n\tasync function deleteRule(rule: Rule): Promise<void> {\n\t\tawait confirmPassword()\n\t\tawait axios.delete(getApiUrl(scope, `/${rule.id}`))\n\t\tremoveRule(rule)\n\t}\n\n\t/**\n\t * Record whether a flow satisfies its checks.\n\t *\n\t * @param rule - The flow to mark\n\t * @param valid - Whether it is valid\n\t */\n\tfunction setValid(rule: Rule, valid: boolean): void {\n\t\trule.valid = valid\n\t\tupdateRule(rule)\n\t}\n\n\treturn {\n\t\tscope,\n\t\tappstoreEnabled,\n\t\tentities,\n\t\tevents,\n\t\tchecks,\n\t\trules,\n\t\toperations,\n\t\tpluginChecks,\n\n\t\tconfiguredRules,\n\t\toperationForRule,\n\t\tentityForOperation,\n\t\tchecksForEntity,\n\n\t\taddPluginCheck,\n\t\taddPluginOperator,\n\t\tfetchRules,\n\t\tcreateNewRule,\n\t\tupdateRule,\n\t\tremoveRule,\n\t\tupdateCheck,\n\t\taddCheck,\n\t\tremoveCheck,\n\t\tsetRuleTrigger,\n\t\tsetRuleOperation,\n\t\tpushUpdateRule,\n\t\tdeleteRule,\n\t\tsetValid,\n\t}\n})\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div ref=\"checkElement\" :class=\"$style.check\" @click=\"showDelete\">\n\t\t<NcSelect\n\t\t\tref=\"checkSelector\"\n\t\t\t:aria-label-combobox=\"t('workflowengine', 'Filter')\"\n\t\t\t:class=\"$style.filter\"\n\t\t\t:clearable=\"false\"\n\t\t\t:modelValue=\"currentOption\"\n\t\t\t:options=\"options\"\n\t\t\t:placeholder=\"t('workflowengine', 'Select a filter')\"\n\t\t\tlabel=\"name\"\n\t\t\t@update:modelValue=\"onFilterChange\" />\n\t\t<NcSelect\n\t\t\t:aria-label-combobox=\"t('workflowengine', 'Comparator')\"\n\t\t\t:class=\"$style.comparator\"\n\t\t\t:clearable=\"false\"\n\t\t\t:disabled=\"!currentOption\"\n\t\t\t:modelValue=\"currentOperator\"\n\t\t\t:options=\"operators\"\n\t\t\t:placeholder=\"t('workflowengine', 'Select a comparator')\"\n\t\t\tlabel=\"name\"\n\t\t\t@update:modelValue=\"onComparatorChange\" />\n\t\t<!-- A custom element takes hyphenated attributes. `disabled` has to fall\n\t\t\taway entirely when it does not apply: on a dashed tag Vue writes the\n\t\t\tliteral string \"false\", which the element would read as truthy. -->\n\t\t<!-- eslint-disable vue/attribute-hyphenation -->\n\t\t<component\n\t\t\t:is=\"currentElement\"\n\t\t\tv-if=\"currentElement\"\n\t\t\tref=\"valueElement\"\n\t\t\t:class=\"$style.option\"\n\t\t\t:disabled=\"!currentOption || undefined\"\n\t\t\t:model-value=\"check.value\"\n\t\t\t:operator=\"check.operator\" />\n\t\t<!-- eslint-enable vue/attribute-hyphenation -->\n\t\t<input\n\t\t\tv-else\n\t\t\t:class=\"[$style.option, { [$style.invalid]: !valid }]\"\n\t\t\t:disabled=\"!currentOption\"\n\t\t\t:placeholder=\"valuePlaceholder\"\n\t\t\t:value=\"check.value\"\n\t\t\ttype=\"text\"\n\t\t\t@input=\"onValueInput\">\n\t\t<NcActions v-if=\"deleteVisible || !currentOption\">\n\t\t\t<NcActionButton :title=\"t('workflowengine', 'Remove filter')\" @click=\"emit('remove')\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :path=\"mdiClose\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcActionButton>\n\t\t</NcActions>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\n/* eslint vue/multi-word-component-names: \"warn\" */\n\nimport type { CheckPlugin, Check as CheckType, Comparison, Rule } from '../types.ts'\n\nimport { mdiClose } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { onClickOutside } from '@vueuse/core'\nimport { computed, onMounted, ref, useTemplateRef, watch } from 'vue'\nimport NcActionButton from '@nextcloud/vue/components/NcActionButton'\nimport NcActions from '@nextcloud/vue/components/NcActions'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport NcSelect from '@nextcloud/vue/components/NcSelect'\nimport { useCustomElementEvents } from '../composables/useCustomElementEvents.ts'\nimport { logger } from '../logger.ts'\nimport { useWorkflowStore } from '../store.ts'\n\nconst props = defineProps<{\n\tcheck: CheckType\n\trule: Rule\n}>()\n\nconst emit = defineEmits<{\n\tupdate: [check: CheckType]\n\tvalidate: [valid: boolean]\n\tremove: []\n}>()\n\nconst store = useWorkflowStore()\n\nconst checkElement = useTemplateRef<HTMLDivElement>('checkElement')\nconst valueElement = useTemplateRef<Element>('valueElement')\nconst checkSelector = useTemplateRef<{ focus?: () => void }>('checkSelector')\n\nconst deleteVisible = ref(false)\nconst valid = ref(false)\n/** Undefined until a custom element reports on its own value. */\nconst elementValid = ref<boolean | undefined>(undefined)\n\nconst checks = computed(() => store.checksForEntity(props.rule.entity))\nconst options = computed(() => Object.values(checks.value))\n\n/**\n * Both selections are derived from the check itself, so a row always shows what\n * it actually holds — including after a neighbouring row was removed and this\n * component was reused for a different check.\n */\nconst currentOption = computed<CheckPlugin | null>(() => (props.check.class === null ? null : checks.value[props.check.class] ?? null))\n\nconst operators = computed<Comparison[]>(() => {\n\tif (!currentOption.value) {\n\t\treturn []\n\t}\n\tconst { operators } = currentOption.value\n\treturn typeof operators === 'function' ? operators(props.check) : operators\n})\n\nconst currentOperator = computed<Comparison | null>(() => operators.value.find((operator) => operator.operator === props.check.operator) ?? null)\n\nconst currentElement = computed(() => {\n\tif (props.check.class === null) {\n\t\treturn undefined\n\t}\n\treturn checks.value[props.check.class]?.element\n})\n\nconst valuePlaceholder = computed(() => currentOption.value?.placeholder?.(props.check) ?? '')\n\nfunction showDelete(): void {\n\tdeleteVisible.value = true\n}\n\nonClickOutside(checkElement, () => {\n\tdeleteVisible.value = false\n})\n\n/**\n * A check is valid unless the plugin says otherwise. Only when the plugin\n * brings no validator does the verdict of its custom element count, so a\n * plugin validator always wins.\n */\nfunction validate(): void {\n\tif (currentOption.value?.validate) {\n\t\tvalid.value = Boolean(currentOption.value.validate(props.check))\n\t} else {\n\t\tvalid.value = elementValid.value ?? true\n\t}\n\tstore.updateCheck(props.check, { invalid: !valid.value })\n\temit('validate', valid.value)\n}\n\n/**\n * @param patch - The fields of the check to change\n */\nfunction update(patch: Partial<CheckType>): void {\n\tstore.updateCheck(props.check, patch)\n\tvalidate()\n\temit('update', props.check)\n}\n\n/**\n * @param option - The filter that was picked\n */\nfunction onFilterChange(option: CheckPlugin | null): void {\n\tif (option === null) {\n\t\treturn\n\t}\n\tif (!option.element && !option.validate && (option as { component?: unknown }).component) {\n\t\tlogger.error(`Check plugin \"${option.class}\" only provides the removed \"component\" option. `\n\t\t\t+ 'Provide a custom element through \"element\" instead.')\n\t}\n\n\tconst available = typeof option.operators === 'function' ? option.operators(props.check) : option.operators\n\t// the comparison of the previous filter may not exist for the new one\n\tconst operator = available.some((item) => item.operator === props.check.operator)\n\t\t? props.check.operator\n\t\t: available[0]?.operator ?? null\n\n\tif (option.class !== props.check.class) {\n\t\telementValid.value = undefined\n\t}\n\tupdate({ class: option.class, operator })\n}\n\n/**\n * @param comparison - The comparison that was picked\n */\nfunction onComparatorChange(comparison: Comparison | null): void {\n\tif (comparison !== null) {\n\t\tupdate({ operator: comparison.operator })\n\t}\n}\n\n/**\n * @param event - The change a custom element reported\n */\nfunction onElementValue(event: CustomEvent<unknown[]>): void {\n\tupdate({ value: event.detail[0] as string })\n}\n\n/**\n * @param reported - What the custom element reported about its own value\n */\nfunction onElementValidity(reported: boolean): void {\n\telementValid.value = reported\n\tvalidate()\n}\n\n/**\n * @param event - The input event of the plain value field\n */\nfunction onValueInput(event: Event): void {\n\tupdate({ value: (event.target as HTMLInputElement).value })\n}\n\nuseCustomElementEvents(valueElement, {\n\t'update:model-value': onElementValue,\n\tvalid: () => onElementValidity(true),\n\tinvalid: () => onElementValidity(false),\n})\n\nwatch(() => props.check.operator, validate)\n\nonMounted(() => {\n\tif (props.check.class === null) {\n\t\tcheckSelector.value?.focus?.()\n\t}\n\tvalidate()\n})\n</script>\n\n<style module lang=\"scss\">\n.check {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\talign-items: flex-start; // to not stretch components vertically\n\twidth: 100%;\n\tpadding-inline-end: 20px;\n\n\t& > * {\n\t\tmargin-inline-end: 5px;\n\t\tmargin-bottom: 5px;\n\t}\n}\n\n.filter {\n\twidth: 180px;\n}\n\n.comparator {\n\tmin-width: 200px;\n\twidth: 200px;\n}\n\n.option {\n\tmin-width: 260px;\n\twidth: 260px;\n\tmin-height: 48px;\n\n\tinput[type='text'] {\n\t\tmin-height: 48px;\n\t}\n}\n\ninput.option {\n\tmargin-top: 0;\n}\n\n.invalid {\n\tborder-color: var(--color-border-error) !important;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div :class=\"$style.event\">\n\t\t<div v-if=\"operation.isComplex && operation.fixedEntity !== ''\">\n\t\t\t<img :class=\"$style.optionIcon\" :src=\"entity?.icon\" alt=\"\">\n\t\t\t<span :class=\"[$style.optionTitle, $style.singleTitle]\">{{ operation.triggerHint }}</span>\n\t\t</div>\n\t\t<NcSelect\n\t\t\tv-else\n\t\t\t:aria-label-combobox=\"t('workflowengine', 'Trigger')\"\n\t\t\t:class=\"$style.trigger\"\n\t\t\t:disabled=\"allEvents.length <= 1\"\n\t\t\t:modelValue=\"currentEvent\"\n\t\t\t:multiple=\"true\"\n\t\t\t:options=\"allEvents\"\n\t\t\t:placeholder=\"placeholderString\"\n\t\t\tlabel=\"displayName\"\n\t\t\t@update:modelValue=\"updateEvent\">\n\t\t\t<template #option=\"option\">\n\t\t\t\t<img :class=\"$style.optionIcon\" :src=\"option.entity.icon\" alt=\"\">\n\t\t\t\t<span :class=\"$style.optionTitle\">{{ option.displayName }}</span>\n\t\t\t</template>\n\t\t\t<template #selected-option=\"option\">\n\t\t\t\t<img :class=\"$style.optionIcon\" :src=\"option.entity.icon\" alt=\"\">\n\t\t\t\t<span :class=\"$style.optionTitle\">{{ option.displayName }}</span>\n\t\t\t</template>\n\t\t</NcSelect>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\n/* eslint vue/multi-word-component-names: \"warn\" */\n\nimport type { FlatEntityEvent, Rule } from '../types.ts'\n\nimport { showWarning } from '@nextcloud/dialogs'\nimport { t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport NcSelect from '@nextcloud/vue/components/NcSelect'\nimport { useWorkflowStore } from '../store.ts'\n\nconst props = defineProps<{ rule: Rule }>()\n\nconst emit = defineEmits<{ update: [rule: Rule] }>()\n\nconst store = useWorkflowStore()\n\nconst operation = computed(() => store.operationForRule(props.rule)!)\nconst entity = computed(() => store.entityForOperation(operation.value))\nconst allEvents = computed(() => store.events)\n\nconst currentEvent = computed(() => allEvents.value.filter((event) => event.entity.id === props.rule.entity && props.rule.events.includes(event.eventName)))\n\n// TRANSLATORS: Users should select a trigger for a workflow action\nconst placeholderString = t('workflowengine', 'Select a trigger')\n\n/**\n * Apply the picked triggers. Picking events of another entity switches the rule\n * over to that entity, because a rule only ever watches one.\n *\n * @param events - The triggers that are now picked\n */\nfunction updateEvent(events: FlatEntityEvent[]): void {\n\tif (events.length === 0) {\n\t\t// TRANSLATORS: Users must select an event as of \"happening\" or \"incident\" which triggers an action\n\t\tshowWarning(t('workflowengine', 'At least one event must be selected'))\n\t\treturn\n\t}\n\n\tconst existingEntity = props.rule.entity\n\tconst newEntities = [...new Set(events.map((event) => event.entity.id))]\n\tconst newEntity = newEntities.length > 1\n\t\t? newEntities.filter((entityId) => entityId !== existingEntity)[0]\n\t\t: newEntities[0]\n\n\tstore.setRuleTrigger(\n\t\tprops.rule,\n\t\tnewEntity,\n\t\tevents.filter((event) => event.entity.id === newEntity).map((event) => event.eventName),\n\t)\n\temit('update', props.rule)\n}\n</script>\n\n<style module lang=\"scss\">\n.event {\n\tmargin-bottom: 5px;\n\n\timg {\n\t\tvertical-align: text-top;\n\t}\n}\n\n.trigger {\n\tmax-width: 550px;\n}\n\n.optionTitle {\n\tmargin-inline-start: 5px;\n\tcolor: var(--color-main-text);\n}\n\n.singleTitle {\n\tpadding-top: 2px;\n\tdisplay: inline-block;\n}\n\n.optionIcon {\n\twidth: 16px;\n\theight: 16px;\n\tfilter: var(--background-invert-if-dark);\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div v-if=\"operation\" :class=\"$style.rule\" :style=\"{ borderInlineStartColor: operation.color || '' }\">\n\t\t<div :class=\"$style.trigger\">\n\t\t\t<p>\n\t\t\t\t<span>{{ t('workflowengine', 'When') }}</span>\n\t\t\t\t<Event :rule=\"rule\" @update=\"updateRule\" />\n\t\t\t</p>\n\t\t\t<p v-for=\"check in rule.checks\" :key=\"checkKey(check)\">\n\t\t\t\t<span>{{ t('workflowengine', 'and') }}</span>\n\t\t\t\t<Check\n\t\t\t\t\t:check=\"check\"\n\t\t\t\t\t:rule=\"rule\"\n\t\t\t\t\t@update=\"updateRule\"\n\t\t\t\t\t@validate=\"validate\"\n\t\t\t\t\t@remove=\"removeCheck(check)\" />\n\t\t\t</p>\n\t\t\t<p>\n\t\t\t\t<span />\n\t\t\t\t<input\n\t\t\t\t\tv-if=\"lastCheckComplete\"\n\t\t\t\t\t:class=\"$style.addCheck\"\n\t\t\t\t\t:value=\"t('workflowengine', 'Add a new filter')\"\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t@click=\"onAddFilter\">\n\t\t\t</p>\n\t\t</div>\n\t\t<div class=\"icon-confirm\" :class=\"[$style.flowIcon]\" />\n\t\t<div :class=\"$style.action\">\n\t\t\t<Operation :operation=\"operation\">\n\t\t\t\t<!-- eslint-disable vue/attribute-hyphenation -- a custom element takes hyphenated attributes -->\n\t\t\t\t<component\n\t\t\t\t\t:is=\"operation.element\"\n\t\t\t\t\tv-if=\"operation.element\"\n\t\t\t\t\tref=\"operationElement\"\n\t\t\t\t\t:model-value=\"inputValue\" />\n\t\t\t\t<!-- eslint-enable vue/attribute-hyphenation -->\n\t\t\t</Operation>\n\t\t\t<div :class=\"$style.buttons\">\n\t\t\t\t<NcButton v-if=\"rule.id < -1 || dirty\" @click=\"cancelRule\">\n\t\t\t\t\t{{ t('workflowengine', 'Cancel') }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton v-else-if=\"!dirty\" @click=\"deleteRule\">\n\t\t\t\t\t{{ t('workflowengine', 'Delete') }}\n\t\t\t\t</NcButton>\n\t\t\t\t<NcButton\n\t\t\t\t\t:title=\"ruleStatus.tooltip\"\n\t\t\t\t\t:variant=\"ruleStatus.variant\"\n\t\t\t\t\t@click=\"saveRule\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"ruleStatus.icon\" :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ ruleStatus.title }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t\t<p v-if=\"error\" :class=\"$style.errorMessage\">\n\t\t\t\t{{ error }}\n\t\t\t</p>\n\t\t</div>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\n/* eslint vue/multi-word-component-names: \"warn\" */\n\nimport type { Check as CheckType, Rule } from '../types.ts'\n\nimport { mdiArrowRight, mdiCheck, mdiClose } from '@mdi/js'\nimport { t } from '@nextcloud/l10n'\nimport { computed, onMounted, ref, useTemplateRef } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport Check from './Check.vue'\nimport Event from './Event.vue'\nimport Operation from './Operation.vue'\nimport { useCustomElementEvents } from '../composables/useCustomElementEvents.ts'\nimport { logger } from '../logger.ts'\nimport { useWorkflowStore } from '../store.ts'\n\nconst props = defineProps<{ rule: Rule }>()\n\nconst store = useWorkflowStore()\n\nconst error = ref<string | null>(null)\nconst dirty = ref(props.rule.id < 0)\nconst originalRule = ref<Rule | null>(null)\nconst inputValue = ref('')\nconst operationElement = useTemplateRef<Element>('operationElement')\n\nconst operation = computed(() => store.operationForRule(props.rule))\n\nconst ruleStatus = computed(() => {\n\tif (error.value || !props.rule.valid || props.rule.checks.length === 0\n\t\t|| props.rule.checks.some((check) => check.invalid === true)) {\n\t\treturn {\n\t\t\ttitle: t('workflowengine', 'The configuration is invalid'),\n\t\t\ticon: mdiClose,\n\t\t\tvariant: 'warning' as const,\n\t\t\ttooltip: error.value ?? undefined,\n\t\t}\n\t}\n\tif (!dirty.value) {\n\t\treturn { title: t('workflowengine', 'Active'), icon: mdiCheck, variant: 'success' as const, tooltip: undefined }\n\t}\n\treturn { title: t('workflowengine', 'Save'), icon: mdiArrowRight, variant: 'primary' as const, tooltip: undefined }\n})\n\nconst lastCheckComplete = computed(() => {\n\tconst lastCheck = props.rule.checks.at(-1)\n\treturn lastCheck === undefined || lastCheck.class !== null\n})\n\n// Filter rows are keyed by the check they render, so removing one cannot make\n// another row reuse a component that still points at the removed check.\nconst checkKeys = new WeakMap<CheckType, number>()\nlet lastCheckKey = 0\n\n/**\n * @param check - The check of the row\n */\nfunction checkKey(check: CheckType): number {\n\tlet key = checkKeys.get(check)\n\tif (key === undefined) {\n\t\tlastCheckKey += 1\n\t\tkey = lastCheckKey\n\t\tcheckKeys.set(check, key)\n\t}\n\treturn key\n}\n\nfunction validate(): void {\n\terror.value = null\n\tstore.updateRule(props.rule)\n}\n\nfunction updateRule(): void {\n\tdirty.value = true\n\terror.value = null\n\tstore.updateRule(props.rule)\n}\n\n/**\n * @param event - The change the operation's custom element reported\n */\nfunction updateOperationByEvent(event: CustomEvent<unknown[]>): void {\n\tinputValue.value = event.detail[0] as string\n\tstore.setRuleOperation(props.rule, inputValue.value)\n\tupdateRule()\n}\n\nasync function saveRule(): Promise<void> {\n\ttry {\n\t\tawait store.pushUpdateRule(props.rule)\n\t\tdirty.value = false\n\t\terror.value = null\n\t\toriginalRule.value = structuredClone(toPlainRule(props.rule))\n\t} catch (exception) {\n\t\tlogger.error('Failed to save operation', { error: exception })\n\t\terror.value = ocsMessage(exception)\n\t}\n}\n\nasync function deleteRule(): Promise<void> {\n\ttry {\n\t\tawait store.deleteRule(props.rule)\n\t} catch (exception) {\n\t\tlogger.error('Failed to delete operation', { error: exception })\n\t\terror.value = ocsMessage(exception)\n\t}\n}\n\nfunction cancelRule(): void {\n\tif (props.rule.id < 0) {\n\t\tstore.removeRule(props.rule)\n\t\treturn\n\t}\n\tinputValue.value = originalRule.value!.operation\n\tstore.updateRule(originalRule.value!)\n\toriginalRule.value = structuredClone(toPlainRule(props.rule))\n\tdirty.value = false\n}\n\n/**\n * @param check - The filter to drop\n */\nfunction removeCheck(check: CheckType): void {\n\tstore.removeCheck(props.rule, check)\n\tupdateRule()\n}\n\nfunction onAddFilter(): void {\n\tstore.addCheck(props.rule)\n}\n\n/**\n * The store holds reactive proxies, which cannot be structurally cloned.\n *\n * @param rule - The rule to copy\n */\nfunction toPlainRule(rule: Rule): Rule {\n\treturn JSON.parse(JSON.stringify(rule))\n}\n\n/**\n * @param exception - The rejected request\n */\nfunction ocsMessage(exception: unknown): string | null {\n\tconst response = (exception as { response?: { data?: { ocs?: { meta?: { message?: string } } } } }).response\n\treturn response?.data?.ocs?.meta?.message ?? null\n}\n\nuseCustomElementEvents(operationElement, {\n\t'update:model-value': updateOperationByEvent,\n})\n\nonMounted(() => {\n\toriginalRule.value = structuredClone(toPlainRule(props.rule))\n\tif (operation.value?.element) {\n\t\tinputValue.value = props.rule.operation\n\t}\n})\n</script>\n\n<style module lang=\"scss\">\n.buttons {\n\tdisplay: flex;\n\tjustify-content: end;\n\n\tbutton {\n\t\tmargin-inline-start: 5px;\n\t}\n\n\tbutton:last-child {\n\t\tmargin-inline-end: 10px;\n\t}\n}\n\n.errorMessage {\n\tfloat: inline-end;\n\tmargin-inline-end: 10px;\n}\n\n.flowIcon {\n\twidth: 44px;\n\tbackground-position: right 27px;\n\tpadding-inline-end: 20px;\n\tmargin-inline-end: 20px;\n}\n\n.rule {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tborder-inline-start: 5px solid var(--color-primary-element);\n\tmargin-bottom: 20px;\n\tpadding: 10px;\n}\n\n.trigger,\n.action {\n\tflex-grow: 1;\n\tmin-height: 100px;\n\tmax-width: 920px;\n}\n\n.action {\n\tmax-width: 400px;\n\tposition: relative;\n}\n\n.trigger p,\n.action p {\n\tmin-height: 34px;\n\tdisplay: flex;\n\n\t& > span:first-child {\n\t\tmin-width: 50px;\n\t\ttext-align: end;\n\t\tcolor: var(--color-text-maxcontrast);\n\t\tpadding-inline-end: 10px;\n\t\tpadding-top: 6px;\n\t}\n}\n\n.trigger p:first-child span {\n\tpadding-top: 3px;\n}\n\n.trigger p:last-child {\n\tpadding-top: 8px;\n}\n\n.addCheck {\n\tbackground-position: 7px center;\n\tbackground-color: transparent;\n\tpadding-inline-start: 6px;\n\tmargin: 0;\n\twidth: 180px;\n\tborder-radius: var(--border-radius);\n\tcolor: var(--color-text-maxcontrast);\n\tfont-weight: normal;\n\ttext-align: start;\n\tfont-size: 1em;\n}\n\n@media (max-width: 1400px) {\n\t.rule {\n\t\twidth: 100%;\n\t\tmax-width: 100%;\n\t}\n\n\t.trigger,\n\t.action {\n\t\twidth: 100%;\n\t\tmax-width: 100%;\n\t}\n\n\t.flowIcon {\n\t\tdisplay: none;\n\t}\n}\n</style>\n","export default \"<svg width=\\\"16\\\" height=\\\"16\\\" version=\\\"1.1\\\" viewBox=\\\"0 0 16 16\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\">\\n <path d=\\\"M 3.0839844 3 C 2.0812854 3 1.25 3.8312754 1.25 4.8339844 L 1.25 7 L 1.0136719 7 C -0.33862677 6.980875 -0.33862677 9.0191 1.0136719 9 L 1.25 9 L 1.25 11.166016 C 1.25 12.168715 2.0812754 13 3.0839844 13 L 7.4160156 13 C 8.4187146 13 9.25 12.168725 9.25 11.166016 L 9.25 9 L 10.060547 9 L 7.75 6.6894531 L 7.75 11.166016 C 7.75 11.363655 7.6136554 11.5 7.4160156 11.5 L 3.0839844 11.5 C 2.8863446 11.5 2.75 11.363655 2.75 11.166016 L 2.75 4.8339844 C 2.75 4.6363446 2.8863446 4.5 3.0839844 4.5 L 5.5605469 4.5 L 4.0605469 3 L 3.0839844 3 z M 6.1816406 3 L 9.25 6.0683594 L 9.25 4.8339844 C 9.25 3.8312854 8.4187246 3 7.4160156 3 L 6.1816406 3 z M 11.5 3.5 C 10.602601 3.5 10.159605 4.5908975 10.802734 5.2167969 L 12.585938 7 L 10.181641 7 L 12.181641 9 L 12.585938 9 L 12.382812 9.203125 L 13.796875 10.617188 L 15.707031 8.7070312 C 16.094031 8.3192316 16.098031 7.6841684 15.707031 7.2929688 L 12.216797 3.8027344 C 12.028497 3.6092346 11.77 3.50002 11.5 3.5 z M 11.324219 10.261719 L 10.802734 10.783203 C 9.8211054 11.725712 11.274208 13.178865 12.216797 12.197266 L 12.738281 11.675781 L 11.324219 10.261719 z \\\" />\\n <path d=\\\"M 0,1.0606601 1.06066,0 16.00033,14.93967 14.93967,16.00033 Z\\\" />\\n</svg>\\n\"","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div :class=\"$style.workflowengine\">\n\t\t<NcSettingsSection\n\t\t\t:docUrl=\"workflowDocUrl\"\n\t\t\t:name=\"t('workflowengine', 'Available flows')\">\n\t\t\t<p v-if=\"isAdminScope\" class=\"settings-hint\">\n\t\t\t\t<a href=\"https://nextcloud.com/developer/\">{{ t('workflowengine', 'For details on how to write your own flow, check out the development documentation.') }}</a>\n\t\t\t</p>\n\n\t\t\t<NcEmptyContent\n\t\t\t\tv-if=\"!isUserAdmin && mainOperations.length === 0\"\n\t\t\t\t:description=\"t('workflowengine', 'Ask your administrator to install new flows.')\"\n\t\t\t\t:name=\"t('workflowengine', 'No flows installed')\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :svg=\"WorkflowOffSvg\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\t\t\t<TransitionGroup\n\t\t\t\tv-else\n\t\t\t\tv-bind=\"slideTransition\"\n\t\t\t\t:class=\"$style.actions\"\n\t\t\t\ttag=\"div\">\n\t\t\t\t<Operation\n\t\t\t\t\tv-for=\"operation in mainOperations\"\n\t\t\t\t\t:key=\"operation.id\"\n\t\t\t\t\t:class=\"$style.card\"\n\t\t\t\t\t:operation=\"operation\"\n\t\t\t\t\tcolored\n\t\t\t\t\t@click=\"createNewRule(operation)\" />\n\t\t\t\t<a\n\t\t\t\t\tv-if=\"showAppStoreHint\"\n\t\t\t\t\tkey=\"add\"\n\t\t\t\t\t:class=\"[$style.card, $style.more]\"\n\t\t\t\t\t:href=\"appstoreUrl\">\n\t\t\t\t\t<NcIconSvgWrapper :class=\"$style.moreIcon\" :path=\"mdiPlus\" :size=\"50\" />\n\t\t\t\t\t<div>\n\t\t\t\t\t\t<h3>{{ t('workflowengine', 'More flows') }}</h3>\n\t\t\t\t\t\t<small>{{ t('workflowengine', 'Browse the App Store') }}</small>\n\t\t\t\t\t</div>\n\t\t\t\t</a>\n\t\t\t</TransitionGroup>\n\n\t\t\t<div v-if=\"hasMoreOperations\" :class=\"$style.showMore\">\n\t\t\t\t<NcButton @click=\"showMoreOperations = !showMoreOperations\">\n\t\t\t\t\t<template #icon>\n\t\t\t\t\t\t<NcIconSvgWrapper :path=\"showMoreOperations ? mdiMenuUp : mdiMenuDown\" :size=\"20\" />\n\t\t\t\t\t</template>\n\t\t\t\t\t{{ showMoreOperations ? t('workflowengine', 'Show less') : t('workflowengine', 'Show more') }}\n\t\t\t\t</NcButton>\n\t\t\t</div>\n\t\t</NcSettingsSection>\n\n\t\t<NcSettingsSection\n\t\t\tv-if=\"mainOperations.length > 0\"\n\t\t\t:name=\"isAdminScope ? t('workflowengine', 'Configured flows') : t('workflowengine', 'Your flows')\">\n\t\t\t<TransitionGroup v-if=\"rules.length > 0\" v-bind=\"slideTransition\">\n\t\t\t\t<Rule v-for=\"rule in rules\" :key=\"rule.id\" :rule=\"rule\" />\n\t\t\t</TransitionGroup>\n\t\t\t<NcEmptyContent v-else :name=\"t('workflowengine', 'No flows configured')\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<NcIconSvgWrapper :svg=\"WorkflowOffSvg\" :size=\"20\" />\n\t\t\t\t</template>\n\t\t\t</NcEmptyContent>\n\t\t</NcSettingsSection>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\n/* eslint vue/multi-word-component-names: \"warn\" */\n\nimport type { OperatorPlugin } from '../types.ts'\n\nimport { mdiMenuDown, mdiMenuUp, mdiPlus } from '@mdi/js'\nimport { getCurrentUser } from '@nextcloud/auth'\nimport { loadState } from '@nextcloud/initial-state'\nimport { t } from '@nextcloud/l10n'\nimport { generateUrl } from '@nextcloud/router'\nimport { computed, onMounted, ref, useCssModule } from 'vue'\nimport NcButton from '@nextcloud/vue/components/NcButton'\nimport NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'\nimport NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'\nimport NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'\nimport Operation from './Operation.vue'\nimport Rule from './Rule.vue'\nimport WorkflowOffSvg from '../../img/workflow-off.svg?raw'\nimport { useWorkflowStore } from '../store.ts'\nimport { Scope } from '../types.ts'\n\nconst ACTION_LIMIT = 3\n\nconst store = useWorkflowStore()\nconst style = useCssModule()\n\nconst showMoreOperations = ref(false)\nconst appstoreUrl = generateUrl('settings/apps/workflow')\nconst workflowDocUrl = loadState<string>('workflowengine', 'doc-url')\n\nconst isUserAdmin = Boolean(getCurrentUser()?.isAdmin)\n\nconst rules = computed(() => store.configuredRules)\nconst operations = computed(() => store.operations)\n\nconst hasMoreOperations = computed(() => Object.keys(operations.value).length > ACTION_LIMIT)\n\nconst mainOperations = computed(() => {\n\tconst all = Object.values(operations.value)\n\treturn showMoreOperations.value ? all : all.slice(0, ACTION_LIMIT)\n})\n\nconst isAdminScope = computed(() => store.scope === Scope.ADMIN)\nconst showAppStoreHint = computed(() => store.appstoreEnabled && isUserAdmin)\n\n// transition classes have to be passed explicitly, css modules rename them\nconst slideTransition = {\n\tenterActiveClass: style.slideEnterActive,\n\tleaveActiveClass: style.slideLeaveActive,\n\tenterFromClass: style.slideEnterFrom,\n\tenterToClass: style.slideEnterTo,\n\tleaveFromClass: style.slideLeaveFrom,\n\tleaveToClass: style.slideLeaveTo,\n}\n\n/**\n * @param operation - The operation to configure a new flow for\n */\nfunction createNewRule(operation: OperatorPlugin): void {\n\tstore.createNewRule(operation)\n}\n\nonMounted(() => {\n\tstore.fetchRules()\n})\n</script>\n\n<style module lang=\"scss\">\n@use \"./../styles/operation.scss\" as *;\n\n.workflowengine {\n\tborder-bottom: 1px solid var(--color-border);\n}\n\n.actions {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tmax-width: 1200px;\n}\n\n.card {\n\tmax-width: 280px;\n\tflex-basis: 250px;\n}\n\n.more {\n\tbackground-color: var(--color-background-dark);\n\ttext-align: center;\n}\n\n.moreIcon {\n\tmargin-block: 10px;\n}\n\n.showMore {\n\tmargin-bottom: 10px;\n}\n\n.slideEnterActive {\n\ttransition-duration: 0.3s;\n\ttransition-timing-function: ease-in;\n}\n\n.slideLeaveActive {\n\ttransition-duration: 0.3s;\n\ttransition-timing-function: cubic-bezier(0, 1, 0.5, 1);\n}\n\n.slideEnterTo,\n.slideLeaveFrom {\n\tmax-height: 500px;\n\toverflow: hidden;\n}\n\n.slideEnterFrom,\n.slideLeaveTo {\n\toverflow: hidden;\n\tmax-height: 0;\n\tpadding-top: 0;\n\tpadding-bottom: 0;\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { Ref } from 'vue'\n\nimport { ref, watch } from 'vue'\n\nexport interface CheckValueOptions<Internal> {\n\t/** Derives the editable value from the stored one; identity by default. */\n\tparse?: (modelValue: string) => Internal\n\t/** Derives the stored value from the editable one; identity by default. */\n\tformat?: (value: Internal) => string\n}\n\nexport interface CheckValue<Internal> {\n\t/** The value the editor works on. */\n\tnewValue: Ref<Internal>\n\t/** Discard local edits and take the stored value again. */\n\tsyncFromModel: () => void\n\t/** Store a value and tell the host about it. */\n\temitValue: (value?: Internal) => void\n}\n\n/**\n * Mirror the value a check editor was given into local state.\n *\n * Every check editor holds the value it is editing itself, because the host\n * only learns about a change once the editor emits it. The value is re-read\n * whenever the host replaces it, which happens when a rule is reverted or a\n * neighbouring filter is removed.\n *\n * @param getModelValue - Reads the value the host passed in\n * @param emit - Reports a new value to the host\n * @param options - How to convert between the stored and the editable value\n */\nexport function useCheckValue<Internal = string>(\n\tgetModelValue: () => string,\n\temit: (value: string) => void,\n\toptions: CheckValueOptions<Internal> = {},\n): CheckValue<Internal> {\n\tconst parse = options.parse ?? ((modelValue: string) => modelValue as unknown as Internal)\n\tconst format = options.format ?? ((value: Internal) => (value === null || value === undefined ? '' : String(value)))\n\n\tconst newValue = ref(parse(getModelValue())) as Ref<Internal>\n\n\tconst syncFromModel = (): void => {\n\t\tnewValue.value = parse(getModelValue())\n\t}\n\n\twatch(getModelValue, syncFromModel)\n\n\tconst emitValue = (value: Internal = newValue.value): void => {\n\t\tnewValue.value = value\n\t\temit(format(value))\n\t}\n\n\treturn { newValue, syncFromModel, emitValue }\n}\n","<!--\n - SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div>\n\t\t<NcSelect\n\t\t\t:aria-label-combobox=\"comboboxLabel\"\n\t\t\t:class=\"$style.select\"\n\t\t\t:clearable=\"false\"\n\t\t\t:modelValue=\"currentValue\"\n\t\t\t:options=\"options\"\n\t\t\t:placeholder=\"placeholder\"\n\t\t\tlabel=\"label\"\n\t\t\t@update:modelValue=\"onSelect\">\n\t\t\t<template #option=\"option\">\n\t\t\t\t<span v-if=\"option.icon\" :class=\"[$style.icon, option.icon]\" />\n\t\t\t\t<span v-else-if=\"option.iconUrl\" :class=\"$style.iconImage\">\n\t\t\t\t\t<img :src=\"option.iconUrl\" alt=\"\">\n\t\t\t\t</span>\n\t\t\t\t<span :class=\"$style.title\">\n\t\t\t\t\t<NcEllipsisedOption :name=\"String(option.label)\" />\n\t\t\t\t</span>\n\t\t\t</template>\n\t\t\t<template #selected-option=\"selectedOption\">\n\t\t\t\t<span v-if=\"selectedOption.icon\" :class=\"[$style.icon, selectedOption.icon]\" />\n\t\t\t\t<span v-else-if=\"selectedOption.iconUrl\" :class=\"$style.iconImage\">\n\t\t\t\t\t<img :src=\"selectedOption.iconUrl\" alt=\"\">\n\t\t\t\t</span>\n\t\t\t\t<span :class=\"$style.title\">\n\t\t\t\t\t<NcEllipsisedOption :name=\"String(selectedOption.label)\" />\n\t\t\t\t</span>\n\t\t\t</template>\n\t\t</NcSelect>\n\t\t<input\n\t\t\tv-if=\"!isPredefined\"\n\t\t\t:class=\"$style.customValue\"\n\t\t\t:placeholder=\"customPlaceholder\"\n\t\t\t:value=\"newValue\"\n\t\t\ttype=\"text\"\n\t\t\t@input=\"onCustomInput\">\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { PredefinedValue } from '../../types.ts'\n\nimport { computed } from 'vue'\nimport NcEllipsisedOption from '@nextcloud/vue/components/NcEllipsisedOption'\nimport NcSelect from '@nextcloud/vue/components/NcSelect'\nimport { useCheckValue } from '../../composables/useCheckValue.ts'\n\nconst props = withDefaults(defineProps<{\n\tmodelValue?: string\n\t/** The values offered besides free text */\n\tpredefinedValues: PredefinedValue[]\n\t/** Label of the entry that switches to free text */\n\tcustomLabel: string\n\t/** Accessible name of the combobox */\n\tcomboboxLabel: string\n\t/** Placeholder of the combobox */\n\tplaceholder: string\n\t/** Placeholder of the free text input */\n\tcustomPlaceholder?: string\n}>(), {\n\tmodelValue: '',\n\tcustomPlaceholder: undefined,\n})\n\nconst emit = defineEmits<{\n\t'update:modelValue': [value: string]\n}>()\n\nconst { newValue, emitValue } = useCheckValue(\n\t() => props.modelValue,\n\t(value) => emit('update:modelValue', value),\n)\n\nconst customValue = computed<PredefinedValue>(() => ({\n\ticon: 'icon-settings-dark',\n\tlabel: props.customLabel,\n\tid: '',\n}))\n\nconst options = computed(() => [...props.predefinedValues, customValue.value])\n\nconst matchingPredefined = computed(() => props.predefinedValues.find((value) => value.id === newValue.value))\n\nconst isPredefined = computed(() => matchingPredefined.value !== undefined)\n\nconst currentValue = computed<PredefinedValue>(() => matchingPredefined.value ?? { ...customValue.value, id: newValue.value })\n\n/**\n * Take a predefined value, or switch to free text when the custom entry was\n * picked, which carries an empty id.\n *\n * @param value - The option that was picked\n */\nfunction onSelect(value: PredefinedValue | null): void {\n\tif (value !== null) {\n\t\temitValue(value.id)\n\t}\n}\n\n/**\n * @param event - The input event of the free text field\n */\nfunction onCustomInput(event: Event): void {\n\temitValue((event.target as HTMLInputElement).value)\n}\n</script>\n\n<style module lang=\"scss\">\n.select,\n.customValue {\n\twidth: 100%;\n}\n\n.customValue {\n\tmin-height: 48px;\n}\n\n.icon,\n.iconImage {\n\tdisplay: inline-block;\n\tmin-width: 30px;\n\tbackground-position: center;\n\tvertical-align: middle;\n}\n\n.iconImage {\n\ttext-align: center;\n}\n\n.title {\n\tdisplay: inline-flex;\n\twidth: calc(100% - 36px);\n\tvertical-align: middle;\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<SelectWithCustomValue\n\t\t:comboboxLabel=\"t('workflowengine', 'File type')\"\n\t\t:customLabel=\"t('workflowengine', 'Custom MIME type')\"\n\t\t:customPlaceholder=\"t('workflowengine', 'e.g. httpd/unix-directory')\"\n\t\t:modelValue=\"modelValue\"\n\t\t:placeholder=\"t('workflowengine', 'Select a file type')\"\n\t\t:predefinedValues=\"predefinedTypes\"\n\t\t@update:modelValue=\"$emit('update:modelValue', $event)\" />\n</template>\n\n<script setup lang=\"ts\">\nimport type { PredefinedValue } from '../../types.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport { imagePath } from '@nextcloud/router'\nimport SelectWithCustomValue from './SelectWithCustomValue.vue'\n\nwithDefaults(defineProps<{ modelValue?: string }>(), { modelValue: '' })\n\ndefineEmits<{ 'update:modelValue': [value: string] }>()\n\nconst predefinedTypes: PredefinedValue[] = [\n\t{\n\t\ticonUrl: imagePath('core', 'filetypes/audio'),\n\t\tlabel: t('workflowengine', 'Audio'),\n\t\tid: '/audio\\\\/.*/',\n\t},\n\t{\n\t\ticon: 'icon-folder',\n\t\tlabel: t('workflowengine', 'Folder'),\n\t\tid: 'httpd/unix-directory',\n\t},\n\t{\n\t\ticon: 'icon-picture',\n\t\tlabel: t('workflowengine', 'Images'),\n\t\tid: '/image\\\\/.*/',\n\t},\n\t{\n\t\ticonUrl: imagePath('core', 'filetypes/x-office-document'),\n\t\tlabel: t('workflowengine', 'Office documents'),\n\t\tid: '/(vnd\\\\.(ms-|openxmlformats-|oasis\\\\.opendocument).*)$/',\n\t},\n\t{\n\t\ticonUrl: imagePath('core', 'filetypes/application-pdf'),\n\t\tlabel: t('workflowengine', 'PDF documents'),\n\t\tid: 'application/pdf',\n\t},\n\t{\n\t\ticonUrl: imagePath('core', 'filetypes/video'),\n\t\tlabel: t('workflowengine', 'Video'),\n\t\tid: '/video\\\\/.*/',\n\t},\n]\n</script>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<NcSelectTags\n\t\tv-model=\"newValue\"\n\t\t:aria-label-combobox=\"t('workflowengine', 'Tag')\"\n\t\t:limit=\"null\"\n\t\t:multiple=\"false\"\n\t\t@update:modelValue=\"emitValue()\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { t } from '@nextcloud/l10n'\nimport NcSelectTags from '@nextcloud/vue/components/NcSelectTags'\nimport { useCheckValue } from '../../composables/useCheckValue.ts'\n\nconst props = withDefaults(defineProps<{ modelValue?: string }>(), { modelValue: '' })\n\nconst emit = defineEmits<{ 'update:modelValue': [value: string] }>()\n\nconst { newValue, emitValue } = useCheckValue<number | null>(\n\t() => props.modelValue,\n\t(value) => emit('update:modelValue', value),\n\t{\n\t\t// NcSelectTags works on numeric tag ids, a rule stores the id as a string\n\t\tparse: (modelValue) => (modelValue === '' ? null : Number.parseInt(modelValue)),\n\t\tformat: (value) => String(value || ''),\n\t},\n)\n</script>\n","/**\n * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { ComponentPublicInstance } from 'vue'\n\nimport { defineCustomElement } from 'vue'\n\n/**\n * What a compiled single file component is, as `defineCustomElement` wants it.\n * Mirrors the constraint of its own overload.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype CustomElementComponent = new (...args: any[]) => ComponentPublicInstance<any>\nimport { logger } from '../logger.ts'\n\n/**\n * Register a component as a custom element, so it can be used as the value\n * editor of a check or as the options editor of an operation.\n *\n * The element renders in the light DOM: the settings page styles it, and its\n * own styles come from the app stylesheet rather than from a shadow root.\n *\n * @param component - The component to register\n * @param customElementId - Unique element name, prefixed with the app\n * namespace, e.g. `oca-myapp-checks-request_user_agent`\n * @return The element name, to be used as `CheckPlugin.element`\n */\nexport function registerCustomElement(component: CustomElementComponent, customElementId: string): string {\n\tif (window.customElements.get(customElementId)) {\n\t\tlogger.error(`Custom element with ID ${customElementId} is already defined!`)\n\t\tthrow new Error(`Custom element with ID ${customElementId} is already defined!`)\n\t}\n\n\twindow.customElements.define(customElementId, defineCustomElement(component, { shadowRoot: false }))\n\n\treturn customElementId\n}\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { Check } from '../types.ts'\n\nconst regexRegex = /^\\/(.*)\\/([gui]{0,3})$/\nconst regexIPv4 = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\/(3[0-2]|[1-2][0-9]|[1-9])$/\nconst regexIPv6 = /^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\\/(1([01][0-9]|2[0-8])|[1-9][0-9]|[0-9])$/\n\n/**\n * Whether a string is a delimited regular expression, e.g. `/^a.*$/i`.\n *\n * @param value - The string to check\n */\nexport function validateRegex(value: string): boolean {\n\tif (!value) {\n\t\treturn false\n\t}\n\treturn regexRegex.exec(value) !== null\n}\n\n/**\n * Whether a string is an IPv4 range in CIDR notation, e.g. `127.0.0.1/32`.\n *\n * @param value - The string to check\n */\nexport function validateIPv4(value: string): boolean {\n\tif (!value) {\n\t\treturn false\n\t}\n\treturn regexIPv4.exec(value) !== null\n}\n\n/**\n * Whether a string is an IPv6 range in CIDR notation, e.g. `::1/128`.\n *\n * @param value - The string to check\n */\nexport function validateIPv6(value: string): boolean {\n\tif (!value) {\n\t\treturn false\n\t}\n\treturn regexIPv6.exec(value) !== null\n}\n\n/**\n * Whether the value of a check is usable with its comparison. Only the\n * regular expression comparisons constrain the value.\n *\n * @param check - The check to validate\n */\nexport function stringValidator(check: Check): boolean {\n\tif (check.operator === 'matches' || check.operator === '!matches') {\n\t\treturn validateRegex(check.value)\n\t}\n\treturn true\n}\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { Check, CheckPlugin, Comparison } from '../../types.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport FileMimeType from './FileMimeType.vue'\nimport FileSystemTag from './FileSystemTag.vue'\nimport { registerCustomElement } from '../../helpers/customElements.ts'\nimport { stringValidator, validateIPv4, validateIPv6 } from '../../helpers/validators.ts'\n\n/** The comparisons a check offers that matches either literally or by regex. */\nfunction stringOrRegexOperators(): Comparison[] {\n\treturn [\n\t\t{ operator: 'matches', name: t('workflowengine', 'matches') },\n\t\t{ operator: '!matches', name: t('workflowengine', 'does not match') },\n\t\t{ operator: 'is', name: t('workflowengine', 'is') },\n\t\t{ operator: '!is', name: t('workflowengine', 'is not') },\n\t]\n}\n\nconst FileChecks: CheckPlugin[] = [\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\FileName',\n\t\tname: t('workflowengine', 'File name'),\n\t\toperators: stringOrRegexOperators,\n\t\tplaceholder: (check: Check) => {\n\t\t\tif (check.operator === 'matches' || check.operator === '!matches') {\n\t\t\t\treturn '/^dummy-.+$/i'\n\t\t\t}\n\t\t\treturn 'filename.txt'\n\t\t},\n\t\tvalidate: stringValidator,\n\t},\n\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\FileMimeType',\n\t\tname: t('workflowengine', 'File MIME type'),\n\t\toperators: stringOrRegexOperators,\n\t\telement: registerCustomElement(FileMimeType, 'oca-workflowengine-checks-file_mime_type'),\n\t},\n\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\FileSize',\n\t\tname: t('workflowengine', 'File size (upload)'),\n\t\toperators: [\n\t\t\t{ operator: 'less', name: t('workflowengine', 'less') },\n\t\t\t{ operator: '!greater', name: t('workflowengine', 'less or equals') },\n\t\t\t{ operator: '!less', name: t('workflowengine', 'greater or equals') },\n\t\t\t{ operator: 'greater', name: t('workflowengine', 'greater') },\n\t\t],\n\t\tplaceholder: () => '5 MB',\n\t\tvalidate: (check: Check) => (check.value ? check.value.match(/^[0-9]+[ ]?[kmgt]?b$/i) !== null : false),\n\t},\n\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\RequestRemoteAddress',\n\t\tname: t('workflowengine', 'Request remote address'),\n\t\toperators: [\n\t\t\t{ operator: 'matchesIPv4', name: t('workflowengine', 'matches IPv4') },\n\t\t\t{ operator: '!matchesIPv4', name: t('workflowengine', 'does not match IPv4') },\n\t\t\t{ operator: 'matchesIPv6', name: t('workflowengine', 'matches IPv6') },\n\t\t\t{ operator: '!matchesIPv6', name: t('workflowengine', 'does not match IPv6') },\n\t\t],\n\t\tplaceholder: (check: Check) => {\n\t\t\tif (check.operator === 'matchesIPv6' || check.operator === '!matchesIPv6') {\n\t\t\t\treturn '::1/128'\n\t\t\t}\n\t\t\treturn '127.0.0.1/32'\n\t\t},\n\t\tvalidate: (check: Check) => {\n\t\t\tif (check.operator === 'matchesIPv6' || check.operator === '!matchesIPv6') {\n\t\t\t\treturn validateIPv6(check.value)\n\t\t\t}\n\t\t\treturn validateIPv4(check.value)\n\t\t},\n\t},\n\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\FileSystemTags',\n\t\tname: t('workflowengine', 'File system tag'),\n\t\toperators: [\n\t\t\t{ operator: 'is', name: t('workflowengine', 'is tagged with') },\n\t\t\t{ operator: '!is', name: t('workflowengine', 'is not tagged with') },\n\t\t],\n\t\telement: registerCustomElement(FileSystemTag, 'oca-workflowengine-file_system_tag'),\n\t},\n]\n\nexport default FileChecks\n","/**\n * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\n/**\n * The time zones to offer.\n *\n * `Intl` lists the canonical zones only, which leaves out `UTC` — a zone rules\n * were able to pick before and that saved rules still carry.\n */\nexport function listTimezones(): string[] {\n\treturn ['UTC', ...Intl.supportedValuesOf('timeZone')]\n}\n\n/**\n * The time zone of this browser, used for a check that has none yet.\n */\nexport function currentTimezone(): string {\n\treturn Intl.DateTimeFormat().resolvedOptions().timeZone\n}\n\n/**\n * Whether a time zone can be resolved.\n *\n * Rules saved earlier may name a zone that is no longer offered, for instance a\n * legacy alias such as `Europe/Kiev`. Those still resolve, so a saved rule does\n * not turn invalid just because its zone left the list.\n *\n * @param timezone - The time zone to check\n */\nexport function isKnownTimezone(timezone: string | null): boolean {\n\tif (!timezone) {\n\t\treturn false\n\t}\n\ttry {\n\t\t// throws a RangeError for a zone that cannot be resolved\n\t\tnew Intl.DateTimeFormat(undefined, { timeZone: timezone })\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div :class=\"$style.timeslot\">\n\t\t<input\n\t\t\tv-model=\"newValue.startTime\"\n\t\t\t:aria-label=\"t('workflowengine', 'Start time')\"\n\t\t\t:class=\"[$style.time, $style.startTime]\"\n\t\t\tplaceholder=\"e.g. 08:00\"\n\t\t\ttype=\"text\"\n\t\t\t@input=\"update\">\n\t\t<input\n\t\t\tv-model=\"newValue.endTime\"\n\t\t\t:aria-label=\"t('workflowengine', 'End time')\"\n\t\t\t:class=\"$style.time\"\n\t\t\tplaceholder=\"e.g. 18:00\"\n\t\t\ttype=\"text\"\n\t\t\t@input=\"update\">\n\t\t<p v-if=\"!valid\" :class=\"$style.invalidHint\">\n\t\t\t{{ t('workflowengine', 'Please enter a valid time span') }}\n\t\t</p>\n\t\t<NcSelect\n\t\t\tv-show=\"valid\"\n\t\t\tv-model=\"newValue.timezone\"\n\t\t\t:aria-label-combobox=\"t('workflowengine', 'Timezone')\"\n\t\t\t:class=\"$style.timezone\"\n\t\t\t:clearable=\"false\"\n\t\t\t:options=\"timezones\"\n\t\t\t@update:modelValue=\"update\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { t } from '@nextcloud/l10n'\nimport { onBeforeMount, ref } from 'vue'\nimport NcSelect from '@nextcloud/vue/components/NcSelect'\nimport { useCheckValue } from '../../composables/useCheckValue.ts'\nimport { currentTimezone, isKnownTimezone, listTimezones } from '../../helpers/timezones.ts'\n\ninterface TimeSpan {\n\tstartTime: string | null\n\tendTime: string | null\n\ttimezone: string\n}\n\nconst props = withDefaults(defineProps<{ modelValue?: string }>(), { modelValue: '[]' })\n\nconst emit = defineEmits<{\n\t'update:modelValue': [value: string]\n\tvalid: []\n\tinvalid: []\n}>()\n\nconst TIME_PATTERN = /^(0[0-9]|1[0-9]|2[0-3]|[0-9]):[0-5][0-9]$/\n\nconst timezones = listTimezones()\nconst valid = ref(false)\n\n/**\n * Split the stored `[\"HH:MM Zone\",\"HH:MM Zone\"]` pair into its parts.\n *\n * @param modelValue - The stored value\n */\nfunction parseTimeSpan(modelValue: string): TimeSpan {\n\ttry {\n\t\tconst data = JSON.parse(modelValue)\n\t\tif (data.length === 2) {\n\t\t\treturn {\n\t\t\t\tstartTime: data[0].split(' ', 2)[0],\n\t\t\t\tendTime: data[1].split(' ', 2)[0],\n\t\t\t\ttimezone: data[0].split(' ', 2)[1],\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// ignore invalid values\n\t}\n\treturn { startTime: null, endTime: null, timezone: currentTimezone() }\n}\n\nconst { newValue, emitValue } = useCheckValue<TimeSpan>(\n\t() => props.modelValue,\n\t(value) => emit('update:modelValue', value),\n\t{\n\t\tparse: parseTimeSpan,\n\t\tformat: ({ startTime, endTime, timezone }) => `[\"${startTime} ${timezone}\",\"${endTime} ${timezone}\"]`,\n\t},\n)\n\n/**\n * Both ends have to be a time of day and the zone has to be one the browser knows.\n */\nfunction validate(): boolean {\n\tconst { startTime, endTime, timezone } = newValue.value\n\tvalid.value = Boolean(startTime) && TIME_PATTERN.test(startTime!)\n\t\t&& Boolean(endTime) && TIME_PATTERN.test(endTime!)\n\t\t&& isKnownTimezone(timezone)\n\tif (valid.value) {\n\t\temit('valid')\n\t} else {\n\t\temit('invalid')\n\t}\n\treturn valid.value\n}\n\nfunction update(): void {\n\tif (newValue.value.timezone === null) {\n\t\tnewValue.value.timezone = currentTimezone()\n\t}\n\tif (validate()) {\n\t\temitValue()\n\t}\n}\n\nonBeforeMount(validate)\n</script>\n\n<style module lang=\"scss\">\n.timeslot {\n\tdisplay: flex;\n\tflex-grow: 1;\n\tflex-wrap: wrap;\n\tmax-width: 180px;\n}\n\n.timezone {\n\twidth: 100%;\n\tmargin-bottom: 5px;\n}\n\n.time {\n\twidth: 50%;\n\tmargin: 0;\n\tmargin-bottom: 5px;\n\tmin-height: 48px;\n}\n\n.startTime {\n\tmargin-inline-end: 5px;\n\twidth: calc(50% - 5px);\n}\n\n.invalidHint {\n\tcolor: var(--color-text-maxcontrast);\n}\n</style>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<SelectWithCustomValue\n\t\t:comboboxLabel=\"t('workflowengine', 'Request URL')\"\n\t\t:customLabel=\"t('workflowengine', 'Custom URL')\"\n\t\t:customPlaceholder=\"customPlaceholder\"\n\t\t:modelValue=\"modelValue\"\n\t\t:placeholder=\"t('workflowengine', 'Select a request URL')\"\n\t\t:predefinedValues=\"predefinedTypes\"\n\t\t@update:modelValue=\"$emit('update:modelValue', $event)\" />\n</template>\n\n<script setup lang=\"ts\">\nimport type { PredefinedValue } from '../../types.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport { computed } from 'vue'\nimport SelectWithCustomValue from './SelectWithCustomValue.vue'\n\nconst props = withDefaults(defineProps<{\n\tmodelValue?: string\n\toperator?: string\n}>(), {\n\tmodelValue: '',\n\toperator: '',\n})\n\ndefineEmits<{ 'update:modelValue': [value: string] }>()\n\nconst predefinedTypes: PredefinedValue[] = [\n\t{\n\t\ticon: 'icon-files-dark',\n\t\tid: 'webdav',\n\t\tlabel: t('workflowengine', 'Files WebDAV'),\n\t},\n]\n\nconst customPlaceholder = computed(() => {\n\tif (props.operator === 'matches' || props.operator === '!matches') {\n\t\treturn '/^https\\\\:\\\\/\\\\/localhost\\\\/index\\\\.php$/i'\n\t}\n\treturn 'https://localhost/index.php'\n})\n</script>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<SelectWithCustomValue\n\t\t:comboboxLabel=\"t('workflowengine', 'User agent')\"\n\t\t:customLabel=\"t('workflowengine', 'Custom user agent')\"\n\t\t:modelValue=\"modelValue\"\n\t\t:placeholder=\"t('workflowengine', 'Select a user agent')\"\n\t\t:predefinedValues=\"predefinedTypes\"\n\t\t@update:modelValue=\"$emit('update:modelValue', $event)\" />\n</template>\n\n<script setup lang=\"ts\">\nimport type { PredefinedValue } from '../../types.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport SelectWithCustomValue from './SelectWithCustomValue.vue'\n\nwithDefaults(defineProps<{ modelValue?: string }>(), { modelValue: '' })\n\ndefineEmits<{ 'update:modelValue': [value: string] }>()\n\nconst predefinedTypes: PredefinedValue[] = [\n\t{ id: 'android', label: t('workflowengine', 'Android client'), icon: 'icon-phone' },\n\t{ id: 'ios', label: t('workflowengine', 'iOS client'), icon: 'icon-phone' },\n\t{ id: 'desktop', label: t('workflowengine', 'Desktop client'), icon: 'icon-desktop' },\n\t{ id: 'mail', label: t('workflowengine', 'Thunderbird & Outlook addons'), icon: 'icon-mail' },\n]\n</script>\n","<!--\n - SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n-->\n<template>\n\t<div>\n\t\t<NcSelect\n\t\t\t:aria-label-combobox=\"t('workflowengine', 'Select groups')\"\n\t\t\t:aria-label-listbox=\"t('workflowengine', 'Groups')\"\n\t\t\t:class=\"$style.select\"\n\t\t\t:clearable=\"false\"\n\t\t\t:loading=\"status.isLoading && groups.length === 0\"\n\t\t\t:modelValue=\"currentValue\"\n\t\t\t:options=\"groups\"\n\t\t\t:placeholder=\"t('workflowengine', 'Type to search for group …')\"\n\t\t\tlabel=\"displayname\"\n\t\t\t@search=\"searchAsync\"\n\t\t\t@update:modelValue=\"update\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport axios from '@nextcloud/axios'\nimport { t } from '@nextcloud/l10n'\nimport { generateOcsUrl } from '@nextcloud/router'\nimport { computed, onMounted, reactive, watch } from 'vue'\nimport NcSelect from '@nextcloud/vue/components/NcSelect'\nimport { useCheckValue } from '../../composables/useCheckValue.ts'\nimport { logger } from '../../logger.ts'\n\ninterface Group {\n\tid: string\n\tdisplayname: string\n}\n\nconst props = withDefaults(defineProps<{ modelValue?: string }>(), { modelValue: '' })\nconst emit = defineEmits<{ 'update:modelValue': [value: string] }>()\n// shared across every instance on the page: the group list is the same for all\n// of them and is expensive to fetch again per check\nconst groups = reactive<Group[]>([])\nconst wantedGroups = reactive<string[]>([])\nconst status = reactive({ isLoading: false })\n\nconst { newValue, emitValue } = useCheckValue(\n\t() => props.modelValue,\n\t(value) => emit('update:modelValue', value),\n)\n\nconst currentValue = computed(() => groups.find((group) => group.id === newValue.value) ?? null)\n\n/**\n * @param group - The group to remember\n */\nfunction addGroup(group: Group): void {\n\tif (!groups.some((item) => item.id === group.id)) {\n\t\tgroups.push(group)\n\t}\n}\n\n/**\n * @param groupId - Id of the group to look for\n */\nfunction hasGroup(groupId: string): boolean {\n\treturn groups.some((item) => item.id === groupId)\n}\n\n/**\n * @param expectedGroupId - Group to look up once the current request is done\n */\nfunction enqueueWantedGroup(expectedGroupId: string): void {\n\tif (!wantedGroups.includes(expectedGroupId)) {\n\t\twantedGroups.push(expectedGroupId)\n\t}\n}\n\nasync function findGroupByQueue(): Promise<void> {\n\tlet nextQuery: string | undefined\n\tdo {\n\t\tnextQuery = wantedGroups.shift()\n\t\tif (nextQuery !== undefined && hasGroup(nextQuery)) {\n\t\t\tnextQuery = undefined\n\t\t}\n\t} while (!nextQuery && wantedGroups.length > 0)\n\tif (nextQuery) {\n\t\tawait searchAsync(nextQuery)\n\t}\n}\n\n/**\n * @param searchQuery - Text to search groups for, empty for the first chunk\n */\nasync function searchAsync(searchQuery: string): Promise<void> {\n\tif (status.isLoading) {\n\t\tif (searchQuery) {\n\t\t\t// The first 20 groups are loaded up front (indicated by an empty\n\t\t\t// searchQuery parameter), afterwards we may load groups that have\n\t\t\t// not been fetched yet, but are used in existing rules.\n\t\t\tenqueueWantedGroup(searchQuery)\n\t\t}\n\t\treturn\n\t}\n\n\tstatus.isLoading = true\n\ttry {\n\t\tconst { data } = await axios.get(generateOcsUrl('cloud/groups/details?limit=20&search={searchQuery}', { searchQuery }))\n\t\tdata.ocs.data.groups.forEach((group: Group) => {\n\t\t\taddGroup({ id: group.id, displayname: group.displayname })\n\t\t})\n\t\tstatus.isLoading = false\n\t\tawait findGroupByQueue()\n\t} catch (error) {\n\t\tstatus.isLoading = false\n\t\tlogger.error('Error while loading group list', { error })\n\t}\n}\n\n/**\n * @param value - The group that was picked\n */\nfunction update(value: Group | null): void {\n\tif (value !== null) {\n\t\temitValue(value.id)\n\t}\n}\n\nwatch(newValue, (value) => {\n\tif (value && currentValue.value === null) {\n\t\tsearchAsync(value)\n\t}\n})\n\nonMounted(async () => {\n\tif (groups.length === 0) {\n\t\tawait searchAsync('')\n\t}\n\t// the group of a stored rule may not be among the ones loaded up front\n\tif (currentValue.value === null && newValue.value) {\n\t\tawait searchAsync(newValue.value)\n\t}\n})\n</script>\n\n<style module>\n.select {\n\twidth: 100%;\n}\n</style>\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { CheckPlugin } from '../../types.ts'\n\nimport { t } from '@nextcloud/l10n'\nimport RequestTime from './RequestTime.vue'\nimport RequestURL from './RequestURL.vue'\nimport RequestUserAgent from './RequestUserAgent.vue'\nimport RequestUserGroup from './RequestUserGroup.vue'\nimport { registerCustomElement } from '../../helpers/customElements.ts'\n\nconst RequestChecks: CheckPlugin[] = [\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\RequestURL',\n\t\tname: t('workflowengine', 'Request URL'),\n\t\toperators: [\n\t\t\t{ operator: 'is', name: t('workflowengine', 'is') },\n\t\t\t{ operator: '!is', name: t('workflowengine', 'is not') },\n\t\t\t{ operator: 'matches', name: t('workflowengine', 'matches') },\n\t\t\t{ operator: '!matches', name: t('workflowengine', 'does not match') },\n\t\t],\n\t\telement: registerCustomElement(RequestURL, 'oca-workflowengine-checks-request_url'),\n\t},\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\RequestTime',\n\t\tname: t('workflowengine', 'Request time'),\n\t\toperators: [\n\t\t\t{ operator: 'in', name: t('workflowengine', 'between') },\n\t\t\t{ operator: '!in', name: t('workflowengine', 'not between') },\n\t\t],\n\t\telement: registerCustomElement(RequestTime, 'oca-workflowengine-checks-request_time'),\n\t},\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\RequestUserAgent',\n\t\tname: t('workflowengine', 'Request user agent'),\n\t\toperators: [\n\t\t\t{ operator: 'is', name: t('workflowengine', 'is') },\n\t\t\t{ operator: '!is', name: t('workflowengine', 'is not') },\n\t\t\t{ operator: 'matches', name: t('workflowengine', 'matches') },\n\t\t\t{ operator: '!matches', name: t('workflowengine', 'does not match') },\n\t\t],\n\t\telement: registerCustomElement(RequestUserAgent, 'oca-workflowengine-checks-request_user_agent'),\n\t},\n\t{\n\t\tclass: 'OCA\\\\WorkflowEngine\\\\Check\\\\UserGroupMembership',\n\t\tname: t('workflowengine', 'Group membership'),\n\t\toperators: [\n\t\t\t{ operator: 'is', name: t('workflowengine', 'is member of') },\n\t\t\t{ operator: '!is', name: t('workflowengine', 'is not member of') },\n\t\t],\n\t\telement: registerCustomElement(RequestUserGroup, 'oca-workflowengine-checks-request_user_group'),\n\t},\n]\n\nexport default RequestChecks\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport FileChecks from './file.ts'\nimport RequestChecks from './request.ts'\n\nexport default [...FileChecks, ...RequestChecks]\n","/**\n * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors\n * SPDX-License-Identifier: AGPL-3.0-or-later\n */\n\nimport type { CheckPlugin, OperatorPlugin, WorkflowEngineApi } from './types.ts'\n\nimport { createPinia, setActivePinia } from 'pinia'\nimport { createApp } from 'vue'\nimport Workflow from './components/Workflow.vue'\nimport ShippedChecks from './components/Checks/index.ts'\nimport { useWorkflowStore } from './store.ts'\n\nconst pinia = createPinia()\n// apps may register their plugins before the app is mounted, so the store has\n// to be usable outside of a component from here on\nsetActivePinia(pinia)\n\nconst store = useWorkflowStore()\n\n// every app declares `window.OCA` with its own members, so the part this app\n// owns is narrowed here instead of in a global declaration\nconst OCA = window.OCA as unknown as { WorkflowEngine?: WorkflowEngineApi }\n\n/**\n * Public javascript api for apps to register custom plugins\n */\nOCA.WorkflowEngine = {\n\t...OCA.WorkflowEngine,\n\n\t/**\n\t * Register the value editor of a check.\n\t *\n\t * @param plugin - The plugin to register\n\t */\n\tregisterCheck(plugin: CheckPlugin): void {\n\t\tstore.addPluginCheck(plugin)\n\t},\n\n\t/**\n\t * Register the presentation of an operation.\n\t *\n\t * @param plugin - The plugin to register\n\t */\n\tregisterOperator(plugin: OperatorPlugin): void {\n\t\tstore.addPluginOperator(plugin)\n\t},\n}\n\nShippedChecks.forEach((checkPlugin) => OCA.WorkflowEngine!.registerCheck(checkPlugin))\n\ncreateApp(Workflow)\n\t.use(pinia)\n\t.mount('#workflowengine')\n"],"names":["DEFAULT_TEXT_COLOR","MINIMUM_CONTRAST","knownTextColor","backgroundColor","contrastingTextColor","Color","iconFilterFor","textColor","props","__props","operationElement","ref","color","computed","watch","known","resolved","nextTick","iconFilter","_createElementBlock","_normalizeClass","$style","_createElementVNode","_toDisplayString","_createBlock","_unref","NcButton","t","_renderSlot","_ctx","useCustomElementEvents","element","handlers","entries","subscribe","target","name","handler","unsubscribe","current","previous","onScopeDispose","logger","getLoggerBuilder","Scope","getApiUrl","scope","path","scopeValue","generateOcsUrl","DEFAULT_OPERATOR_COLOR","flattenEvents","entities","entity","event","useWorkflowStore","defineStore","loadState","appstoreEnabled","events","checks","rules","operations","pluginChecks","configuredRules","rule","first","second","operationForRule","entityForOperation","operation","checksForEntity","check","available","plugin","addPluginCheck","addPluginOperator","merged","updateRule","index","item","stored","updateCheck","patch","addCheck","removeCheck","setRuleTrigger","setRuleOperation","removeRule","fetchRules","data","axios","createNewRule","confirmPassword","firstEvent","pushUpdateRule","deleteRule","setValid","valid","emit","__emit","store","checkElement","useTemplateRef","valueElement","checkSelector","deleteVisible","elementValid","options","currentOption","operators","currentOperator","operator","currentElement","valuePlaceholder","showDelete","onClickOutside","validate","update","onFilterChange","option","onComparatorChange","comparison","onElementValue","onElementValidity","reported","onValueInput","onMounted","_createVNode","NcSelect","_openBlock","_resolveDynamicComponent","NcActions","NcActionButton","NcIconSvgWrapper","mdiClose","allEvents","currentEvent","placeholderString","updateEvent","showWarning","existingEntity","newEntities","newEntity","entityId","_hoisted_1","_withCtx","error","dirty","originalRule","inputValue","ruleStatus","mdiArrowRight","mdiCheck","lastCheckComplete","lastCheck","checkKeys","lastCheckKey","checkKey","key","updateOperationByEvent","saveRule","toPlainRule","exception","ocsMessage","cancelRule","onAddFilter","_normalizeStyle","Event","_Fragment","_renderList","Check","$event","Operation","WorkflowOffSvg","ACTION_LIMIT","style","useCssModule","showMoreOperations","appstoreUrl","generateUrl","workflowDocUrl","isUserAdmin","getCurrentUser","hasMoreOperations","mainOperations","all","isAdminScope","showAppStoreHint","slideTransition","NcSettingsSection","_hoisted_2","NcEmptyContent","_TransitionGroup","_mergeProps","mdiPlus","_cache","mdiMenuUp","mdiMenuDown","_createTextVNode","Rule","useCheckValue","getModelValue","parse","modelValue","format","value","newValue","syncFromModel","emitValue","customValue","matchingPredefined","isPredefined","currentValue","onSelect","onCustomInput","NcEllipsisedOption","selectedOption","predefinedTypes","imagePath","SelectWithCustomValue","$emit","NcSelectTags","registerCustomElement","component","customElementId","defineCustomElement","regexRegex","regexIPv4","regexIPv6","validateRegex","validateIPv4","validateIPv6","stringValidator","stringOrRegexOperators","FileChecks","FileMimeType","FileSystemTag","listTimezones","currentTimezone","isKnownTimezone","timezone","TIME_PATTERN","timezones","parseTimeSpan","startTime","endTime","onBeforeMount","_vModelText","customPlaceholder","groups","reactive","wantedGroups","status","group","addGroup","hasGroup","groupId","enqueueWantedGroup","expectedGroupId","findGroupByQueue","nextQuery","searchAsync","searchQuery","RequestChecks","RequestURL","RequestTime","RequestUserAgent","RequestUserGroup","ShippedChecks","pinia","createPinia","setActivePinia","OCA","checkPlugin","createApp","Workflow"],"mappings":"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"} |