mirror of
https://github.com/immich-app/immich.git
synced 2025-12-17 17:23:20 +03:00
feat: workflow foundation (#23621)
* feat: plugins * feat: table definition * feat: type and migration * feat: add repositories * feat: validate manifest with class-validator and load manifest info to database * feat: workflow/plugin controller/service layer * feat: implement workflow logic * feat: make trigger static * feat: dynamical instantiate plugin instances * fix: access control and helper script * feat: it works * chore: simplify * refactor: refactor and use queue for workflow execution * refactor: remove unsused property in plugin-schema * build wasm in prod * feat: plugin loader in transaction * fix: docker build arm64 * generated files * shell check * fix tests * fix: waiting for migration to finish before loading plugin * remove context reassignment * feat: use mise to manage extism tools (#23760) * pr feedback * refactor: create workflow now including create filters and actions * feat: workflow medium tests * fix: broken medium test * feat: medium tests * chore: unify workflow job * sign user id with jwt * chore: query plugin with filters and action * chore: read manifest in repository * chore: load manifest from server configs * merge main * feat: endpoint documentation * pr feedback * load plugin from absolute path * refactor:handle trigger * throw error and return early * pr feedback * unify plugin services * fix: plugins code * clean up * remove triggerConfig * clean up * displayName and methodName --------- Co-authored-by: Jason Rasmussen <jason@rasm.me> Co-authored-by: bo0tzz <git@bo0tzz.me>
This commit is contained in:
@@ -732,6 +732,7 @@ export type QueuesResponseDto = {
|
||||
storageTemplateMigration: QueueResponseDto;
|
||||
thumbnailGeneration: QueueResponseDto;
|
||||
videoConversion: QueueResponseDto;
|
||||
workflow: QueueResponseDto;
|
||||
};
|
||||
export type JobCreateDto = {
|
||||
name: ManualJobName;
|
||||
@@ -926,6 +927,36 @@ export type AssetFaceUpdateDto = {
|
||||
export type PersonStatisticsResponseDto = {
|
||||
assets: number;
|
||||
};
|
||||
export type PluginActionResponseDto = {
|
||||
description: string;
|
||||
id: string;
|
||||
methodName: string;
|
||||
pluginId: string;
|
||||
schema: object | null;
|
||||
supportedContexts: PluginContext[];
|
||||
title: string;
|
||||
};
|
||||
export type PluginFilterResponseDto = {
|
||||
description: string;
|
||||
id: string;
|
||||
methodName: string;
|
||||
pluginId: string;
|
||||
schema: object | null;
|
||||
supportedContexts: PluginContext[];
|
||||
title: string;
|
||||
};
|
||||
export type PluginResponseDto = {
|
||||
actions: PluginActionResponseDto[];
|
||||
author: string;
|
||||
createdAt: string;
|
||||
description: string;
|
||||
filters: PluginFilterResponseDto[];
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
updatedAt: string;
|
||||
version: string;
|
||||
};
|
||||
export type SearchExploreItem = {
|
||||
data: AssetResponseDto;
|
||||
value: string;
|
||||
@@ -1411,6 +1442,7 @@ export type SystemConfigJobDto = {
|
||||
smartSearch: JobSettingsDto;
|
||||
thumbnailGeneration: JobSettingsDto;
|
||||
videoConversion: JobSettingsDto;
|
||||
workflow: JobSettingsDto;
|
||||
};
|
||||
export type SystemConfigLibraryScanDto = {
|
||||
cronExpression: string;
|
||||
@@ -1667,6 +1699,54 @@ export type CreateProfileImageResponseDto = {
|
||||
profileImagePath: string;
|
||||
userId: string;
|
||||
};
|
||||
export type WorkflowActionResponseDto = {
|
||||
actionConfig: object | null;
|
||||
actionId: string;
|
||||
id: string;
|
||||
order: number;
|
||||
workflowId: string;
|
||||
};
|
||||
export type WorkflowFilterResponseDto = {
|
||||
filterConfig: object | null;
|
||||
filterId: string;
|
||||
id: string;
|
||||
order: number;
|
||||
workflowId: string;
|
||||
};
|
||||
export type WorkflowResponseDto = {
|
||||
actions: WorkflowActionResponseDto[];
|
||||
createdAt: string;
|
||||
description: string;
|
||||
enabled: boolean;
|
||||
filters: WorkflowFilterResponseDto[];
|
||||
id: string;
|
||||
name: string | null;
|
||||
ownerId: string;
|
||||
triggerType: TriggerType;
|
||||
};
|
||||
export type WorkflowActionItemDto = {
|
||||
actionConfig?: object;
|
||||
actionId: string;
|
||||
};
|
||||
export type WorkflowFilterItemDto = {
|
||||
filterConfig?: object;
|
||||
filterId: string;
|
||||
};
|
||||
export type WorkflowCreateDto = {
|
||||
actions: WorkflowActionItemDto[];
|
||||
description?: string;
|
||||
enabled?: boolean;
|
||||
filters: WorkflowFilterItemDto[];
|
||||
name: string;
|
||||
triggerType: PluginTriggerType;
|
||||
};
|
||||
export type WorkflowUpdateDto = {
|
||||
actions?: WorkflowActionItemDto[];
|
||||
description?: string;
|
||||
enabled?: boolean;
|
||||
filters?: WorkflowFilterItemDto[];
|
||||
name?: string;
|
||||
};
|
||||
/**
|
||||
* List all activities
|
||||
*/
|
||||
@@ -3510,6 +3590,30 @@ export function getPersonThumbnail({ id }: {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* List all plugins
|
||||
*/
|
||||
export function getPlugins(opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchJson<{
|
||||
status: 200;
|
||||
data: PluginResponseDto[];
|
||||
}>("/plugins", {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* Retrieve a plugin
|
||||
*/
|
||||
export function getPlugin({ id }: {
|
||||
id: string;
|
||||
}, opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchJson<{
|
||||
status: 200;
|
||||
data: PluginResponseDto;
|
||||
}>(`/plugins/${encodeURIComponent(id)}`, {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* Retrieve assets by city
|
||||
*/
|
||||
@@ -4824,6 +4928,72 @@ export function getUniqueOriginalPaths(opts?: Oazapfts.RequestOpts) {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* List all workflows
|
||||
*/
|
||||
export function getWorkflows(opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchJson<{
|
||||
status: 200;
|
||||
data: WorkflowResponseDto[];
|
||||
}>("/workflows", {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* Create a workflow
|
||||
*/
|
||||
export function createWorkflow({ workflowCreateDto }: {
|
||||
workflowCreateDto: WorkflowCreateDto;
|
||||
}, opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchJson<{
|
||||
status: 201;
|
||||
data: WorkflowResponseDto;
|
||||
}>("/workflows", oazapfts.json({
|
||||
...opts,
|
||||
method: "POST",
|
||||
body: workflowCreateDto
|
||||
})));
|
||||
}
|
||||
/**
|
||||
* Delete a workflow
|
||||
*/
|
||||
export function deleteWorkflow({ id }: {
|
||||
id: string;
|
||||
}, opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchText(`/workflows/${encodeURIComponent(id)}`, {
|
||||
...opts,
|
||||
method: "DELETE"
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* Retrieve a workflow
|
||||
*/
|
||||
export function getWorkflow({ id }: {
|
||||
id: string;
|
||||
}, opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchJson<{
|
||||
status: 200;
|
||||
data: WorkflowResponseDto;
|
||||
}>(`/workflows/${encodeURIComponent(id)}`, {
|
||||
...opts
|
||||
}));
|
||||
}
|
||||
/**
|
||||
* Update a workflow
|
||||
*/
|
||||
export function updateWorkflow({ id, workflowUpdateDto }: {
|
||||
id: string;
|
||||
workflowUpdateDto: WorkflowUpdateDto;
|
||||
}, opts?: Oazapfts.RequestOpts) {
|
||||
return oazapfts.ok(oazapfts.fetchJson<{
|
||||
status: 200;
|
||||
data: WorkflowResponseDto;
|
||||
}>(`/workflows/${encodeURIComponent(id)}`, oazapfts.json({
|
||||
...opts,
|
||||
method: "PUT",
|
||||
body: workflowUpdateDto
|
||||
})));
|
||||
}
|
||||
export enum ReactionLevel {
|
||||
Album = "album",
|
||||
Asset = "asset"
|
||||
@@ -4976,6 +5146,10 @@ export enum Permission {
|
||||
PinCodeCreate = "pinCode.create",
|
||||
PinCodeUpdate = "pinCode.update",
|
||||
PinCodeDelete = "pinCode.delete",
|
||||
PluginCreate = "plugin.create",
|
||||
PluginRead = "plugin.read",
|
||||
PluginUpdate = "plugin.update",
|
||||
PluginDelete = "plugin.delete",
|
||||
ServerAbout = "server.about",
|
||||
ServerApkLinks = "server.apkLinks",
|
||||
ServerStorage = "server.storage",
|
||||
@@ -5025,6 +5199,10 @@ export enum Permission {
|
||||
UserProfileImageRead = "userProfileImage.read",
|
||||
UserProfileImageUpdate = "userProfileImage.update",
|
||||
UserProfileImageDelete = "userProfileImage.delete",
|
||||
WorkflowCreate = "workflow.create",
|
||||
WorkflowRead = "workflow.read",
|
||||
WorkflowUpdate = "workflow.update",
|
||||
WorkflowDelete = "workflow.delete",
|
||||
AdminUserCreate = "adminUser.create",
|
||||
AdminUserRead = "adminUser.read",
|
||||
AdminUserUpdate = "adminUser.update",
|
||||
@@ -5083,7 +5261,8 @@ export enum QueueName {
|
||||
Library = "library",
|
||||
Notifications = "notifications",
|
||||
BackupDatabase = "backupDatabase",
|
||||
Ocr = "ocr"
|
||||
Ocr = "ocr",
|
||||
Workflow = "workflow"
|
||||
}
|
||||
export enum QueueCommand {
|
||||
Start = "start",
|
||||
@@ -5104,6 +5283,11 @@ export enum PartnerDirection {
|
||||
SharedBy = "shared-by",
|
||||
SharedWith = "shared-with"
|
||||
}
|
||||
export enum PluginContext {
|
||||
Asset = "asset",
|
||||
Album = "album",
|
||||
Person = "person"
|
||||
}
|
||||
export enum SearchSuggestionType {
|
||||
Country = "country",
|
||||
State = "state",
|
||||
@@ -5255,3 +5439,11 @@ export enum OAuthTokenEndpointAuthMethod {
|
||||
ClientSecretPost = "client_secret_post",
|
||||
ClientSecretBasic = "client_secret_basic"
|
||||
}
|
||||
export enum TriggerType {
|
||||
AssetCreate = "AssetCreate",
|
||||
PersonRecognized = "PersonRecognized"
|
||||
}
|
||||
export enum PluginTriggerType {
|
||||
AssetCreate = "AssetCreate",
|
||||
PersonRecognized = "PersonRecognized"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user