Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/app/src/web/actions-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export type BrowserActionContext = {
readonly addTerminalSession: (session: ActiveTerminalSession) => void
readonly githubStatus: GithubAuthStatus | null
readonly portForwardInput: string
readonly projectTasksIncludeDefault: boolean
readonly reloadDashboard: () => void
readonly selectedProjectId: string | null
readonly selectedProjectKey: string | null
Expand All @@ -76,6 +77,7 @@ export type BrowserActionContext = {
readonly setProjectBrowser: Setter<ProjectBrowserSession | null>
readonly setProjectTaskLogs: Setter<string>
readonly setProjectTasks: Setter<ContainerTaskSnapshot | null>
readonly setProjectTasksIncludeDefault: Setter<boolean>
readonly setSelectedMenuIndex: Setter<number>
readonly setSelectedProject: Setter<ProjectDetails | null>
readonly setSelectedProjectId: Setter<string | null>
Expand Down
75 changes: 56 additions & 19 deletions packages/app/src/web/actions-tasks.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import type { Effect } from "effect"
import { Effect } from "effect"

import { type BrowserActionContext, requireSelectedProjectId, withBusy } from "./actions-shared.js"
import { type BrowserActionContext, confirmAction, requireSelectedProjectId, withBusy } from "./actions-shared.js"
import { loadProjectTaskLogs, loadProjectTasks, stopProjectTask } from "./api.js"
import type { ContainerTaskSnapshot } from "./api.js"

type LoadSelectedProjectTasksOptions = {
readonly includeDefault?: boolean
readonly silent?: boolean
}

const requireProjectIdForTasks = (context: BrowserActionContext): string | null => {
const projectId = requireSelectedProjectId(context)
if (projectId === null) {
Expand Down Expand Up @@ -66,16 +71,20 @@ const removeTaskFromSnapshot = (

const stopSelectedProjectTaskEffect = (
selected: SelectedProjectTaskAction
): Effect.Effect<void, string> => stopProjectTask(selected.projectId, selected.pid)
): Effect.Effect<ContainerTaskSnapshot, string> =>
stopProjectTask(selected.projectId, selected.pid).pipe(
Effect.flatMap(() => loadProjectTasks(selected.projectId, selected.context.projectTasksIncludeDefault))
)

const loadSelectedProjectTaskLogsEffect = (
selected: SelectedProjectTaskAction
): Effect.Effect<string, string> => loadProjectTaskLogs(selected.projectId, selected.pid, 200)

const applyStoppedProjectTask = (
selected: SelectedProjectTaskAction
selected: SelectedProjectTaskAction,
snapshot: ContainerTaskSnapshot
): void => {
selected.context.setProjectTasks((snapshot) => removeTaskFromSnapshot(snapshot, selected.pid))
selected.context.setProjectTasks(removeTaskFromSnapshot(snapshot, selected.pid))
selected.context.setMessage(`Sent SIGTERM to PID ${selected.pid}.`)
}

Expand All @@ -87,18 +96,16 @@ const applyLoadedProjectTaskLogs = (
selected.context.setMessage(`Loaded logs for PID ${selected.pid}.`)
}

export const loadSelectedProjectTasks = (
export const loadProjectTasksById = (
context: BrowserActionContext,
options?: { readonly silent?: boolean }
projectId: string,
options?: LoadSelectedProjectTasksOptions
) => {
const projectId = requireProjectIdForTasks(context)
if (projectId === null) {
return
}
const includeDefault = options?.includeDefault ?? context.projectTasksIncludeDefault
withBusy({
context,
effect: loadProjectTasks(projectId),
label: "Loading container tasks",
effect: loadProjectTasks(projectId, includeDefault),
label: includeDefault ? "Loading all container tasks" : "Loading container tasks",
onSuccess: (snapshot) => {
context.setProjectTasks(snapshot)
if (options?.silent !== true) {
Expand All @@ -108,16 +115,46 @@ export const loadSelectedProjectTasks = (
})
}

export const loadSelectedProjectTasks = (
context: BrowserActionContext,
options?: LoadSelectedProjectTasksOptions
) => {
const projectId = requireProjectIdForTasks(context)
if (projectId === null) {
return
}
loadProjectTasksById(context, projectId, options)
}

export const setSelectedProjectTasksIncludeDefault = (
context: BrowserActionContext,
includeDefault: boolean
) => {
context.setProjectTasksIncludeDefault(includeDefault)
context.setProjectTaskLogs("")
const projectId = requireProjectIdForTasks(context)
if (projectId === null) {
return
}
loadProjectTasksById(context, projectId, { includeDefault })
}

export const stopSelectedProjectTask = (
context: BrowserActionContext,
pid: number
) => {
withSelectedProjectTaskBusy({
context,
effect: stopSelectedProjectTaskEffect,
label: "Stopping container task",
onSuccess: applyStoppedProjectTask,
pid
withSelectedProjectTask(context, pid, (selected) => {
if (!confirmAction(`Stop PID ${selected.pid}?`)) {
return
}
withBusy({
context: selected.context,
effect: stopSelectedProjectTaskEffect(selected),
label: "Stopping container task",
onSuccess: (snapshot) => {
applyStoppedProjectTask(selected, snapshot)
}
})
})
}

Expand Down
8 changes: 7 additions & 1 deletion packages/app/src/web/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ export {
loadSelectedProjectInfo,
runApplyAllProjects
} from "./actions-projects.js"
export { loadSelectedProjectTaskLogs, loadSelectedProjectTasks, stopSelectedProjectTask } from "./actions-tasks.js"
export {
loadProjectTasksById,
loadSelectedProjectTaskLogs,
loadSelectedProjectTasks,
setSelectedProjectTasksIncludeDefault,
stopSelectedProjectTask
} from "./actions-tasks.js"

export const runBrowserMenuAction = (
currentMenu: BrowserMenuTag,
Expand Down
7 changes: 5 additions & 2 deletions packages/app/src/web/api-tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ import { Effect } from "effect"
import { requestJson, requestText } from "./api-http.js"
import { ContainerTaskSnapshotResponseSchema, OutputResponseSchema } from "./api-schema.js"

export const loadProjectTasks = (projectId: string) =>
const projectTasksPath = (projectId: string, includeDefault: boolean): string =>
`/projects/${encodeURIComponent(projectId)}/tasks${includeDefault ? "?includeDefault=true" : ""}`

export const loadProjectTasks = (projectId: string, includeDefault = false) =>
requestJson(
"GET",
`/projects/${encodeURIComponent(projectId)}/tasks`,
projectTasksPath(projectId, includeDefault),
ContainerTaskSnapshotResponseSchema
).pipe(
Effect.map((response) => response.snapshot)
Expand Down
4 changes: 4 additions & 0 deletions packages/app/src/web/app-ready-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type ActionContextArgs = {
readonly addTerminalSession: BrowserActionContext["addTerminalSession"]
readonly githubStatus: BrowserActionContext["githubStatus"]
readonly portForwardInput: BrowserActionContext["portForwardInput"]
readonly projectTasksIncludeDefault: BrowserActionContext["projectTasksIncludeDefault"]
readonly refreshDashboard: () => void
readonly selectedProjectId: string | null
readonly selectedProjectKey: string | null
Expand All @@ -33,6 +34,7 @@ type ActionContextArgs = {
readonly setProjectBrowser: BrowserActionContext["setProjectBrowser"]
readonly setProjectTaskLogs: BrowserActionContext["setProjectTaskLogs"]
readonly setProjectTasks: BrowserActionContext["setProjectTasks"]
readonly setProjectTasksIncludeDefault: BrowserActionContext["setProjectTasksIncludeDefault"]
readonly setSelectedMenuIndex: BrowserActionContext["setSelectedMenuIndex"]
readonly setSelectedProject: BrowserActionContext["setSelectedProject"]
readonly setSelectedProjectId: BrowserActionContext["setSelectedProjectId"]
Expand All @@ -47,6 +49,7 @@ export const createActionContext = (args: ActionContextArgs): BrowserActionConte
databaseLabelInput: args.databaseLabelInput,
githubStatus: args.githubStatus,
portForwardInput: args.portForwardInput,
projectTasksIncludeDefault: args.projectTasksIncludeDefault,
reloadDashboard: args.refreshDashboard,
selectedProjectId: args.selectedProjectId,
selectedProjectKey: args.selectedProjectKey,
Expand All @@ -69,6 +72,7 @@ export const createActionContext = (args: ActionContextArgs): BrowserActionConte
setProjectBrowser: args.setProjectBrowser,
setProjectTaskLogs: args.setProjectTaskLogs,
setProjectTasks: args.setProjectTasks,
setProjectTasksIncludeDefault: args.setProjectTasksIncludeDefault,
setSelectedMenuIndex: args.setSelectedMenuIndex,
setSelectedProject: args.setSelectedProject,
setSelectedProjectId: args.setSelectedProjectId
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/web/app-ready-controller-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const createReadyActionContext = (
databaseLabelInput: state.databaseLabelInput,
githubStatus: state.githubStatus,
portForwardInput: state.portForwardInput,
projectTasksIncludeDefault: state.projectTasksIncludeDefault,
refreshDashboard,
selectedProjectId: state.selectedProjectId,
selectedProjectKey: selectedProjectSummary?.projectKey ?? null,
Expand All @@ -39,6 +40,7 @@ export const createReadyActionContext = (
setProjectBrowser: state.setProjectBrowser,
setProjectTaskLogs: state.setProjectTaskLogs,
setProjectTasks: state.setProjectTasks,
setProjectTasksIncludeDefault: state.setProjectTasksIncludeDefault,
setSelectedMenuIndex: state.setSelectedMenuIndex,
setSelectedProject: state.setSelectedProject,
setSelectedProjectId: state.setSelectedProjectId
Expand Down
50 changes: 4 additions & 46 deletions packages/app/src/web/app-ready-controller.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import { updateActionPromptValue } from "./action-prompt.js"
import { withBusy } from "./actions-shared.js"
import {
applyProjectById,
applySelectedProject,
attachProjectTerminalById,
cancelBrowserActionPrompt,
closeSelectedProjectPort,
connectProjectById,
loadSelectedProjectBrowser,
loadSelectedProjectPorts,
openProjectBrowserById,
openSelectedProjectBrowser,
openSelectedProjectPort,
runApplyAllProjects,
submitBrowserActionPrompt
} from "./actions.js"
import { deleteProjectTerminalSession } from "./api.js"
import type { DashboardData } from "./api.js"
import type { createActionContext } from "./app-ready-actions.js"
import { resolveCurrentMenu, runAuthActionByIndex, runProjectAuthActionByIndex } from "./app-ready-actions.js"
Expand All @@ -41,6 +34,7 @@ import { bindScreenActions } from "./app-ready-screen-actions.js"
import { useSshLink } from "./app-ready-ssh-link-hook.js"
import { bindTaskActions } from "./app-ready-task-actions.js"
import { useProjectTasksReset } from "./app-ready-tasks-hook.js"
import { bindTerminalActions } from "./app-ready-terminal-actions.js"
import { useReadyUrlSync } from "./app-ready-url.js"
import { filterDashboardProjectsByQuery } from "./project-search.js"

Expand Down Expand Up @@ -102,7 +96,8 @@ const useReadyResetEffects = (args: ReadySideEffectsArgs) => {
useProjectTasksReset(
args.state.selectedProjectId,
args.state.setProjectTaskLogs,
args.state.setProjectTasks
args.state.setProjectTasks,
args.state.setProjectTasksIncludeDefault
)
}

Expand Down Expand Up @@ -130,6 +125,7 @@ const useReadyAutoloadEffects = (args: ReadySideEffectsArgs) => {
const useReadyShortcutEffects = (args: ReadySideEffectsArgs) => {
useBrowserShortcuts({
activeScreen: args.state.activeScreen,
activeTerminalSessionId: args.state.activeTerminalSessionId,
actionPrompt: args.state.actionPrompt,
context: args.actionContext,
controllerCwd: args.dashboard.health.cwd,
Expand Down Expand Up @@ -253,44 +249,6 @@ const bindBrowserActions = (
}
})

const bindTerminalActions = (
actionContext: ReturnType<typeof createActionContext>,
state: ReturnType<typeof useReadyState>
) => ({
onApplyProjectById: (projectId: string) => {
applyProjectById(projectId, actionContext)
},
onApplySelectedProject: () => {
applySelectedProject(actionContext)
},
onApplyAllProjects: () => {
runApplyAllProjects(actionContext)
},
onOpenProjectTerminalById: (projectId: string, projectKey?: string) => {
connectProjectById(projectId, actionContext, projectKey)
},
onAttachProjectTerminalSession: (
projectId: string,
projectKey: string,
projectDisplayName: string,
sessionId: string
) => {
attachProjectTerminalById(projectId, projectKey, projectDisplayName, sessionId, actionContext)
},
onKillProjectTerminalSession: (_projectId: string, projectKey: string, sessionId: string) => {
withBusy({
context: actionContext,
effect: deleteProjectTerminalSession(projectKey, sessionId),
label: "Killing SSH terminal",
onSuccess: () => {
state.closeTerminalSession(sessionId)
actionContext.reloadDashboard()
actionContext.setMessage(`Killed SSH terminal: ${sessionId}.`)
}
})
}
})

export const useReadyController = ({ dashboard, dashboardRefreshTick, refreshDashboard }: ReadyControllerArgs) => {
const state = useReadyState()
const currentMenu = resolveCurrentMenu(state.selectedMenuIndex)
Expand Down
11 changes: 9 additions & 2 deletions packages/app/src/web/app-ready-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ type CreateSubmitArgs = CreateKeyArgs & {
readonly quickCreate?: boolean
}

const createCharacterInput = (event: KeyboardEvent): string => event.key.length === 1 ? event.key : ""
type CreateKeyboardEvent = {
readonly key: string
readonly shiftKey: boolean
readonly preventDefault: () => void
}

const createCharacterInput = (event: Pick<CreateKeyboardEvent, "key">): string =>
event.key.length === 1 ? event.key : ""

export const resetCreateView = (): CreateFlowView => createInitialFlowView()

Expand Down Expand Up @@ -94,7 +101,7 @@ export const useCreateMenuReset = (
}

export const handleCreateKey = (
event: KeyboardEvent,
event: CreateKeyboardEvent,
{ context, controllerCwd, createView, projectsRoot, setCreateView }: CreateKeyArgs
): boolean => {
if (event.key === "Escape") {
Expand Down
3 changes: 3 additions & 0 deletions packages/app/src/web/app-ready-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export type ReadyLayoutProps = {
readonly onOpenProjectBrowserById: (projectId: string) => void
readonly onOpenProjectBrowser: () => void
readonly onOpenProjectDatabaseEditor: () => void
readonly onOpenProjectTaskManagerById: (projectId: string) => void
readonly onKillProjectTerminalSession: (projectId: string, projectKey: string, sessionId: string) => void
readonly onOpenProjectPortForward: () => void
readonly onOpenProjectTerminalById: (projectId: string, projectKey?: string) => void
Expand All @@ -80,6 +81,7 @@ export type ReadyLayoutProps = {
readonly onRefreshProjectBrowser: () => void
readonly onRefreshProjectDatabases: () => void
readonly onRefreshProjectTasks: () => void
readonly onProjectTasksIncludeDefaultChange: (includeDefault: boolean) => void
readonly onRestartProjectDatabaseEditor: () => void
readonly onSaveDatabaseProfile: () => void
readonly onSetActiveScreen: (screen: BrowserScreen) => void
Expand All @@ -100,6 +102,7 @@ export type ReadyLayoutProps = {
readonly projectBrowser: ProjectBrowserSession | null
readonly projectTaskLogs: string
readonly projectTasks: ContainerTaskSnapshot | null
readonly projectTasksIncludeDefault: boolean
readonly selectedMenuIndex: number
readonly selectedProjectId: string | null
readonly selectedProjectSummary: DashboardData["projects"][number] | undefined
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/web/app-ready-main-panels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ const DatabaseDetails = (props: MainPanelsProps): JSX.Element => (

const TaskDetails = (props: MainPanelsProps): JSX.Element => (
<TaskPanel
includeDefault={props.projectTasksIncludeDefault}
logs={props.projectTaskLogs}
onIncludeDefaultChange={props.onProjectTasksIncludeDefaultChange}
onLoadLogs={props.onLoadProjectTaskLogs}
onRefreshTasks={props.onRefreshProjectTasks}
onStopTask={props.onStopProjectTask}
Expand Down
Loading