mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
fix(frontend): call a dev workspace a dev workspace in the merge UI (#10605)
* fix(frontend): call a dev workspace a dev workspace in the merge UI Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * refactor(frontend): drop the unreachable dev-workspace guard on the fork modals Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,7 +29,8 @@
|
||||
useWorkspaceDrafts
|
||||
} from '$lib/workspaceDrafts.svelte'
|
||||
import type { Kind as LayoutKind } from '$lib/utils_deployable'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { userStore, userWorkspaces } from '$lib/stores'
|
||||
import { childWorkspaceNoun } from '$lib/utils/devWorkspaceLabel'
|
||||
|
||||
interface Props {
|
||||
currentWorkspaceId: string
|
||||
@@ -161,6 +162,10 @@
|
||||
// (unrelated to the fork's own work) are the common case worth hiding.
|
||||
let hideUnchanged = $state(true)
|
||||
|
||||
const currentNoun = $derived(
|
||||
childWorkspaceNoun($userWorkspaces.find((w) => w.id === currentWorkspaceId))
|
||||
)
|
||||
|
||||
// The list (and, in the default view, the Draft Count) come from the Workspace
|
||||
// Drafts module; deploy/discard invalidate the resource, so the list refetches
|
||||
// and deployed items drop off without a manual reload here.
|
||||
@@ -663,8 +668,7 @@
|
||||
size="xs"
|
||||
options={{
|
||||
right: 'Hide unchanged drafts',
|
||||
rightTooltip:
|
||||
"Hide drafts identical to the parent workspace. A fork inherits the parent's drafts when it's created; those are unrelated to the changes made in this fork."
|
||||
rightTooltip: `Hide drafts identical to the parent workspace. A ${currentNoun} inherits the parent's drafts when it's created; those are unrelated to the changes made in this ${currentNoun}.`
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
import CompareModeToggle, { type CompareMode } from './CompareModeToggle.svelte'
|
||||
import CompareTargetPicker from './CompareTargetPicker.svelte'
|
||||
import { displayDate } from '$lib/utils'
|
||||
import { childWorkspaceNoun } from '$lib/utils/devWorkspaceLabel'
|
||||
import { editUrlFor } from './sessions/forkEditUrl'
|
||||
import { diffInMask } from './sessions/modifiedItemsMask'
|
||||
import DatatableSchemaDiff from './DatatableSchemaDiff.svelte'
|
||||
@@ -400,6 +401,8 @@
|
||||
let currentWorkspaceInfo = $derived($userWorkspaces.find((w) => w.id == currentWorkspaceId))
|
||||
let parentWorkspaceInfo = $derived($userWorkspaces.find((w) => w.id == parentWorkspaceId))
|
||||
|
||||
let currentNoun = $derived(childWorkspaceNoun(currentWorkspaceInfo))
|
||||
|
||||
// An arbitrary target is one-way: the pair has no tally, so nothing distinguishes
|
||||
// a change made here from one made there, and the "update current" direction
|
||||
// would list every difference as an incoming change.
|
||||
@@ -448,7 +451,7 @@
|
||||
? `No changes between this workspace and ${parentWorkspaceId}.`
|
||||
: mergeIntoParent
|
||||
? `Nothing to deploy — ${parentWorkspaceId} already has every change from this workspace.`
|
||||
: `Nothing to update — this fork is up to date with ${parentWorkspaceId}.`
|
||||
: `Nothing to update — this ${currentNoun} is up to date with ${parentWorkspaceId}.`
|
||||
)
|
||||
|
||||
let conflictingDiffs = $derived(
|
||||
@@ -1437,7 +1440,8 @@
|
||||
<span>
|
||||
{#if mergeIntoParent}
|
||||
This workspace has {draftCount} undeployed draft{draftCount !== 1 ? 's' : ''}.
|
||||
Only deployed versions in this fork can be sent to {parentWorkspaceId} — deploy
|
||||
Only deployed versions in this {currentNoun} can be sent to {parentWorkspaceId} —
|
||||
deploy
|
||||
{draftCount !== 1 ? 'them' : 'it'} first, otherwise those changes won't be included.
|
||||
{:else}
|
||||
This workspace has {draftCount} undeployed draft{draftCount !== 1 ? 's' : ''}.
|
||||
@@ -1461,14 +1465,14 @@
|
||||
<Alert title="Conflicting changes detected" type="warning" class="mt-2">
|
||||
<span>
|
||||
{conflictingDiffs.length} item{conflictingDiffs.length !== 1 ? 's have' : ' has'} conflicting
|
||||
changes, it was modified on the original workspace while changes were made on this fork.
|
||||
Make sure to resolve these before merging.
|
||||
changes, it was modified on the original workspace while changes were made on this
|
||||
{currentNoun}. Make sure to resolve these before merging.
|
||||
</span>
|
||||
</Alert>
|
||||
{/if}
|
||||
{#if hasBehindChanges && hasAheadChanges && !(mergeIntoParent && !canDeployToParent)}
|
||||
<Alert
|
||||
title="This fork is behind {parentWorkspaceId} and needs to be up to date before deploying"
|
||||
title="This {currentNoun} is behind {parentWorkspaceId} and needs to be up to date before deploying"
|
||||
type="warning"
|
||||
class="my-2"
|
||||
>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { userWorkspaces } from '$lib/stores'
|
||||
import { childWorkspaceNoun } from '$lib/utils/devWorkspaceLabel'
|
||||
import { runScriptAndPollResult } from '$lib/components/jobs/utils'
|
||||
import { writingJobOptions } from '$lib/components/jobs/writingJob'
|
||||
import YAML from 'yaml'
|
||||
@@ -34,6 +35,11 @@
|
||||
|
||||
let { currentWorkspaceId, parentWorkspaceId }: Props = $props()
|
||||
|
||||
let currentNoun = $derived(
|
||||
childWorkspaceNoun($userWorkspaces.find((w) => w.id === currentWorkspaceId))
|
||||
)
|
||||
let currentNounCap = $derived(currentNoun.charAt(0).toUpperCase() + currentNoun.slice(1))
|
||||
|
||||
let loading = $state(true)
|
||||
let error: string | undefined = $state(undefined)
|
||||
let diffs: DatatableDiff[] = $state([])
|
||||
@@ -321,8 +327,9 @@
|
||||
<div class="border-t divide-y">
|
||||
{#if diff.aheadChanges.length > 0}
|
||||
<div class="px-3 py-1.5">
|
||||
<div class="text-2xs font-semibold text-blue-500 mb-1">Fork changes (ahead)</div
|
||||
>
|
||||
<div class="text-2xs font-semibold text-blue-500 mb-1">
|
||||
{currentNounCap} changes (ahead)
|
||||
</div>
|
||||
{#each diff.aheadChanges as change}
|
||||
<div class="flex items-center gap-2 text-xs py-0.5">
|
||||
{#if change.kind === 'added'}
|
||||
@@ -393,8 +400,8 @@
|
||||
<DrawerContent
|
||||
on:close={() => (drawerOpen = false)}
|
||||
title="{drawerChange.schemaName}.{drawerChange.tableName} ({drawerDirection === 'ahead'
|
||||
? 'Fork → Parent'
|
||||
: 'Parent → Fork'})"
|
||||
? `${currentNounCap} → Parent`
|
||||
: `Parent → ${currentNounCap}`})"
|
||||
>
|
||||
{#snippet actions()}
|
||||
<Button
|
||||
@@ -422,7 +429,7 @@
|
||||
<!-- Diff section -->
|
||||
<div style="height: 45%;">
|
||||
<div class="py-1.5 text-2xs font-semibold text-secondary">
|
||||
Schema diff (parent ↔ fork)
|
||||
Schema diff (parent ↔ {currentNoun})
|
||||
</div>
|
||||
<div class="h-[calc(100%-28px)] border rounded-md overflow-clip">
|
||||
{#await import('$lib/components/DiffEditor.svelte')}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { goto } from '$app/navigation'
|
||||
import { onMount, untrack } from 'svelte'
|
||||
import { useWorkspaceDrafts } from '$lib/workspaceDrafts.svelte'
|
||||
import { devLabelWord } from '$lib/utils/devWorkspaceLabel'
|
||||
import { childWorkspaceNoun, devLabelWord } from '$lib/utils/devWorkspaceLabel'
|
||||
import { diffActionableInDirection } from '$lib/utils_workspace_deploy'
|
||||
|
||||
let loading = $state(false)
|
||||
@@ -26,6 +26,7 @@
|
||||
// prefix) also avoids a parentless "Fork of ()" banner when the linkage is dropped.
|
||||
let isFork = $derived(parentWorkspaceId != null)
|
||||
let isDevWorkspace = $derived(currentWorkspaceData?.is_dev_workspace ?? false)
|
||||
let currentNoun = $derived(childWorkspaceNoun(currentWorkspaceData))
|
||||
// Operators run scripts and flows, they never deploy a fork, so the banner and
|
||||
// its CTA are noise for them. Gates the fetches too, not just the markup: the
|
||||
// fork/parent comparison is an expensive tally no operator can act on.
|
||||
@@ -233,7 +234,7 @@
|
||||
function forkAheadBehindMessage(changesAhead: number, changesBehind: number) {
|
||||
let msg: string[] = []
|
||||
if (changesAhead > 0 || changesBehind > 0) {
|
||||
msg.push('This fork is ')
|
||||
msg.push(`This ${currentNoun} is `)
|
||||
if (changesAhead > 0)
|
||||
msg.push(`${changesAhead} change${changesAhead > 1 ? 's' : ''} ahead of `)
|
||||
if (changesAhead > 0 && changesBehind > 0) msg.push('and ')
|
||||
@@ -400,7 +401,7 @@
|
||||
{/if}
|
||||
{:else if comparison.skipped_comparison}
|
||||
<span class="text-blue-600 dark:text-blue-200">
|
||||
This fork was created before the addition of certain windmill features, and
|
||||
This {currentNoun} was created before the addition of certain windmill features, and
|
||||
therefore the changes with its parent workspace cannot be displayed.</span
|
||||
>
|
||||
{:else if showDraftsOnly}
|
||||
@@ -425,7 +426,7 @@
|
||||
{:else if !hasAnswer || changesAhead > 0}
|
||||
Review & Deploy Changes
|
||||
{:else}
|
||||
Review & Update fork
|
||||
Review & Update {currentNoun}
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -41,3 +41,14 @@ export function devLabelWord(label: string | null | undefined): string {
|
||||
export function devLabelNoun(label: string | null | undefined): string {
|
||||
return `${devLabelKey(label)} workspace`
|
||||
}
|
||||
|
||||
/**
|
||||
* How to name a child workspace in prose: its environment noun when it is a dev workspace
|
||||
* ("dev workspace", "staging workspace"), "fork" otherwise. A dev workspace is a standing
|
||||
* environment its whole team works in, so calling it a fork misreads it as throwaway.
|
||||
*/
|
||||
export function childWorkspaceNoun(
|
||||
workspace: { is_dev_workspace?: boolean; dev_workspace_label?: string | null } | undefined
|
||||
): string {
|
||||
return workspace?.is_dev_workspace ? devLabelNoun(workspace.dev_workspace_label) : 'fork'
|
||||
}
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
// prefix. Distinct from having a compare target: a root workspace has no parent
|
||||
// yet can still be pointed at an arbitrary one.
|
||||
const isFork = $derived(!!parentWorkspaceId)
|
||||
// A dev workspace is a standing environment, torn down by detaching it in the
|
||||
// dev-workspace settings — never by an archive/delete button sitting next to the
|
||||
// merge it is here to perform.
|
||||
const isDevWorkspace = $derived(!!currentWorkspaceData?.is_dev_workspace)
|
||||
const hasCompareTarget = $derived(!!compareTargetId)
|
||||
|
||||
// Mode is seeded from the URL (?mode=draft|fork). `draft` is valid for any
|
||||
@@ -389,10 +393,10 @@
|
||||
<CenteredPage>
|
||||
<PageHeader title="Compare & Deploy">
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
<!-- The merged compare toggle (fork direction + deployed↔draft) now lives
|
||||
inside each comparison card; only the fork lifecycle actions remain
|
||||
in the page header. -->
|
||||
{#if isFork}
|
||||
<!-- The merged compare toggle (fork direction + deployed↔draft) lives inside
|
||||
each comparison card; only the fork lifecycle actions remain in the page
|
||||
header, and only for a throwaway fork. -->
|
||||
{#if isFork && !isDevWorkspace}
|
||||
<Button
|
||||
variant="default"
|
||||
color="light"
|
||||
|
||||
Reference in New Issue
Block a user