From 96bc73e47d2f3b9c370694cf8653f3621e80a4c8 Mon Sep 17 00:00:00 2001 From: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:38:40 +0800 Subject: [PATCH] tweaks --- .../deployments/detail/access-tab.tsx | 3 +- .../deployments/hooks/use-source-apps.ts | 5 +- web/features/deployments/store.ts | 349 +---------------- web/features/deployments/store/actions.ts | 354 ++++++++++++++++++ .../deployments/store/initial-state.ts | 41 ++ web/features/deployments/store/selectors.ts | 11 + 6 files changed, 421 insertions(+), 342 deletions(-) create mode 100644 web/features/deployments/store/actions.ts create mode 100644 web/features/deployments/store/initial-state.ts create mode 100644 web/features/deployments/store/selectors.ts diff --git a/web/features/deployments/detail/access-tab.tsx b/web/features/deployments/detail/access-tab.tsx index a30a5da614..420b904629 100644 --- a/web/features/deployments/detail/access-tab.tsx +++ b/web/features/deployments/detail/access-tab.tsx @@ -6,6 +6,7 @@ import type { } from '@/contract/console/deployments' import { useMemo } from 'react' import { useDeploymentAppData, useDeploymentsStore } from '../store' +import { deploymentsSelectors } from '../store/selectors' import { deployedRows, } from '../utils' @@ -28,7 +29,7 @@ type AccessTabProps = { const AccessTab: FC = ({ instanceId: appId }) => { const appData = useDeploymentAppData(appId) - const createdApiToken = useDeploymentsStore(state => state.createdApiToken) + const createdApiToken = useDeploymentsStore(deploymentsSelectors.createdApiToken) const clearCreatedApiToken = useDeploymentsStore(state => state.clearCreatedApiToken) const generateApiKey = useDeploymentsStore(state => state.generateApiKey) const revokeApiKey = useDeploymentsStore(state => state.revokeApiKey) diff --git a/web/features/deployments/hooks/use-source-apps.ts b/web/features/deployments/hooks/use-source-apps.ts index d937d4402f..a0d286188a 100644 --- a/web/features/deployments/hooks/use-source-apps.ts +++ b/web/features/deployments/hooks/use-source-apps.ts @@ -5,6 +5,7 @@ import { useQuery } from '@tanstack/react-query' import { useMemo } from 'react' import { consoleQuery } from '@/service/client' import { useDeploymentsStore } from '../store' +import { deploymentsSelectors } from '../store/selectors' const MAX_SOURCE_APPS = 100 @@ -17,8 +18,8 @@ type UseSourceAppsOptions = { export function useSourceApps(options: UseSourceAppsOptions = {}) { const { enabled = true, environmentId, keyword, notDeployed } = options - const instancesById = useDeploymentsStore(state => state.instancesById) - const listRefreshToken = useDeploymentsStore(state => state.listRefreshToken) + const instancesById = useDeploymentsStore(deploymentsSelectors.instancesById) + const listRefreshToken = useDeploymentsStore(deploymentsSelectors.listRefreshToken) const query = useMemo(() => ({ pageNumber: 1, diff --git a/web/features/deployments/store.ts b/web/features/deployments/store.ts index 134667c887..03e9f07401 100644 --- a/web/features/deployments/store.ts +++ b/web/features/deployments/store.ts @@ -1,348 +1,19 @@ -import type { DeploymentAppData, ListAppDeploymentsQuery } from './data' -import type { AppInfo } from './types' -import type { AccessSubject, APIToken, ConsoleReleaseSummary, ListAppDeploymentsReply } from '@/contract/console/deployments' +import type { DeploymentsStore } from './store/actions' + import { create } from 'zustand' -import { - cancelDeployment, - createApiKey, - createAppInstance, - createDeployment, - deleteApiKey, - deleteAppInstance, - fetchDeploymentAppData, - listAppDeployments, - patchAccessChannel, - patchDeveloperAPI, - refreshDeploymentAppData, - refreshDeploymentAppDataWhenReady, - toAppInfoFromOverview, - toAppInfoFromSummary, - undeployEnvironment, - updateAppInstance, - updateEnvironmentAccessPolicy, - waitForAppInstanceInDeploymentList, -} from './data' +import { createDeploymentsActions } from './store/actions' +import { initialDeploymentsState } from './store/initial-state' +import { deploymentsSelectors } from './store/selectors' -export type StartDeployParams = { - appId: string - environmentId: string - releaseId?: string - releaseNote?: string -} - -type OpenDeployDrawerParams = { - appId: string - environmentId?: string - releaseId?: string -} - -type OpenRollbackParams = { - appId: string - environmentId: string - targetReleaseId: string - deploymentId?: string -} - -type CreatedApiToken = Pick & { - appId: string - token: string -} - -export type CreateInstanceParams = { - sourceAppId: string - name: string - description?: string -} - -export type CreateInstanceResult = { - appInstanceId: string - initialRelease?: ConsoleReleaseSummary -} - -type DeploymentsState = { - instancesById: Record - appData: Record - listRefreshToken: number - createdApiToken?: CreatedApiToken - - deployDrawer: { - open: boolean - appId?: string - environmentId?: string - releaseId?: string - } - rollbackModal: { - open: boolean - appId?: string - environmentId?: string - deploymentId?: string - targetReleaseId?: string - } - createInstanceModal: { open: boolean } - - openDeployDrawer: (params: OpenDeployDrawerParams) => void - closeDeployDrawer: () => void - - openRollbackModal: (params: OpenRollbackParams) => void - closeRollbackModal: () => void - - openCreateInstanceModal: () => void - closeCreateInstanceModal: () => void - - upsertInstances: (apps: AppInfo[]) => void - applyAppData: (data: DeploymentAppData) => void - bumpDeploymentListRefresh: () => void - fetchSourceApps: (query: ListAppDeploymentsQuery) => Promise - fetchAppData: (appId: string) => Promise - refreshAppData: (appId: string) => Promise - - createInstance: (params: CreateInstanceParams) => Promise - updateInstance: (appId: string, patch: Pick) => Promise - switchSourceApp: (appId: string, nextAppId: string) => void - deleteInstance: (appId: string) => Promise - - startDeploy: (params: StartDeployParams) => Promise - retryDeploy: (appId: string, environmentId: string, targetReleaseId: string) => Promise - rollbackDeployment: (appId: string, environmentId: string, targetReleaseId: string) => Promise - undeployDeployment: (appId: string, environmentId: string, deploymentId?: string, isDeploying?: boolean) => Promise - - generateApiKey: (appId: string, environmentId: string) => Promise - revokeApiKey: (appId: string, environmentId: string, apiKeyId: string) => Promise - clearCreatedApiToken: () => void - toggleAccessChannel: (appId: string, channel: string, enabled: boolean, expectedVersion: number) => Promise - setEnvironmentAccessPolicy: ( - appId: string, - environmentId: string, - channel: string, - enabled: boolean, - accessMode: string, - subjects: AccessSubject[], - expectedVersion: number, - ) => Promise -} - -export const useDeploymentsStore = create((set, get) => ({ - instancesById: {}, - appData: {}, - listRefreshToken: 0, - createdApiToken: undefined, - - deployDrawer: { open: false }, - rollbackModal: { open: false }, - createInstanceModal: { open: false }, - - openDeployDrawer: params => set({ - deployDrawer: { - open: true, - appId: params.appId, - environmentId: params.environmentId, - releaseId: params.releaseId, - }, - }), - closeDeployDrawer: () => set({ deployDrawer: { open: false } }), - - openRollbackModal: ({ appId, environmentId, deploymentId, targetReleaseId }) => set({ - rollbackModal: { open: true, appId, environmentId, deploymentId, targetReleaseId }, - }), - closeRollbackModal: () => set({ rollbackModal: { open: false } }), - - openCreateInstanceModal: () => set({ createInstanceModal: { open: true } }), - closeCreateInstanceModal: () => set({ createInstanceModal: { open: false } }), - - upsertInstances: apps => set(state => ({ - instancesById: apps.reduce((next, app) => { - next[app.id] = { - ...next[app.id], - ...app, - } - return next - }, { ...state.instancesById }), - })), - - applyAppData: data => set(state => ({ - appData: { - ...state.appData, - [data.appId]: data, - }, - })), - - bumpDeploymentListRefresh: () => set(state => ({ - listRefreshToken: state.listRefreshToken + 1, - })), - - fetchSourceApps: async (query) => { - const response = await listAppDeployments(query) - const apps = response.data - ?.map(toAppInfoFromSummary) - .filter((app): app is AppInfo => Boolean(app)) ?? [] - get().upsertInstances(apps) - return response - }, - - fetchAppData: async (appId) => { - const data = await fetchDeploymentAppData(appId) - get().applyAppData(data) - const app = toAppInfoFromOverview(data.overview.instance) - if (app) - get().upsertInstances([app]) - return data - }, - - refreshAppData: async (appId) => { - const data = await refreshDeploymentAppData(appId) - get().applyAppData(data) - const app = toAppInfoFromOverview(data.overview.instance) - if (app) - get().upsertInstances([app]) - }, - - createInstance: async ({ sourceAppId, name, description }) => { - const response = await createAppInstance({ sourceAppId, name, description }) - if (!response.appInstanceId) - throw new Error('Create app instance did not return an appInstanceId.') - set({ createInstanceModal: { open: false } }) - await Promise.allSettled([ - refreshDeploymentAppDataWhenReady(response.appInstanceId) - .then((data) => { - get().applyAppData(data) - const app = toAppInfoFromOverview(data.overview.instance) - if (app) - get().upsertInstances([app]) - }), - waitForAppInstanceInDeploymentList(response.appInstanceId).then((list) => { - const apps = list?.data - ?.map(toAppInfoFromSummary) - .filter((app): app is AppInfo => Boolean(app)) ?? [] - get().upsertInstances(apps) - }), - ]) - get().bumpDeploymentListRefresh() - return { - appInstanceId: response.appInstanceId, - initialRelease: response.initialRelease, - } - }, - - updateInstance: async (appId, patch) => { - await updateAppInstance(appId, { - name: patch.name, - description: patch.description, - }) - await get().refreshAppData(appId) - get().bumpDeploymentListRefresh() - set(state => ({ - instancesById: { - ...state.instancesById, - [appId]: { - ...state.instancesById[appId], - id: appId, - name: patch.name, - mode: state.instancesById[appId]?.mode ?? 'workflow', - description: patch.description, - }, - }, - })) - }, - - switchSourceApp: () => undefined, - - deleteInstance: async (appId) => { - await deleteAppInstance(appId) - set((state) => { - const { [appId]: _removed, ...appData } = state.appData - const { [appId]: _removedInstance, ...instancesById } = state.instancesById - return { - instancesById, - appData, - } - }) - get().bumpDeploymentListRefresh() - }, - - startDeploy: async ({ appId, environmentId, releaseId, releaseNote }) => { - set({ deployDrawer: { open: false } }) - await createDeployment({ appId, environmentId, releaseId, releaseNote }) - await get().refreshAppData(appId) - get().bumpDeploymentListRefresh() - }, - - retryDeploy: async (appId, environmentId, targetReleaseId) => { - await createDeployment({ appId, environmentId, releaseId: targetReleaseId }) - await get().refreshAppData(appId) - get().bumpDeploymentListRefresh() - }, - - rollbackDeployment: async (appId, environmentId, targetReleaseId) => { - set({ rollbackModal: { open: false } }) - await createDeployment({ appId, environmentId, releaseId: targetReleaseId }) - await get().refreshAppData(appId) - get().bumpDeploymentListRefresh() - }, - - undeployDeployment: async (appId, _environmentId, runtimeInstanceId, isDeploying) => { - if (!runtimeInstanceId) - return - if (isDeploying) - await cancelDeployment(appId, runtimeInstanceId) - else - await undeployEnvironment(appId, runtimeInstanceId) - await get().refreshAppData(appId) - get().bumpDeploymentListRefresh() - }, - - generateApiKey: async (appId, environmentId) => { - const appData = get().appData[appId] - const existingCount = appData?.accessConfig.developerApi?.apiKeys?.filter(key => - (key.environmentId ?? key.environment?.id) === environmentId, - ).length ?? 0 - const environmentName = appData - ?.environmentDeployments - .data - ?.find(row => row.environment?.id === environmentId) - ?.environment - ?.name ?? 'env' - const label = `${environmentName}-key-${String(existingCount + 1).padStart(3, '0')}` - const response = await createApiKey(appId, environmentId, label) - await get().refreshAppData(appId) - if (response.apiToken?.token) { - set({ - createdApiToken: { - id: response.apiToken.id, - appId, - environmentId: response.apiToken.environmentId ?? response.apiToken.environment?.id, - maskedPrefix: response.apiToken.maskedPrefix ?? response.apiToken.maskedKey, - name: response.apiToken.name || label, - token: response.apiToken.token, - }, - }) - } - }, - - revokeApiKey: async (appId, _environmentId, apiKeyId) => { - await deleteApiKey(appId, apiKeyId) - await get().refreshAppData(appId) - }, - - clearCreatedApiToken: () => set({ createdApiToken: undefined }), - - toggleAccessChannel: async (appId, channel, enabled) => { - if (channel === 'api') - await patchDeveloperAPI(appId, enabled) - else - await patchAccessChannel(appId, enabled) - await get().refreshAppData(appId) - }, - - setEnvironmentAccessPolicy: async (appId, environmentId, _channel, _enabled, accessMode, subjects) => { - await updateEnvironmentAccessPolicy(appId, environmentId, accessMode, subjects) - await get().refreshAppData(appId) - }, +export const useDeploymentsStore = create()((...parameters) => ({ + ...initialDeploymentsState, + ...createDeploymentsActions(...parameters), })) export const useDeploymentInstance = (appId?: string) => { - return useDeploymentsStore(state => appId ? state.instancesById[appId] : undefined) + return useDeploymentsStore(deploymentsSelectors.instance(appId)) } export const useDeploymentAppData = (appId?: string) => { - return useDeploymentsStore(state => appId ? state.appData[appId] : undefined) + return useDeploymentsStore(deploymentsSelectors.appData(appId)) } diff --git a/web/features/deployments/store/actions.ts b/web/features/deployments/store/actions.ts new file mode 100644 index 0000000000..8778cf7b91 --- /dev/null +++ b/web/features/deployments/store/actions.ts @@ -0,0 +1,354 @@ +import type { StateCreator } from 'zustand' +import type { + CreateInstanceParams, + DeploymentAppData, + ListAppDeploymentsQuery, +} from '../data' +import type { AppInfo } from '../types' +import type { DeploymentsState } from './initial-state' +import type { AccessSubject, ConsoleReleaseSummary, ListAppDeploymentsReply } from '@/contract/console/deployments' +import { + cancelDeployment, + createApiKey, + createAppInstance, + createDeployment, + deleteApiKey, + deleteAppInstance, + fetchDeploymentAppData, + listAppDeployments, + patchAccessChannel, + patchDeveloperAPI, + refreshDeploymentAppData, + refreshDeploymentAppDataWhenReady, + toAppInfoFromOverview, + toAppInfoFromSummary, + undeployEnvironment, + updateAppInstance, + updateEnvironmentAccessPolicy, + waitForAppInstanceInDeploymentList, +} from '../data' + +export type StartDeployParams = { + appId: string + environmentId: string + releaseId?: string + releaseNote?: string +} + +type OpenDeployDrawerParams = { + appId: string + environmentId?: string + releaseId?: string +} + +type OpenRollbackParams = { + appId: string + environmentId: string + targetReleaseId: string + deploymentId?: string +} + +export type CreateInstanceResult = { + appInstanceId: string + initialRelease?: ConsoleReleaseSummary +} + +export type DeploymentsAction = { + openDeployDrawer: (params: OpenDeployDrawerParams) => void + closeDeployDrawer: () => void + + openRollbackModal: (params: OpenRollbackParams) => void + closeRollbackModal: () => void + + openCreateInstanceModal: () => void + closeCreateInstanceModal: () => void + + upsertInstances: (apps: AppInfo[]) => void + applyAppData: (data: DeploymentAppData) => void + bumpDeploymentListRefresh: () => void + fetchSourceApps: (query: ListAppDeploymentsQuery) => Promise + fetchAppData: (appId: string) => Promise + refreshAppData: (appId: string) => Promise + + createInstance: (params: CreateInstanceParams) => Promise + updateInstance: (appId: string, patch: Pick) => Promise + switchSourceApp: (appId: string, nextAppId: string) => void + deleteInstance: (appId: string) => Promise + + startDeploy: (params: StartDeployParams) => Promise + retryDeploy: (appId: string, environmentId: string, targetReleaseId: string) => Promise + rollbackDeployment: (appId: string, environmentId: string, targetReleaseId: string) => Promise + undeployDeployment: (appId: string, environmentId: string, deploymentId?: string, isDeploying?: boolean) => Promise + + generateApiKey: (appId: string, environmentId: string) => Promise + revokeApiKey: (appId: string, environmentId: string, apiKeyId: string) => Promise + clearCreatedApiToken: () => void + toggleAccessChannel: (appId: string, channel: string, enabled: boolean, expectedVersion: number) => Promise + setEnvironmentAccessPolicy: ( + appId: string, + environmentId: string, + channel: string, + enabled: boolean, + accessMode: string, + subjects: AccessSubject[], + expectedVersion: number, + ) => Promise +} + +export type DeploymentsStore = DeploymentsState & DeploymentsAction + +type Setter = Parameters>[0] +type Getter = Parameters>[1] + +class DeploymentsActionImpl implements DeploymentsAction { + readonly #get: Getter + readonly #set: Setter + + constructor(set: Setter, get: Getter, _api?: unknown) { + void _api + this.#set = set + this.#get = get + } + + openDeployDrawer = (params: OpenDeployDrawerParams) => { + this.#set({ + deployDrawer: { + open: true, + appId: params.appId, + environmentId: params.environmentId, + releaseId: params.releaseId, + }, + }) + } + + closeDeployDrawer = () => { + this.#set({ deployDrawer: { open: false } }) + } + + openRollbackModal = ({ appId, environmentId, deploymentId, targetReleaseId }: OpenRollbackParams) => { + this.#set({ + rollbackModal: { open: true, appId, environmentId, deploymentId, targetReleaseId }, + }) + } + + closeRollbackModal = () => { + this.#set({ rollbackModal: { open: false } }) + } + + openCreateInstanceModal = () => { + this.#set({ createInstanceModal: { open: true } }) + } + + closeCreateInstanceModal = () => { + this.#set({ createInstanceModal: { open: false } }) + } + + upsertInstances = (apps: AppInfo[]) => { + this.#set(state => ({ + instancesById: apps.reduce((next, app) => { + next[app.id] = { + ...next[app.id], + ...app, + } + return next + }, { ...state.instancesById }), + })) + } + + applyAppData = (data: DeploymentAppData) => { + this.#set(state => ({ + appData: { + ...state.appData, + [data.appId]: data, + }, + })) + } + + bumpDeploymentListRefresh = () => { + this.#set(state => ({ + listRefreshToken: state.listRefreshToken + 1, + })) + } + + fetchSourceApps = async (query: ListAppDeploymentsQuery) => { + const response = await listAppDeployments(query) + const apps = response.data + ?.map(toAppInfoFromSummary) + .filter((app): app is AppInfo => Boolean(app)) ?? [] + this.upsertInstances(apps) + return response + } + + fetchAppData = async (appId: string) => { + const data = await fetchDeploymentAppData(appId) + this.applyAppData(data) + const app = toAppInfoFromOverview(data.overview.instance) + if (app) + this.upsertInstances([app]) + return data + } + + refreshAppData = async (appId: string) => { + const data = await refreshDeploymentAppData(appId) + this.applyAppData(data) + const app = toAppInfoFromOverview(data.overview.instance) + if (app) + this.upsertInstances([app]) + } + + createInstance = async ({ sourceAppId, name, description }: CreateInstanceParams) => { + const response = await createAppInstance({ sourceAppId, name, description }) + if (!response.appInstanceId) + throw new Error('Create app instance did not return an appInstanceId.') + + this.#set({ createInstanceModal: { open: false } }) + await Promise.allSettled([ + refreshDeploymentAppDataWhenReady(response.appInstanceId) + .then((data) => { + this.applyAppData(data) + const app = toAppInfoFromOverview(data.overview.instance) + if (app) + this.upsertInstances([app]) + }), + waitForAppInstanceInDeploymentList(response.appInstanceId).then((list) => { + const apps = list?.data + ?.map(toAppInfoFromSummary) + .filter((app): app is AppInfo => Boolean(app)) ?? [] + this.upsertInstances(apps) + }), + ]) + this.bumpDeploymentListRefresh() + return { + appInstanceId: response.appInstanceId, + initialRelease: response.initialRelease, + } + } + + updateInstance = async (appId: string, patch: Pick) => { + await updateAppInstance(appId, { + name: patch.name, + description: patch.description, + }) + await this.refreshAppData(appId) + this.bumpDeploymentListRefresh() + this.#set(state => ({ + instancesById: { + ...state.instancesById, + [appId]: { + ...state.instancesById[appId], + id: appId, + name: patch.name, + mode: state.instancesById[appId]?.mode ?? 'workflow', + description: patch.description, + }, + }, + })) + } + + switchSourceApp = () => undefined + + deleteInstance = async (appId: string) => { + await deleteAppInstance(appId) + this.#set((state) => { + const { [appId]: _removed, ...appData } = state.appData + const { [appId]: _removedInstance, ...instancesById } = state.instancesById + return { + instancesById, + appData, + } + }) + this.bumpDeploymentListRefresh() + } + + startDeploy = async ({ appId, environmentId, releaseId, releaseNote }: StartDeployParams) => { + this.#set({ deployDrawer: { open: false } }) + await createDeployment({ appId, environmentId, releaseId, releaseNote }) + await this.refreshAppData(appId) + this.bumpDeploymentListRefresh() + } + + retryDeploy = async (appId: string, environmentId: string, targetReleaseId: string) => { + await createDeployment({ appId, environmentId, releaseId: targetReleaseId }) + await this.refreshAppData(appId) + this.bumpDeploymentListRefresh() + } + + rollbackDeployment = async (appId: string, environmentId: string, targetReleaseId: string) => { + this.#set({ rollbackModal: { open: false } }) + await createDeployment({ appId, environmentId, releaseId: targetReleaseId }) + await this.refreshAppData(appId) + this.bumpDeploymentListRefresh() + } + + undeployDeployment = async (appId: string, _environmentId: string, runtimeInstanceId?: string, isDeploying?: boolean) => { + if (!runtimeInstanceId) + return + if (isDeploying) + await cancelDeployment(appId, runtimeInstanceId) + else + await undeployEnvironment(appId, runtimeInstanceId) + await this.refreshAppData(appId) + this.bumpDeploymentListRefresh() + } + + generateApiKey = async (appId: string, environmentId: string) => { + const appData = this.#get().appData[appId] + const existingCount = appData?.accessConfig.developerApi?.apiKeys?.filter(key => + (key.environmentId ?? key.environment?.id) === environmentId, + ).length ?? 0 + const environmentName = appData + ?.environmentDeployments + .data + ?.find(row => row.environment?.id === environmentId) + ?.environment + ?.name ?? 'env' + const label = `${environmentName}-key-${String(existingCount + 1).padStart(3, '0')}` + const response = await createApiKey(appId, environmentId, label) + await this.refreshAppData(appId) + if (response.apiToken?.token) { + this.#set({ + createdApiToken: { + id: response.apiToken.id, + appId, + environmentId: response.apiToken.environmentId ?? response.apiToken.environment?.id, + maskedPrefix: response.apiToken.maskedPrefix ?? response.apiToken.maskedKey, + name: response.apiToken.name || label, + token: response.apiToken.token, + }, + }) + } + } + + revokeApiKey = async (appId: string, _environmentId: string, apiKeyId: string) => { + await deleteApiKey(appId, apiKeyId) + await this.refreshAppData(appId) + } + + clearCreatedApiToken = () => { + this.#set({ createdApiToken: undefined }) + } + + toggleAccessChannel = async (appId: string, channel: string, enabled: boolean) => { + if (channel === 'api') + await patchDeveloperAPI(appId, enabled) + else + await patchAccessChannel(appId, enabled) + await this.refreshAppData(appId) + } + + setEnvironmentAccessPolicy = async ( + appId: string, + environmentId: string, + _channel: string, + _enabled: boolean, + accessMode: string, + subjects: AccessSubject[], + ) => { + await updateEnvironmentAccessPolicy(appId, environmentId, accessMode, subjects) + await this.refreshAppData(appId) + } +} + +export const createDeploymentsActions = ( + ...parameters: Parameters> +) => new DeploymentsActionImpl(...parameters) diff --git a/web/features/deployments/store/initial-state.ts b/web/features/deployments/store/initial-state.ts new file mode 100644 index 0000000000..0770072332 --- /dev/null +++ b/web/features/deployments/store/initial-state.ts @@ -0,0 +1,41 @@ +import type { DeploymentAppData } from '../data' +import type { AppInfo } from '../types' +import type { APIToken } from '@/contract/console/deployments' + +export type CreatedApiToken = Pick & { + appId: string + token: string +} + +export type DeploymentsState = { + instancesById: Record + appData: Record + listRefreshToken: number + createdApiToken?: CreatedApiToken + + deployDrawer: { + open: boolean + appId?: string + environmentId?: string + releaseId?: string + } + rollbackModal: { + open: boolean + appId?: string + environmentId?: string + deploymentId?: string + targetReleaseId?: string + } + createInstanceModal: { open: boolean } +} + +export const initialDeploymentsState: DeploymentsState = { + instancesById: {}, + appData: {}, + listRefreshToken: 0, + createdApiToken: undefined, + + deployDrawer: { open: false }, + rollbackModal: { open: false }, + createInstanceModal: { open: false }, +} diff --git a/web/features/deployments/store/selectors.ts b/web/features/deployments/store/selectors.ts new file mode 100644 index 0000000000..acdab1a800 --- /dev/null +++ b/web/features/deployments/store/selectors.ts @@ -0,0 +1,11 @@ +import type { DeploymentsStore } from './actions' + +export const deploymentsSelectors = { + appData: (appId?: string) => (state: DeploymentsStore) => + appId ? state.appData[appId] : undefined, + createdApiToken: (state: DeploymentsStore) => state.createdApiToken, + instance: (appId?: string) => (state: DeploymentsStore) => + appId ? state.instancesById[appId] : undefined, + instancesById: (state: DeploymentsStore) => state.instancesById, + listRefreshToken: (state: DeploymentsStore) => state.listRefreshToken, +}