refactor: plugin manifest (#28673)

This commit is contained in:
Jason Rasmussen 2026-05-28 17:23:49 -04:00 committed by GitHub
parent 134c0d4dfb
commit 8783180cf3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 140 additions and 118 deletions

View file

@ -64,7 +64,7 @@
<Self schema={childSchema} key={childKey} bind:config={getValue, setValue} />
{/each}
</div>
{:else if schema.uiHint === 'albumId'}
{:else if schema.uiHint === 'AlbumId'}
<SchemaAlbumPicker {label} {description} array={schema.array} bind:albumIds={getUiHintValue, setUiHintValue} />
{:else if schema.enum && schema.array}
<Field {label} {description}>

View file

@ -24,7 +24,7 @@
<div class="grow text-start">
<Text fontWeight="medium" class="flex items-center gap-1"
>{method.title}
{#if method.uiHints.includes('filter')}
{#if method.uiHints.includes('Filter')}
<Badge size="tiny" color="info" title={$t('plugin_method_filter_type_description')}
>{$t('plugin_method_filter_type')}</Badge
>

View file

@ -1,37 +0,0 @@
<script lang="ts">
import { pluginManager } from '$lib/managers/plugin-manager.svelte';
import { handleUpdateWorkflow } from '$lib/services/workflow.service';
import { getTriggerDescription, getTriggerName } from '$lib/utils/workflow';
import { type WorkflowResponseDto } from '@immich/sdk';
import { FormModal, ListButton, Text } from '@immich/ui';
import { t } from 'svelte-i18n';
type Props = {
workflow: WorkflowResponseDto;
onClose: () => void;
};
const { workflow, onClose }: Props = $props();
let selected = $state(pluginManager.getTrigger(workflow.trigger));
const onSubmit = async () => {
const success = await handleUpdateWorkflow(workflow.id, { trigger: selected.trigger });
if (success) {
onClose();
}
};
</script>
<FormModal title={$t('trigger')} {onClose} {onSubmit} size="small">
<div class="flex flex-col gap-2">
{#each pluginManager.triggers as item (item.trigger)}
<ListButton selected={item.trigger === selected.trigger} onclick={() => (selected = item)}>
<div class="grow text-start">
<Text fontWeight="medium">{getTriggerName($t, item.trigger)}</Text>
<Text size="tiny" color="muted">{getTriggerDescription($t, item.trigger)}</Text>
</div>
</ListButton>
{/each}
</div>
</FormModal>

View file

@ -2,7 +2,7 @@
import { pluginManager } from '$lib/managers/plugin-manager.svelte';
import { handleCreateWorkflow } from '$lib/services/workflow.service';
import { type PluginTemplateResponseDto } from '@immich/sdk';
import { FormModal, Icon, ListButton, Text } from '@immich/ui';
import { Badge, FormModal, Icon, ListButton, Text } from '@immich/ui';
import { mdiFlashOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
@ -59,6 +59,11 @@
<Text fontWeight="medium">{template.title}</Text>
<Text size="tiny" color="muted">{template.description}</Text>
</div>
{#if template.uiHints.includes('SmartAlbum')}
<div class="shrink-0">
<Badge size="small">{$t('smart_album')}</Badge>
</div>
{/if}
</div>
</ListButton>
{/each}

View file

@ -26,7 +26,7 @@ import type { MessageFormatter } from 'svelte-i18n';
import { goto } from '$app/navigation';
import { eventManager } from '$lib/managers/event-manager.svelte';
import WorkflowDuplicateModal from '$lib/modals/WorkflowDuplicateModal.svelte';
import WorkflowTemplatePicker from '$lib/modals/WorkflowTemplatePicker.svelte';
import WorkflowTemplatePickerModal from '$lib/modals/WorkflowTemplatePickerModal.svelte';
import { Route } from '$lib/route';
import { copyToClipboard, downloadJson } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
@ -50,7 +50,7 @@ export const getWorkflowsActions = ($t: MessageFormatter) => {
const UseTemplate: ActionItem = {
title: $t('browse_templates'),
icon: mdiFileDocumentMultipleOutline,
onAction: () => modalManager.show(WorkflowTemplatePicker, {}),
onAction: () => modalManager.show(WorkflowTemplatePickerModal, {}),
};
return { Create, UseTemplate };

View file

@ -104,7 +104,7 @@ export type JSONSchemaProperty = {
array?: boolean;
properties?: Record<string, JSONSchemaProperty>;
required?: string[];
uiHint?: 'albumId' | 'assetId' | 'personId';
uiHint?: 'AlbumId' | 'AssetId' | 'PersonId';
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View file

@ -26,7 +26,7 @@
let { step, index, onEdit, onDelete, onInsertBefore, onDrop }: Props = $props();
const method = $derived(pluginManager.getMethod(step.method));
const isFilter = $derived(method?.uiHints?.includes('filter') ?? false);
const isFilter = $derived(method?.uiHints?.includes('Filter') ?? false);
const configEntries = $derived(
Object.entries(step.config ?? {}).filter(([, value]) => value !== null && value !== undefined && value !== ''),
);
@ -75,7 +75,7 @@
target: document.body,
props: {
description: method?.description,
isFilter: method?.uiHints?.includes('filter') ?? false,
isFilter: method?.uiHints?.includes('Filter') ?? false,
label: step ? pluginManager.getMethodLabel(step.method) : '',
stepNumber: index + 1,
},

View file

@ -67,7 +67,7 @@
for (const [i, step] of workflow.steps.entries()) {
const method = pluginManager.getMethod(step.method);
const isFilter = method?.uiHints?.includes('filter') ?? false;
const isFilter = method?.uiHints?.includes('Filter') ?? false;
const type = isFilter ? $t('filter') : $t('action');
const label = pluginManager.getMethodLabel(step.method);
lines.push(` [${i + 1}] ${type.toUpperCase()} · ${label}`);