mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
* Add create_ephemeral workspace endpoint * Add cli devShell * List ephemeral workspaces + improve endpoint * Add postgres function to clone a workspace (to be revisited) * Clone workspace using the postgres function * Add first iteration of ephemeral workspaces command * Update display of forked workspaces * Remove SQLX_OFFLINE * Add UI to create ephemeral workspace * Add option to exclude repository from being inherited to forks * WIP: reworking cloning logic * Fix cloning * Fix redirect after creating fork * Clean up cloning behaviour * Rename ephemeral to fork * emove ephemeral_workspaces table in favour of columns in workspaces * Fix display of forked workspaces * Fix skip inherit git sync repo setting * Fix fork invite display + creating fork as user * Fix SideMenu bug * Fix alignment * Simplify migrations * Update deletion of workspaces * Delete forked workspace from cli * Deleting fork workspaces from the UI as non-admin * Update cli sync and fork creation to adapt to branches and forks * Update fork prefix * Remove skip tracking toggle * Fix npm check warnings * Fix last npm check * fix: force stdin to Stdio::null for all user code execution (#6575) Set stdin to Stdio::null for all Commands that execute user code across all supported languages to prevent unwanted input consumption. This affects Python, Deno, Bash, PowerShell, Go, Rust, PHP, Ruby, Java, C#, Ansible, Nu, and Bun executors. The dedicated worker handler was intentionally left unchanged as it requires stdin for inter-process communication. Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> * Update ee-repo ref * Update SQLx metadata * Fix typos --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
129 lines
3.8 KiB
TypeScript
129 lines
3.8 KiB
TypeScript
import type { UserWorkspace } from '../stores'
|
|
|
|
export interface WorkspaceHierarchyItem {
|
|
workspace: UserWorkspace
|
|
depth: number
|
|
isForked: boolean
|
|
parentName?: string
|
|
hasChildren: boolean
|
|
}
|
|
|
|
/**
|
|
* Builds a hierarchical structure from a flat array of workspaces.
|
|
* Supports unlimited nesting levels (fork of fork of fork...).
|
|
* Returns a flattened array with hierarchy metadata for easy rendering.
|
|
*/
|
|
export function buildWorkspaceHierarchy(workspaces: UserWorkspace[]): WorkspaceHierarchyItem[] {
|
|
if (!workspaces || workspaces.length === 0) {
|
|
return []
|
|
}
|
|
|
|
// Create maps for quick lookups
|
|
const workspaceMap = new Map(workspaces.map(w => [w.id, w]))
|
|
const childrenMap = new Map<string, UserWorkspace[]>()
|
|
const hasChildrenSet = new Set<string>()
|
|
|
|
// Build children mapping and track which workspaces have children
|
|
for (const workspace of workspaces) {
|
|
if (workspace.parent_workspace_id) {
|
|
if (!childrenMap.has(workspace.parent_workspace_id)) {
|
|
childrenMap.set(workspace.parent_workspace_id, [])
|
|
}
|
|
childrenMap.get(workspace.parent_workspace_id)!.push(workspace)
|
|
hasChildrenSet.add(workspace.parent_workspace_id)
|
|
}
|
|
}
|
|
|
|
// Find root workspaces (those without a parent or whose parent is not in the current list)
|
|
const rootWorkspaces = workspaces.filter(w => {
|
|
if (!w.parent_workspace_id) {
|
|
return true // Definitely a root
|
|
}
|
|
// Check if parent exists in the current workspace list
|
|
return !workspaceMap.has(w.parent_workspace_id)
|
|
})
|
|
|
|
const result: WorkspaceHierarchyItem[] = []
|
|
|
|
// Recursively build the hierarchy
|
|
function addWorkspaceAndChildren(workspace: UserWorkspace, depth: number, isForked: boolean, parentName?: string) {
|
|
// Add the current workspace
|
|
result.push({
|
|
workspace,
|
|
depth,
|
|
isForked,
|
|
parentName,
|
|
hasChildren: hasChildrenSet.has(workspace.id)
|
|
})
|
|
|
|
// Add its children (sorted by name for consistency)
|
|
const children = childrenMap.get(workspace.id) || []
|
|
children
|
|
.sort((a, b) => a.name.localeCompare(b.name))
|
|
.forEach(child => {
|
|
addWorkspaceAndChildren(child, depth + 1, true, workspace.name)
|
|
})
|
|
}
|
|
|
|
// Process root workspaces (sorted by name for consistency)
|
|
rootWorkspaces
|
|
.sort((a, b) => a.name.localeCompare(b.name))
|
|
.forEach(workspace => {
|
|
const isRootForked = workspace.parent_workspace_id != null
|
|
const parentName = isRootForked && workspace.parent_workspace_id
|
|
? workspace.parent_workspace_id // Use parent ID as fallback if parent not in list
|
|
: undefined
|
|
|
|
addWorkspaceAndChildren(workspace, 0, isRootForked, parentName)
|
|
})
|
|
|
|
return result
|
|
}
|
|
|
|
/**
|
|
* Helper function to get the indentation padding based on depth.
|
|
* Each level adds 24px of left padding.
|
|
*/
|
|
export function getWorkspaceIndentation(depth: number): string {
|
|
return `${depth * 24}px`
|
|
}
|
|
|
|
/**
|
|
* Helper function to check if a workspace is a root workspace
|
|
*/
|
|
export function isRootWorkspace(workspace: UserWorkspace): boolean {
|
|
return workspace.parent_workspace_id == null
|
|
}
|
|
|
|
/**
|
|
* Helper function to find all descendants of a workspace
|
|
*/
|
|
export function findWorkspaceDescendants(
|
|
workspaceId: string,
|
|
allWorkspaces: UserWorkspace[]
|
|
): UserWorkspace[] {
|
|
const descendants: UserWorkspace[] = []
|
|
const childrenMap = new Map<string, UserWorkspace[]>()
|
|
|
|
// Build children mapping
|
|
for (const workspace of allWorkspaces) {
|
|
if (workspace.parent_workspace_id) {
|
|
if (!childrenMap.has(workspace.parent_workspace_id)) {
|
|
childrenMap.set(workspace.parent_workspace_id, [])
|
|
}
|
|
childrenMap.get(workspace.parent_workspace_id)!.push(workspace)
|
|
}
|
|
}
|
|
|
|
// Recursively find descendants
|
|
function collectDescendants(id: string) {
|
|
const children = childrenMap.get(id) || []
|
|
for (const child of children) {
|
|
descendants.push(child)
|
|
collectDescendants(child.id)
|
|
}
|
|
}
|
|
|
|
collectDescendants(workspaceId)
|
|
return descendants
|
|
} |