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,
|
ActionResult,
|
||||||
BackupOptions,
|
BackupOptions,
|
||||||
DeepPartial,
|
DeepPartial,
|
||||||
|
MaybePromise,
|
||||||
} from "./types"
|
} from "./types"
|
||||||
import * as patterns from "./util/patterns"
|
import * as patterns from "./util/patterns"
|
||||||
import { Utils } from "./util/utils"
|
import { Utils } from "./util/utils"
|
||||||
@@ -91,7 +92,31 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
|||||||
utils: Utils<Store>
|
utils: Utils<Store>
|
||||||
input: Type
|
input: Type
|
||||||
}) => Promise<ActionResult>,
|
}) => 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: {
|
HealthCheck: {
|
||||||
of: healthCheck,
|
of: healthCheck,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,12 @@ import { ActionMetadata, ActionResult, Effects, ExportedAction } from "../types"
|
|||||||
import { createUtils } from "../util"
|
import { createUtils } from "../util"
|
||||||
import { Utils } from "../util/utils"
|
import { Utils } from "../util/utils"
|
||||||
|
|
||||||
|
export type MaybeFn<Store, Value> =
|
||||||
|
| Value
|
||||||
|
| ((options: {
|
||||||
|
effects: Effects
|
||||||
|
utils: Utils<Store>
|
||||||
|
}) => Promise<Value> | Value)
|
||||||
export class CreatedAction<
|
export class CreatedAction<
|
||||||
Store,
|
Store,
|
||||||
ConfigType extends
|
ConfigType extends
|
||||||
@@ -12,7 +18,7 @@ export class CreatedAction<
|
|||||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||||
> {
|
> {
|
||||||
private constructor(
|
private constructor(
|
||||||
public readonly myMetaData: Omit<ActionMetadata, "input">,
|
public readonly myMetaData: MaybeFn<Store, Omit<ActionMetadata, "input">>,
|
||||||
readonly fn: (options: {
|
readonly fn: (options: {
|
||||||
effects: Effects
|
effects: Effects
|
||||||
utils: Utils<Store>
|
utils: Utils<Store>
|
||||||
@@ -30,20 +36,18 @@ export class CreatedAction<
|
|||||||
| Config<any, never>,
|
| Config<any, never>,
|
||||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||||
>(
|
>(
|
||||||
metaData: Omit<ActionMetadata, "input"> & {
|
metaData: MaybeFn<Store, Omit<ActionMetadata, "input">>,
|
||||||
input: Config<Type, Store> | Config<Type, never>
|
|
||||||
},
|
|
||||||
fn: (options: {
|
fn: (options: {
|
||||||
effects: Effects
|
effects: Effects
|
||||||
utils: Utils<Store>
|
utils: Utils<Store>
|
||||||
input: Type
|
input: Type
|
||||||
}) => Promise<ActionResult>,
|
}) => Promise<ActionResult>,
|
||||||
|
inputConfig: Config<Type, Store> | Config<Type, never>,
|
||||||
) {
|
) {
|
||||||
const { input, ...rest } = metaData
|
|
||||||
return new CreatedAction<Store, ConfigType, Type>(
|
return new CreatedAction<Store, ConfigType, Type>(
|
||||||
rest,
|
metaData,
|
||||||
fn,
|
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: {
|
async ActionMetadata(options: {
|
||||||
effects: Effects
|
effects: Effects
|
||||||
utils: Utils<Store>
|
utils: Utils<Store>
|
||||||
}): Promise<ActionMetadata> {
|
}): Promise<ActionMetadata> {
|
||||||
return {
|
return {
|
||||||
...this.myMetaData,
|
...(await this.metaData(options)),
|
||||||
input: await this.input.build(options),
|
input: await this.input.build(options),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,34 @@
|
|||||||
import { Effects, ExpectedExports } from "../types"
|
import { Effects, ExpectedExports } from "../types"
|
||||||
import { createUtils } from "../util"
|
import { createUtils } from "../util"
|
||||||
import { once } from "../util/once"
|
import { once } from "../util/once"
|
||||||
|
import { Utils } from "../util/utils"
|
||||||
import { CreatedAction } from "./createAction"
|
import { CreatedAction } from "./createAction"
|
||||||
|
|
||||||
export function setupActions<Store>(
|
export function setupActions<Store>(
|
||||||
...createdActions: CreatedAction<Store, any>[]
|
...createdActions: CreatedAction<Store, any>[]
|
||||||
) {
|
) {
|
||||||
const myActions = once(() => {
|
const myActions = async (options: {
|
||||||
|
effects: Effects
|
||||||
|
utils: Utils<Store>
|
||||||
|
}) => {
|
||||||
const actions: Record<string, CreatedAction<Store, any>> = {}
|
const actions: Record<string, CreatedAction<Store, any>> = {}
|
||||||
for (const action of createdActions) {
|
for (const action of createdActions) {
|
||||||
actions[action.myMetaData.id] = action
|
const actionMetadata = await action.metaData(options)
|
||||||
|
actions[actionMetadata.id] = action
|
||||||
}
|
}
|
||||||
return actions
|
return actions
|
||||||
})
|
}
|
||||||
const answer: {
|
const answer: {
|
||||||
actions: ExpectedExports.actions
|
actions: ExpectedExports.actions
|
||||||
actionsMetadata: ExpectedExports.actionsMetadata
|
actionsMetadata: ExpectedExports.actionsMetadata
|
||||||
} = {
|
} = {
|
||||||
get actions() {
|
actions(options: { effects: Effects }) {
|
||||||
return myActions()
|
const utils = createUtils<Store>(options.effects)
|
||||||
|
|
||||||
|
return myActions({
|
||||||
|
...options,
|
||||||
|
utils,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
async actionsMetadata({ effects }: { effects: Effects }) {
|
async actionsMetadata({ effects }: { effects: Effects }) {
|
||||||
const utils = createUtils<Store>(effects)
|
const utils = createUtils<Store>(effects)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export type ExportedAction = (options: {
|
|||||||
effects: Effects
|
effects: Effects
|
||||||
input?: Record<string, unknown>
|
input?: Record<string, unknown>
|
||||||
}) => Promise<ActionResult>
|
}) => Promise<ActionResult>
|
||||||
|
export type MaybePromise<A> = A | Promise<A>
|
||||||
export namespace ExpectedExports {
|
export namespace ExpectedExports {
|
||||||
version: 1
|
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. */
|
/** 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
|
* 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.
|
* 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]: {
|
[id: string]: {
|
||||||
run: ExportedAction
|
run: ExportedAction
|
||||||
getConfig: (options: { effects: Effects }) => Promise<InputSpec>
|
getConfig: (options: { effects: Effects }) => Promise<InputSpec>
|
||||||
}
|
}
|
||||||
}
|
}>
|
||||||
|
|
||||||
export type actionsMetadata = (options: {
|
export type actionsMetadata = (options: {
|
||||||
effects: Effects
|
effects: Effects
|
||||||
@@ -160,7 +160,7 @@ export type ActionMetadata = {
|
|||||||
description: string
|
description: string
|
||||||
id: string
|
id: string
|
||||||
input: InputSpec
|
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
|
* 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