mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-26 02:11:56 +00:00
feat: Create a dynamic action
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
ActionResult,
|
||||
BackupOptions,
|
||||
DeepPartial,
|
||||
MaybePromise,
|
||||
} from "./types"
|
||||
import * as patterns from "./util/patterns"
|
||||
import { Utils } from "./util/utils"
|
||||
@@ -91,7 +92,31 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
utils: Utils<Store>
|
||||
input: Type
|
||||
}) => Promise<ActionResult>,
|
||||
) => createAction<Store, ConfigType, Type>(metaData, fn),
|
||||
) => {
|
||||
const { input, ...rest } = metaData
|
||||
return createAction<Store, ConfigType, Type>(rest, fn, input)
|
||||
},
|
||||
createDynamicAction: <
|
||||
ConfigType extends
|
||||
| Record<string, any>
|
||||
| Config<any, any>
|
||||
| Config<any, never>,
|
||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||
>(
|
||||
metaData: (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
}) => MaybePromise<Omit<ActionMetadata, "input">>,
|
||||
fn: (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
input: Type
|
||||
}) => Promise<ActionResult>,
|
||||
input: Config<Type, Store> | Config<Type, never>,
|
||||
) => {
|
||||
return createAction<Store, ConfigType, Type>(metaData, fn, input)
|
||||
},
|
||||
|
||||
HealthCheck: {
|
||||
of: healthCheck,
|
||||
},
|
||||
|
||||
@@ -3,6 +3,12 @@ import { ActionMetadata, ActionResult, Effects, ExportedAction } from "../types"
|
||||
import { createUtils } from "../util"
|
||||
import { Utils } from "../util/utils"
|
||||
|
||||
export type MaybeFn<Store, Value> =
|
||||
| Value
|
||||
| ((options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
}) => Promise<Value> | Value)
|
||||
export class CreatedAction<
|
||||
Store,
|
||||
ConfigType extends
|
||||
@@ -12,7 +18,7 @@ export class CreatedAction<
|
||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||
> {
|
||||
private constructor(
|
||||
public readonly myMetaData: Omit<ActionMetadata, "input">,
|
||||
public readonly myMetaData: MaybeFn<Store, Omit<ActionMetadata, "input">>,
|
||||
readonly fn: (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
@@ -30,20 +36,18 @@ export class CreatedAction<
|
||||
| Config<any, never>,
|
||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||
>(
|
||||
metaData: Omit<ActionMetadata, "input"> & {
|
||||
input: Config<Type, Store> | Config<Type, never>
|
||||
},
|
||||
metaData: MaybeFn<Store, Omit<ActionMetadata, "input">>,
|
||||
fn: (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
input: Type
|
||||
}) => Promise<ActionResult>,
|
||||
inputConfig: Config<Type, Store> | Config<Type, never>,
|
||||
) {
|
||||
const { input, ...rest } = metaData
|
||||
return new CreatedAction<Store, ConfigType, Type>(
|
||||
rest,
|
||||
metaData,
|
||||
fn,
|
||||
input as Config<Type, Store>,
|
||||
inputConfig as Config<Type, Store>,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -63,12 +67,18 @@ export class CreatedAction<
|
||||
})
|
||||
}
|
||||
|
||||
async metaData(options: { effects: Effects; utils: Utils<Store> }) {
|
||||
if (this.myMetaData instanceof Function)
|
||||
return await this.myMetaData(options)
|
||||
return this.myMetaData
|
||||
}
|
||||
|
||||
async ActionMetadata(options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
}): Promise<ActionMetadata> {
|
||||
return {
|
||||
...this.myMetaData,
|
||||
...(await this.metaData(options)),
|
||||
input: await this.input.build(options),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,34 @@
|
||||
import { Effects, ExpectedExports } from "../types"
|
||||
import { createUtils } from "../util"
|
||||
import { once } from "../util/once"
|
||||
import { Utils } from "../util/utils"
|
||||
import { CreatedAction } from "./createAction"
|
||||
|
||||
export function setupActions<Store>(
|
||||
...createdActions: CreatedAction<Store, any>[]
|
||||
) {
|
||||
const myActions = once(() => {
|
||||
const myActions = async (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
}) => {
|
||||
const actions: Record<string, CreatedAction<Store, any>> = {}
|
||||
for (const action of createdActions) {
|
||||
actions[action.myMetaData.id] = action
|
||||
const actionMetadata = await action.metaData(options)
|
||||
actions[actionMetadata.id] = action
|
||||
}
|
||||
return actions
|
||||
})
|
||||
}
|
||||
const answer: {
|
||||
actions: ExpectedExports.actions
|
||||
actionsMetadata: ExpectedExports.actionsMetadata
|
||||
} = {
|
||||
get actions() {
|
||||
return myActions()
|
||||
actions(options: { effects: Effects }) {
|
||||
const utils = createUtils<Store>(options.effects)
|
||||
|
||||
return myActions({
|
||||
...options,
|
||||
utils,
|
||||
})
|
||||
},
|
||||
async actionsMetadata({ effects }: { effects: Effects }) {
|
||||
const utils = createUtils<Store>(effects)
|
||||
|
||||
@@ -7,7 +7,7 @@ export type ExportedAction = (options: {
|
||||
effects: Effects
|
||||
input?: Record<string, unknown>
|
||||
}) => Promise<ActionResult>
|
||||
|
||||
export type MaybePromise<A> = A | Promise<A>
|
||||
export namespace ExpectedExports {
|
||||
version: 1
|
||||
/** Set configuration is called after we have modified and saved the configuration in the start9 ui. Use this to make a file for the docker to read from for configuration. */
|
||||
@@ -39,12 +39,12 @@ export namespace ExpectedExports {
|
||||
* One old use case is to add a action where we add a file, that will then be run during the
|
||||
* service starting, and that file would indicate that it would rescan all the data.
|
||||
*/
|
||||
export type actions = {
|
||||
export type actions = (options: { effects: Effects }) => MaybePromise<{
|
||||
[id: string]: {
|
||||
run: ExportedAction
|
||||
getConfig: (options: { effects: Effects }) => Promise<InputSpec>
|
||||
}
|
||||
}
|
||||
}>
|
||||
|
||||
export type actionsMetadata = (options: {
|
||||
effects: Effects
|
||||
@@ -160,7 +160,7 @@ export type ActionMetadata = {
|
||||
description: string
|
||||
id: string
|
||||
input: InputSpec
|
||||
allowedStatuses: "only-running" | "only-stopped" | "any"
|
||||
allowedStatuses: "only-running" | "only-stopped" | "any" | "disabled"
|
||||
/**
|
||||
* So the ordering of the actions is by alphabetical order of the group, then followed by the alphabetical of the actions
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user