use showDialog directly

This commit is contained in:
Alex Tran
2025-12-04 04:18:35 +00:00
parent 288ba44825
commit 5eccffc084
13 changed files with 73 additions and 98 deletions

View File

@@ -2144,7 +2144,11 @@
"trash_page_title": "Trash ({count})",
"trashed_items_will_be_permanently_deleted_after": "Trashed items will be permanently deleted after {days, plural, one {# day} other {# days}}.",
"trigger": "Trigger",
"trigger_asset_uploaded": "Asset Uploaded",
"trigger_asset_uploaded_description": "Triggered when a new asset is uploaded",
"trigger_description": "An event that kick off the workflow",
"trigger_person_recognized": "Person Recognized",
"trigger_person_recognized_description": "Triggered when a person is detected",
"trigger_type": "Trigger type",
"troubleshoot": "Troubleshoot",
"type": "Type",

View File

@@ -14,42 +14,30 @@ class PluginTriggerResponseDto {
/// Returns a new [PluginTriggerResponseDto] instance.
PluginTriggerResponseDto({
required this.contextType,
required this.description,
required this.name,
required this.type,
});
PluginContextType contextType;
String description;
String name;
PluginTriggerType type;
@override
bool operator ==(Object other) => identical(this, other) || other is PluginTriggerResponseDto &&
other.contextType == contextType &&
other.description == description &&
other.name == name &&
other.type == type;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(contextType.hashCode) +
(description.hashCode) +
(name.hashCode) +
(type.hashCode);
@override
String toString() => 'PluginTriggerResponseDto[contextType=$contextType, description=$description, name=$name, type=$type]';
String toString() => 'PluginTriggerResponseDto[contextType=$contextType, type=$type]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'contextType'] = this.contextType;
json[r'description'] = this.description;
json[r'name'] = this.name;
json[r'type'] = this.type;
return json;
}
@@ -64,8 +52,6 @@ class PluginTriggerResponseDto {
return PluginTriggerResponseDto(
contextType: PluginContextType.fromJson(json[r'contextType'])!,
description: mapValueOfType<String>(json, r'description')!,
name: mapValueOfType<String>(json, r'name')!,
type: PluginTriggerType.fromJson(json[r'type'])!,
);
}
@@ -115,8 +101,6 @@ class PluginTriggerResponseDto {
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'contextType',
'description',
'name',
'type',
};
}

View File

@@ -18459,12 +18459,6 @@
}
]
},
"description": {
"type": "string"
},
"name": {
"type": "string"
},
"type": {
"allOf": [
{
@@ -18475,8 +18469,6 @@
},
"required": [
"contextType",
"description",
"name",
"type"
],
"type": "object"

View File

@@ -968,8 +968,6 @@ export type PluginResponseDto = {
};
export type PluginTriggerResponseDto = {
contextType: PluginContextType;
description: string;
name: string;
"type": PluginTriggerType;
};
export type QueueResponseDto = {

View File

@@ -5,10 +5,8 @@ import type { JSONSchema } from 'src/types/plugin-schema.types';
import { ValidateEnum } from 'src/validation';
export class PluginTriggerResponseDto {
name!: string;
@ValidateEnum({ enum: PluginTriggerType, name: 'PluginTriggerType' })
type!: PluginTriggerType;
description!: string;
@ValidateEnum({ enum: PluginContextType, name: 'PluginContextType' })
contextType!: PluginContextType;
}

View File

@@ -1,23 +1,17 @@
import { PluginContext, PluginTriggerType } from 'src/enum';
export type PluginTrigger = {
name: string;
type: PluginTriggerType;
description: string;
contextType: PluginContext;
};
export const pluginTriggers: PluginTrigger[] = [
{
name: 'Asset Uploaded',
type: PluginTriggerType.AssetCreate,
description: 'Triggered when a new asset is uploaded',
contextType: PluginContext.Asset,
},
{
name: 'Person Recognized',
type: PluginTriggerType.PersonRecognized,
description: 'Triggered when a person is detected',
contextType: PluginContext.Person,
},
];

View File

@@ -1,5 +1,10 @@
<script lang="ts">
import type { PluginActionResponseDto, PluginFilterResponseDto, PluginTriggerResponseDto } from '@immich/sdk';
import {
PluginTriggerType,
type PluginActionResponseDto,
type PluginFilterResponseDto,
type PluginTriggerResponseDto,
} from '@immich/sdk';
import { Icon, IconButton, Text } from '@immich/ui';
import { mdiClose, mdiFilterOutline, mdiFlashOutline, mdiPlayCircleOutline, mdiViewDashboardOutline } from '@mdi/js';
import { t } from 'svelte-i18n';
@@ -12,6 +17,20 @@
let { trigger, filters, actions }: Props = $props();
const getTriggerName = (triggerType: PluginTriggerType) => {
switch (triggerType) {
case PluginTriggerType.AssetCreate: {
return $t('trigger_asset_uploaded');
}
case PluginTriggerType.PersonRecognized: {
return $t('trigger_person_recognized');
}
default: {
return triggerType;
}
}
};
let isOpen = $state(false);
let position = $state({ x: 0, y: 0 });
let isDragging = $state(false);
@@ -96,7 +115,7 @@
<Icon icon={mdiFlashOutline} size="18" class="text-primary" />
<span class="text-[10px] font-semibold uppercase tracking-wide">{$t('trigger')}</span>
</div>
<p class="text-sm truncate pl-5">{trigger.name}</p>
<p class="text-sm truncate pl-5">{getTriggerName(trigger.type)}</p>
</div>
<!-- Connector -->

View File

@@ -2,6 +2,7 @@
import { PluginTriggerType, type PluginTriggerResponseDto } from '@immich/sdk';
import { Icon, Text } from '@immich/ui';
import { mdiFaceRecognition, mdiFileUploadOutline, mdiLightningBolt } from '@mdi/js';
import { t } from 'svelte-i18n';
interface Props {
trigger: PluginTriggerResponseDto;
@@ -24,6 +25,34 @@
}
}
};
const getTriggerName = (triggerType: PluginTriggerType) => {
switch (triggerType) {
case PluginTriggerType.AssetCreate: {
return $t('trigger_asset_uploaded');
}
case PluginTriggerType.PersonRecognized: {
return $t('trigger_person_recognized');
}
default: {
return triggerType;
}
}
};
const getTriggerDescription = (triggerType: PluginTriggerType) => {
switch (triggerType) {
case PluginTriggerType.AssetCreate: {
return $t('trigger_asset_uploaded_description');
}
case PluginTriggerType.PersonRecognized: {
return $t('trigger_person_recognized_description');
}
default: {
return '';
}
}
};
</script>
<button
@@ -42,9 +71,9 @@
<Icon icon={getTriggerIcon(trigger.type)} size="24" />
</div>
<div class="flex-1">
<Text class="font-semibold mb-1">{trigger.name}</Text>
{#if trigger.description}
<Text size="small">{trigger.description}</Text>
<Text class="font-semibold mb-1">{getTriggerName(trigger.type)}</Text>
{#if getTriggerDescription(trigger.type)}
<Text size="small">{getTriggerDescription(trigger.type)}</Text>
{/if}
</div>
</div>

View File

@@ -1,16 +0,0 @@
<script lang="ts">
import { ConfirmModal } from '@immich/ui';
import { t } from 'svelte-i18n';
type Props = {
onClose: (confirmed: boolean) => void;
};
let { onClose }: Props = $props();
</script>
<ConfirmModal
confirmColor="danger"
prompt={$t('workflow_delete_prompt')}
onClose={(confirmed) => (confirmed ? onClose(true) : onClose(false))}
/>

View File

@@ -1,16 +0,0 @@
<script lang="ts">
import { ConfirmModal } from '@immich/ui';
import { t } from 'svelte-i18n';
type Props = {
onClose: (confirmed: boolean) => void;
};
let { onClose }: Props = $props();
</script>
<ConfirmModal
confirmColor="primary"
prompt={$t('workflow_navigation_prompt')}
onClose={(confirmed) => (confirmed ? onClose(true) : onClose(false))}
/>

View File

@@ -1,19 +0,0 @@
<script lang="ts">
import { ConfirmModal } from '@immich/ui';
import { mdiLightningBolt } from '@mdi/js';
import { t } from 'svelte-i18n';
type Props = {
onClose: (confirmed: boolean) => void;
};
let { onClose }: Props = $props();
</script>
<ConfirmModal
confirmColor="primary"
title={$t('change_trigger')}
icon={mdiLightningBolt}
prompt={$t('change_trigger_prompt')}
onClose={(confirmed) => (confirmed ? onClose(true) : onClose(false))}
/>

View File

@@ -2,7 +2,6 @@
import { goto } from '$app/navigation';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import { AppRoute } from '$lib/constants';
import WorkflowDeleteConfirmModal from '$lib/modals/WorkflowDeleteConfirmModal.svelte';
import type { WorkflowPayload } from '$lib/services/workflow.service';
import { handleError } from '$lib/utils/handle-error';
import {
@@ -109,7 +108,11 @@
const handleDeleteWorkflow = async (workflow: WorkflowResponseDto) => {
try {
const confirmed = await modalManager.show(WorkflowDeleteConfirmModal);
const confirmed = await modalManager.showDialog({
prompt: $t('workflow_delete_prompt'),
confirmColor: 'danger',
});
if (!confirmed) {
return;
}

View File

@@ -9,8 +9,6 @@
import WorkflowTriggerCard from '$lib/components/workflows/WorkflowTriggerCard.svelte';
import { AppRoute } from '$lib/constants';
import AddWorkflowStepModal from '$lib/modals/AddWorkflowStepModal.svelte';
import WorkflowNavigationConfirmModal from '$lib/modals/WorkflowNavigationConfirmModal.svelte';
import WorkflowTriggerUpdateConfirmModal from '$lib/modals/WorkflowTriggerUpdateConfirmModal.svelte';
import {
buildWorkflowPayload,
getActionsByContext,
@@ -287,7 +285,11 @@
};
const handleTriggerChange = async (newTrigger: PluginTriggerResponseDto) => {
const confirmed = await modalManager.show(WorkflowTriggerUpdateConfirmModal);
const confirmed = await modalManager.showDialog({
prompt: $t('change_trigger_prompt'),
title: $t('change_trigger'),
confirmColor: 'primary',
});
if (!confirmed) {
return;
@@ -303,7 +305,10 @@
cancel();
modalManager
.show(WorkflowNavigationConfirmModal)
.showDialog({
prompt: $t('workflow_navigation_prompt'),
confirmColor: 'primary',
})
.then((isConfirmed) => {
if (isConfirmed && to) {
allowNavigation = true;
@@ -398,7 +403,7 @@
<CardBody>
<div class="grid grid-cols-2 gap-4">
{#each triggers as trigger (trigger.name)}
{#each triggers as trigger (trigger.type)}
<WorkflowTriggerCard
{trigger}
selected={selectedTrigger.type === trigger.type}