mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-19 00:02:28 +00:00
Compare commits
16
Commits
@@ -3,11 +3,13 @@
|
||||
import Select from './select/Select.svelte'
|
||||
import { fetchAvailableModels, AI_PROVIDERS } from './copilot/lib'
|
||||
import type { AIProvider, ProviderConfig } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import ResourcePicker from './ResourcePicker.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import { saveConfig, removeConfig, isSameAsStoredConfig } from './aiProviderStorage'
|
||||
import AIReasoningEffortPicker from './AIReasoningEffortPicker.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
value: ProviderConfig | undefined
|
||||
@@ -26,7 +28,7 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore ?? '')
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace ?? '')
|
||||
|
||||
let value = $derived.by(() => {
|
||||
if (!_uncheckedValue || typeof _uncheckedValue !== 'object') return undefined
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { ExternalLink, Globe } from 'lucide-svelte'
|
||||
import { JobService, type Job } from '$lib/gen'
|
||||
import { base } from '$lib/base'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { msToReadableTimeShort } from '$lib/utils'
|
||||
import ChatCollapsibleCard from './copilot/chat/ChatCollapsibleCard.svelte'
|
||||
import ToolContentDisplay from './copilot/chat/ToolContentDisplay.svelte'
|
||||
@@ -10,6 +9,9 @@
|
||||
import GfmMarkdown from './GfmMarkdown.svelte'
|
||||
import type { AgentTraceEntry } from './agentTrace'
|
||||
import { SvelteMap, SvelteSet } from 'svelte/reactivity'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
entries: AgentTraceEntry[]
|
||||
@@ -40,7 +42,7 @@
|
||||
try {
|
||||
jobs.set(
|
||||
jobId,
|
||||
await JobService.getJob({ id: jobId, workspace: workspaceId ?? $workspaceStore! })
|
||||
await JobService.getJob({ id: jobId, workspace: workspaceId ?? $operatingWorkspace! })
|
||||
)
|
||||
} catch {
|
||||
// A tool job can be gone (retention) or unreadable. The row still has its
|
||||
@@ -121,7 +123,7 @@
|
||||
{:else if entry.jobId}
|
||||
<a
|
||||
class="text-2xs text-accent inline-flex items-center gap-1 w-fit hover:underline"
|
||||
href="{base}/run/{entry.jobId}?workspace={workspaceId ?? $workspaceStore}"
|
||||
href="{base}/run/{entry.jobId}?workspace={workspaceId ?? $operatingWorkspace}"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { OauthService, type ResourceType } from '$lib/gen'
|
||||
import FilesetEditor from './FilesetEditor.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptySchema, emptyString } from '$lib/utils'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import Toggle from './Toggle.svelte'
|
||||
@@ -20,6 +19,9 @@
|
||||
import { base } from '$lib/base'
|
||||
import { isDataTableWizardEnabled } from './workspaceSettings/utils.svelte'
|
||||
import { parsePostgresConnectionString } from '$lib/utils/postgresConnectionString'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
resourceType: string
|
||||
@@ -152,7 +154,7 @@
|
||||
}
|
||||
}
|
||||
$effect(() => {
|
||||
$workspaceStore && untrack(() => loadSchema())
|
||||
$operatingWorkspace && untrack(() => loadSchema())
|
||||
})
|
||||
$effect(() => {
|
||||
notFound && rawCode && untrack(() => parseJson())
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy'
|
||||
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { userStore } from '$lib/stores'
|
||||
import LabelsInput from './LabelsInput.svelte'
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import {
|
||||
@@ -53,6 +53,9 @@
|
||||
import Label from './Label.svelte'
|
||||
import ResourcePathHint from './ResourcePathHint.svelte'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
step?: number
|
||||
@@ -84,7 +87,7 @@
|
||||
fillPath = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore!)
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace!)
|
||||
|
||||
let isValid = $state(true)
|
||||
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService, VariableService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { copyToClipboard, truncate } from '$lib/utils'
|
||||
import { ClipboardCopy, Expand } from 'lucide-svelte'
|
||||
import Drawer from './common/drawer/Drawer.svelte'
|
||||
import ObjectViewer from './propertyPicker/ObjectViewer.svelte'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
import { Button, DrawerContent } from './common'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
value: any
|
||||
@@ -22,14 +24,14 @@
|
||||
|
||||
async function getResource(path: string) {
|
||||
jsonViewerContent = await ResourceService.getResourceValue({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
path
|
||||
})
|
||||
}
|
||||
|
||||
async function getVariable(path: string) {
|
||||
jsonViewerContent = await VariableService.getVariableValue({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
path
|
||||
})
|
||||
}
|
||||
|
||||
@@ -41,12 +41,14 @@
|
||||
import { safeSelectItems } from './select/utils.svelte'
|
||||
import S3ArgInput from './common/fileUpload/S3ArgInput.svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { getJsonSchemaFromResource } from './schema/jsonSchemaResource.svelte'
|
||||
import AIProviderPicker from './AIProviderPicker.svelte'
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
import FileInput from './common/fileInput/FileInput.svelte'
|
||||
import { randomUUID } from '$lib/utils/uuid'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
label?: string
|
||||
@@ -823,7 +825,7 @@
|
||||
/>
|
||||
{/await}
|
||||
{:else if inputCat == 'object' && format?.startsWith('jsonschema-')}
|
||||
{#await getJsonSchemaFromResource(format.substring('jsonschema-'.length), workspace ?? $workspaceStore ?? '')}
|
||||
{#await getJsonSchemaFromResource(format.substring('jsonschema-'.length), workspace ?? $operatingWorkspace ?? '')}
|
||||
<Loader2 class="animate-spin" />
|
||||
{:then schema}
|
||||
{#if !schema || !schema.properties}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { JobService, type FlowValue } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { tryEvery } from '$lib/utils'
|
||||
import { Check, LoaderCircle, Server, X, Cpu } from 'lucide-svelte'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface CredentialsCheckResult {
|
||||
available: boolean
|
||||
@@ -28,7 +30,7 @@
|
||||
apiResult = null
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/w/${$workspaceStore}/ai/check_bedrock_credentials`)
|
||||
const response = await fetch(`/api/w/${$operatingWorkspace}/ai/check_bedrock_credentials`)
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error: ${response.status}`)
|
||||
}
|
||||
@@ -78,7 +80,7 @@
|
||||
}
|
||||
|
||||
const job = await JobService.runFlowPreview({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
requestBody: {
|
||||
value: flowValue as unknown as FlowValue,
|
||||
args: {}
|
||||
@@ -88,7 +90,7 @@
|
||||
tryEvery({
|
||||
tryCode: async () => {
|
||||
const testResult = await JobService.getCompletedJob({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
id: job
|
||||
})
|
||||
|
||||
@@ -130,7 +132,7 @@
|
||||
workerStatus = 'error'
|
||||
try {
|
||||
await JobService.cancelQueuedJob({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
id: job,
|
||||
requestBody: {
|
||||
reason: 'Timeout checking Bedrock credentials'
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import Select from './select/Select.svelte'
|
||||
import { WorkspaceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { RefreshCcw } from 'lucide-svelte'
|
||||
import { Button } from './common'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface ChannelItem {
|
||||
channel_id?: string
|
||||
@@ -21,8 +23,8 @@
|
||||
showRefreshButton?: boolean
|
||||
onError?: (error: Error) => void
|
||||
onSelectedChannelChange?: (channel: ChannelItem | undefined) => void
|
||||
/** Workspace to list Teams channels from; defaults to the nav
|
||||
* `$workspaceStore`. A forked session passes its acting workspace. */
|
||||
/** Workspace to list Teams channels from; defaults to the operating workspace (see
|
||||
* `useOperatingWorkspace`). */
|
||||
workspace?: string
|
||||
}
|
||||
|
||||
@@ -40,7 +42,7 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore)
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let isFetching = $state(false)
|
||||
let loadedChannels = $state<ChannelItem[]>([])
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import ClipboardPanel from './details/ClipboardPanel.svelte'
|
||||
import Section from './Section.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
let url = $derived(`${window.location.protocol}//${window.location.hostname}/`)
|
||||
</script>
|
||||
@@ -20,7 +22,7 @@
|
||||
<span class="font-medium">Setup the wmill cli for this workspace & remote:</span>
|
||||
<div class="mt-1">
|
||||
<ClipboardPanel
|
||||
content={`wmill workspace add ${$workspaceStore} ${$workspaceStore} ${url}`}
|
||||
content={`wmill workspace add ${$operatingWorkspace} ${$operatingWorkspace} ${url}`}
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { superadmin, userStore, type DBSchema } from '$lib/stores'
|
||||
import { superadmin, type DBSchema } from '$lib/stores'
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
EditIcon,
|
||||
@@ -33,6 +33,10 @@
|
||||
import type { DbFeatures } from './apps/components/display/dbtable/dbFeatures'
|
||||
import Star from './Star.svelte'
|
||||
import type { Asset } from '$lib/gen'
|
||||
import { useOperatingUser } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
/** Represents a selected table with its schema */
|
||||
export interface SelectedTable {
|
||||
@@ -644,7 +648,7 @@
|
||||
Import schema from database
|
||||
</span>
|
||||
</button>
|
||||
{#if !!$userStore?.is_admin || !!$superadmin}
|
||||
{#if !!actingUser?.is_admin || !!$superadmin}
|
||||
<button
|
||||
onclick={() => onImport('schema_and_data')}
|
||||
class="hover:opacity-70 transition-opacity rounded-md border aspect-square w-52 gap-4 p-4 center-center flex-col"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { dbSchemas, workspaceStore, type DBSchema } from '$lib/stores'
|
||||
import { dbSchemas, type DBSchema } from '$lib/stores'
|
||||
import { sortArray } from '$lib/utils'
|
||||
import { Loader2, RefreshCcw } from 'lucide-svelte'
|
||||
import Alert from './common/alert/Alert.svelte'
|
||||
@@ -29,6 +29,9 @@
|
||||
import { createAsyncConfirmationModal } from './common/confirmationModal/asyncConfirmationModal.svelte'
|
||||
import Portal from '$lib/components/Portal.svelte'
|
||||
import { outOfOrderRunMessage } from './workspaceSettings/datatableMigrationUtils'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
input?: DbInput
|
||||
@@ -44,9 +47,8 @@
|
||||
/** Tables that are already added and should show as disabled */
|
||||
disabledTables?: SelectedTable[]
|
||||
onImport?: (mode: 'schema_and_data' | 'schema_only') => void
|
||||
/** Workspace the datatable/schema lookups run against. Defaults to the
|
||||
* navigation `$workspaceStore`; pass the acting workspace when embedded in
|
||||
* a session preview whose workspace differs from the top nav. */
|
||||
/** Workspace the datatable/schema lookups run against. Defaults to the operating
|
||||
* workspace (see `useOperatingWorkspace`). */
|
||||
workspace?: string
|
||||
/** Worker tag every job of this manager runs on, overriding the database
|
||||
* language's native tag. Bound so the hints below can offer to set it. */
|
||||
@@ -68,7 +70,7 @@
|
||||
workerTag = $bindable()
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let dbSchema: DBSchema | undefined = $derived(input && $dbSchemas[schemaCacheKey(input)])
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { createGrid, type GridApi, type IDatasource } from 'ag-grid-community'
|
||||
import { transformColumnDefs } from './apps/components/display/table/utils'
|
||||
@@ -82,6 +81,9 @@
|
||||
import 'ag-grid-community/styles/ag-theme-alpine.css'
|
||||
import '$lib/components/apps/components/display/table/theme/windmill-theme.css'
|
||||
import { untrack } from 'svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
type Props = {
|
||||
dbTableOps: IDbTableOps
|
||||
@@ -101,7 +103,7 @@
|
||||
|
||||
let datasource: IDatasource = {
|
||||
getRows: async function (params) {
|
||||
if (!$workspaceStore) return params.failCallback()
|
||||
if (!$operatingWorkspace) return params.failCallback()
|
||||
let lastRow = rowCount && rowCount <= params.endRow ? rowCount : -1
|
||||
|
||||
const items = await dbTableOps.getRows({
|
||||
@@ -132,7 +134,7 @@
|
||||
minWidth: 150,
|
||||
editable: true,
|
||||
onCellValueChanged: (e) => {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
const colDef = e.colDef as unknown as { field: string; datatype: string }
|
||||
dbTableOps
|
||||
.onUpdate?.(
|
||||
@@ -169,7 +171,7 @@
|
||||
|
||||
let prevUpdateKey: any = undefined
|
||||
$effect(() => {
|
||||
if (!$workspaceStore || !api) return
|
||||
if (!$operatingWorkspace || !api) return
|
||||
const key = { quicksearch, colDefs: dbTableOps.colDefs, refreshCount, rowFilter }
|
||||
if (deepEqual(key, prevUpdateKey)) return
|
||||
prevUpdateKey = key
|
||||
@@ -191,7 +193,7 @@
|
||||
),
|
||||
...(dbTableOps.onDelete && {
|
||||
onDelete: (values) => {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
dbTableOps
|
||||
.onDelete?.({ values })
|
||||
.then(() => {
|
||||
@@ -249,7 +251,7 @@
|
||||
columnDefs={dbTableOps.colDefs ?? []}
|
||||
dbType={dbTableOps.dbType}
|
||||
onInsert={(values) => {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
dbTableOps.onInsert?.({ values }).then((result) => {
|
||||
refresh?.()
|
||||
sendUserToast('Row inserted')
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { WorkspaceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
|
||||
import Select from './select/Select.svelte'
|
||||
import ExploreAssetButton, { assetCanBeExplored } from './ExploreAssetButton.svelte'
|
||||
import { usePromise } from '$lib/svelte5Utils.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
value?: string | undefined
|
||||
@@ -29,7 +31,7 @@
|
||||
}: Props = $props()
|
||||
|
||||
let datatables = usePromise(() =>
|
||||
WorkspaceService.listDataTables({ workspace: $workspaceStore ?? '' }).then((d) =>
|
||||
WorkspaceService.listDataTables({ workspace: $operatingWorkspace ?? '' }).then((d) =>
|
||||
d.map((d) => d.name)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { userStore } from '$lib/stores'
|
||||
import { SettingsIcon } from 'lucide-svelte'
|
||||
import { Button } from './common'
|
||||
import Drawer from './common/drawer/Drawer.svelte'
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import DefaultScriptsInner from './DefaultScriptsInner.svelte'
|
||||
import { useOperatingUser } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
interface Props {
|
||||
placement?: 'left' | 'right'
|
||||
@@ -17,7 +20,7 @@
|
||||
let drawer: Drawer | undefined = $state()
|
||||
</script>
|
||||
|
||||
{#if $userStore?.is_admin || $userStore?.is_super_admin}
|
||||
{#if actingUser?.is_admin || actingUser?.is_super_admin}
|
||||
<Drawer bind:this={drawer} {placement}>
|
||||
<DrawerContent title="Edit Default Scripts" on:close={drawer?.closeDrawer}>
|
||||
<DefaultScriptsInner />
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { WorkspaceService, type Script, type WorkspaceDefaultScripts } from '$lib/gen'
|
||||
import { defaultScripts, workspaceStore } from '$lib/stores'
|
||||
import { defaultScripts } from '$lib/stores'
|
||||
import { flip } from 'svelte/animate'
|
||||
import Toggle from './Toggle.svelte'
|
||||
import { defaultScriptLanguages } from '$lib/scripts'
|
||||
import Alert from './common/alert/Alert.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
small?: boolean
|
||||
@@ -29,7 +32,7 @@
|
||||
}
|
||||
defaultScripts.update((s) => ({ ...s, order: norder }))
|
||||
await WorkspaceService.editDefaultScripts({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
requestBody: $defaultScripts
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { WorkspaceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
|
||||
import Select from './select/Select.svelte'
|
||||
import ExploreAssetButton, { assetCanBeExplored } from './ExploreAssetButton.svelte'
|
||||
import { usePromise } from '$lib/svelte5Utils.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
value?: string | undefined
|
||||
@@ -29,9 +31,8 @@
|
||||
}: Props = $props()
|
||||
|
||||
let ducklakes = usePromise(() =>
|
||||
WorkspaceService.listDucklakes({ workspace: $workspaceStore ?? '' })
|
||||
WorkspaceService.listDucklakes({ workspace: $operatingWorkspace ?? '' })
|
||||
)
|
||||
|
||||
</script>
|
||||
|
||||
<div class={className}>
|
||||
@@ -46,9 +47,6 @@
|
||||
{onClear}
|
||||
/>
|
||||
{#if showSchemaExplorer && value && assetCanBeExplored({ kind: 'ducklake', path: value })}
|
||||
<ExploreAssetButton
|
||||
class="mt-1 w-fit"
|
||||
asset={{ kind: 'ducklake', path: value }}
|
||||
/>
|
||||
<ExploreAssetButton class="mt-1 w-fit" asset={{ kind: 'ducklake', path: value }} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
const bubble = createBubbler()
|
||||
import type { Schema } from '$lib/common'
|
||||
import { VariableService, type ScriptLang } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Button } from './common'
|
||||
import ItemPicker from './ItemPicker.svelte'
|
||||
import VariableEditor from './VariableEditor.svelte'
|
||||
@@ -36,6 +35,9 @@
|
||||
import Section from '$lib/components/Section.svelte'
|
||||
import Editor from './Editor.svelte'
|
||||
import AddPropertyV2 from './schema/AddPropertyV2.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
// export let openEditTab: () => void = () => {}
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -128,7 +130,7 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
$effect.pre(() => {
|
||||
if (args == undefined) {
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
import { editorConfig, registerWebviewPaste, updateOptions } from '$lib/editorUtils'
|
||||
import { editorFontSize } from '$lib/editorFontSize.svelte'
|
||||
import { createHash as randomHash } from '$lib/editorLangUtils'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import DdlMigrationGuard from './DdlMigrationGuard.svelte'
|
||||
import {
|
||||
type Preview,
|
||||
@@ -120,6 +119,9 @@
|
||||
import { rawAppLintStore, type MonacoLintError } from './raw_apps/lintStore'
|
||||
import { MarkerSeverity } from 'monaco-editor'
|
||||
import { resource, useDebounce, watch } from 'runed'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
// import EditorTheme from './EditorTheme.svelte'
|
||||
|
||||
let divEl: HTMLDivElement | null = $state(null)
|
||||
@@ -684,7 +686,7 @@
|
||||
// via a short-TTL cache — macros are late-bound, so mild staleness is fine.
|
||||
async function addWorkspaceMacroCompletions() {
|
||||
workspaceMacroCompletor?.dispose()
|
||||
const workspace = $workspaceStore
|
||||
const workspace = $operatingWorkspace
|
||||
if (!workspace) return
|
||||
let macros: Awaited<ReturnType<typeof listWorkspaceMacrosCached>> = []
|
||||
try {
|
||||
@@ -739,7 +741,7 @@
|
||||
provideCompletionItems: async function (model, position) {
|
||||
// Read the store per request, not at registration — the provider
|
||||
// outlives a workspace switch.
|
||||
const workspace = $workspaceStore
|
||||
const workspace = $operatingWorkspace
|
||||
if (!workspace) return { suggestions: [] }
|
||||
const before = model.getLineContent(position.lineNumber).slice(0, position.column - 1)
|
||||
if (!/^\s*(\/\/|--|#)\s*(column|data_test|on|materialize)\b/.test(before)) {
|
||||
@@ -780,7 +782,7 @@
|
||||
$dbSchemas[resourcePath] = await getDbSchemas(
|
||||
lang === 'graphql' ? 'graphql' : (scriptLang ?? ''),
|
||||
resourcePath,
|
||||
$workspaceStore,
|
||||
$operatingWorkspace,
|
||||
(e) => console.error(`error getting ${lang} (${scriptLang}) db schema`, e),
|
||||
{ customTag }
|
||||
)
|
||||
@@ -1778,9 +1780,9 @@
|
||||
let customTsTypesData = resource([() => lang], async () => {
|
||||
if (lang !== 'typescript') return undefined
|
||||
let datatables = (
|
||||
await WorkspaceService.listDataTables({ workspace: $workspaceStore ?? '' })
|
||||
await WorkspaceService.listDataTables({ workspace: $operatingWorkspace ?? '' })
|
||||
).map((d) => d.name)
|
||||
let ducklakes = await WorkspaceService.listDucklakes({ workspace: $workspaceStore ?? '' })
|
||||
let ducklakes = await WorkspaceService.listDucklakes({ workspace: $operatingWorkspace ?? '' })
|
||||
return { datatables, ducklakes }
|
||||
})
|
||||
function setTypescriptCustomTypes() {
|
||||
@@ -1822,7 +1824,7 @@
|
||||
scriptLang === 'nativets')
|
||||
) {
|
||||
const resourceTypes = await ResourceService.listResourceType({
|
||||
workspace: $workspaceStore ?? ''
|
||||
workspace: $operatingWorkspace ?? ''
|
||||
})
|
||||
|
||||
const namespace = formatResourceTypes(
|
||||
@@ -2023,7 +2025,7 @@
|
||||
$lspTokenStore = newToken
|
||||
token = newToken
|
||||
}
|
||||
let root = hostname + '/api/scripts_u/tokened_raw/' + $workspaceStore + '/' + token
|
||||
let root = hostname + '/api/scripts_u/tokened_raw/' + $operatingWorkspace + '/' + token
|
||||
return root
|
||||
}
|
||||
|
||||
@@ -2274,10 +2276,10 @@
|
||||
|
||||
<svelte:window onkeydown={onKeyDown} />
|
||||
<EditorTheme />
|
||||
{#if datatableForMigrations && $workspaceStore}
|
||||
{#if datatableForMigrations && $operatingWorkspace}
|
||||
<DdlMigrationGuard
|
||||
bind:this={ddlGuard}
|
||||
workspace={$workspaceStore}
|
||||
workspace={$operatingWorkspace}
|
||||
datatable={datatableForMigrations}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService, VariableService, WorkspaceService, type Script } from '$lib/gen'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import type Editor from './Editor.svelte'
|
||||
import ItemPicker from './ItemPicker.svelte'
|
||||
@@ -76,6 +75,9 @@
|
||||
import FlowInlineScriptAiButton from './copilot/FlowInlineScriptAIButton.svelte'
|
||||
import GitRepoPopoverPicker from './GitRepoPopoverPicker.svelte'
|
||||
import { insertDelegateToGitRepoInCode } from '$lib/ansibleUtils'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
lang: SupportedLanguage | 'bunnative' | undefined
|
||||
@@ -121,9 +123,8 @@
|
||||
right?: import('svelte').Snippet
|
||||
openAiChat?: boolean
|
||||
moduleId?: string
|
||||
// Workspace to scope variable/resource/data-table lookups to. Defaults to
|
||||
// the nav `$workspaceStore`; an AI-session live editor passes the session's
|
||||
// acting workspace (a fork) so the helper pickers hit the right workspace.
|
||||
// Workspace to scope variable/resource/data-table lookups to. Defaults to the
|
||||
// operating workspace (see `useOperatingWorkspace`).
|
||||
workspace?: string
|
||||
}
|
||||
|
||||
@@ -153,7 +154,7 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let contextualVariablePicker: ItemPicker | undefined = $state()
|
||||
let variablePicker: ItemPicker | undefined = $state()
|
||||
|
||||
@@ -15,7 +15,15 @@
|
||||
} from '$lib/components/workspacePicker'
|
||||
import BreadcrumbSegment from '$lib/components/BreadcrumbSegment.svelte'
|
||||
import { isOwner } from '$lib/utils'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { userStore } from '$lib/stores'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
interface Props {
|
||||
summary?: string
|
||||
@@ -47,9 +55,8 @@
|
||||
* dropped, leaving only the summary. Used by the condensed session-
|
||||
* preview top bar to save vertical room. */
|
||||
hidePath?: boolean
|
||||
/** Workspace whose items the breadcrumb picker lists. Session live
|
||||
* editors pass their acting workspace so the picker isn't scoped to the
|
||||
* navigation workspace; falls back to $workspaceStore in the picker. */
|
||||
/** Workspace whose items the breadcrumb picker lists; defaults to the operating
|
||||
* workspace (see `useOperatingWorkspace`). */
|
||||
workspaceId?: string
|
||||
}
|
||||
|
||||
@@ -116,7 +123,7 @@
|
||||
// Treat an empty path as ownable so the pen popover lets a user pick the
|
||||
// path for a brand-new item. `Path.reset()` then synthesizes a default
|
||||
// under their own user/folder scope.
|
||||
let own = $derived(!path || isOwner(path, $userStore, $workspaceStore))
|
||||
let own = $derived(!path || isOwner(path, actingUser, $operatingWorkspace))
|
||||
|
||||
// Virtual entry for the picker: surfaces the currently-edited item at its
|
||||
// live path (which may differ from `savedPath` mid-rename, so the picker
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
import type { Schema, SupportedLanguage } from '$lib/common'
|
||||
import { base } from '$lib/base'
|
||||
import { enterpriseLicense, workspaceStore } from '$lib/stores'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import MsTeamsIcon from '$lib/components/icons/MSTeamsIcon.svelte'
|
||||
import { classNames, emptySchema, emptyString, sendUserToast, tryEvery } from '$lib/utils'
|
||||
import MultiSelect from '$lib/components/select/MultiSelect.svelte'
|
||||
@@ -61,6 +61,9 @@
|
||||
import SmtpConfigurationStatus from './common/smtp/SmtpConfigurationStatus.svelte'
|
||||
import { SettingService } from '$lib/gen'
|
||||
import { isSmtpSettingsValid } from './instanceSettings/SmtpSettings.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
const slackRecoveryHandler = hubPaths.slackRecoveryHandler
|
||||
const slackHandlerScriptPath = hubPaths.slackErrorHandler
|
||||
@@ -81,9 +84,8 @@
|
||||
customHandlerKind?: 'flow' | 'script'
|
||||
customTabTooltip?: import('svelte').Snippet
|
||||
noMargin?: boolean
|
||||
/** Workspace for handler lookup / settings / test jobs. Defaults to the
|
||||
* nav `$workspaceStore`; a trigger editor in a forked session passes its
|
||||
* acting workspace so the handler is resolved and saved there. */
|
||||
/** Workspace for handler lookup / settings / test jobs. Defaults to the operating
|
||||
* workspace (see `useOperatingWorkspace`). */
|
||||
workspace?: string
|
||||
/** Offer the instance critical alert channels as a destination. Workspace-level
|
||||
* error handling only: schedules and triggers have no such setting. */
|
||||
@@ -106,13 +108,12 @@
|
||||
showInstanceAlerts = false
|
||||
}: Props = $props()
|
||||
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore)
|
||||
// Carry the acting workspace onto the "create from template" route when an
|
||||
// explicit override is set, so a forked session creates the handler script
|
||||
// there. `customScriptTemplate` already has a query string (`?hub=…`).
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace)
|
||||
// Carry the workspace onto the "create from template" route, so the handler script is
|
||||
// created where this handler is saved. `customScriptTemplate` already has a query string.
|
||||
let templateHref = $derived(
|
||||
workspace
|
||||
? `${customScriptTemplate}&workspace=${encodeURIComponent(workspace)}`
|
||||
effectiveWorkspace
|
||||
? `${customScriptTemplate}&workspace=${encodeURIComponent(effectiveWorkspace)}`
|
||||
: customScriptTemplate
|
||||
)
|
||||
|
||||
|
||||
@@ -33,15 +33,18 @@
|
||||
import { Button, ButtonType } from '$lib/components/common'
|
||||
import S3FilePicker from '$lib/components/S3FilePicker.svelte'
|
||||
import { VolumeService } from '$lib/gen'
|
||||
import {
|
||||
globalDbManagerDrawer,
|
||||
globalS3FilePickerExplorer,
|
||||
userStore,
|
||||
workspaceStore
|
||||
} from '$lib/stores'
|
||||
import { globalDbManagerDrawer, globalS3FilePickerExplorer } from '$lib/stores'
|
||||
import { isS3Uri } from '$lib/utils'
|
||||
import { Database, File, HardDriveIcon } from 'lucide-svelte'
|
||||
import DucklakeIcon from './icons/DucklakeIcon.svelte'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
const {
|
||||
asset,
|
||||
@@ -69,7 +72,7 @@
|
||||
} = $props()
|
||||
|
||||
let dbManagerDrawer = $derived(globalDbManagerDrawer.val)
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
const assetUri = $derived(formatAsset(asset))
|
||||
// Contexts with a select/upload flow pass their own picker; everything else
|
||||
// (e.g. the resources list) falls back to the global read-only explorer.
|
||||
@@ -80,7 +83,7 @@
|
||||
</script>
|
||||
|
||||
<Button
|
||||
disabled={$userStore?.operator || disabled}
|
||||
disabled={actingUser?.operator || disabled}
|
||||
unifiedSize={'md'}
|
||||
variant={buttonVariant}
|
||||
wrapperClasses={className}
|
||||
|
||||
@@ -17,13 +17,7 @@
|
||||
linkedAgentToolsVersion,
|
||||
migrateLinkedAgentToolsScope
|
||||
} from '$lib/components/flows/linkedAgentToolsStore.svelte'
|
||||
import {
|
||||
enterpriseLicense,
|
||||
userStore,
|
||||
userWorkspaces,
|
||||
workspaceStore,
|
||||
usedTriggerKinds
|
||||
} from '$lib/stores'
|
||||
import { enterpriseLicense, userStore, userWorkspaces, usedTriggerKinds } from '$lib/stores'
|
||||
import {
|
||||
generateRandomString,
|
||||
orderedJsonStringify,
|
||||
@@ -111,6 +105,14 @@
|
||||
import { UserDraft } from '$lib/userDraft.svelte'
|
||||
import { setOpenInSessionHandoff } from './sessions/openInSessionContext'
|
||||
import { getEditorStoragePath, setEditorStoragePath } from './editorStoragePathContext'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
let {
|
||||
initialPath = $bindable(''),
|
||||
@@ -158,9 +160,9 @@
|
||||
// and the AutosaveIndicator all target it. Falls back to the global store, so
|
||||
// the full-page editor is unchanged; the sessions preview overrides it to the
|
||||
// session's (forked) workspace, so an embedded editor acts on the session's
|
||||
// fork rather than the navigation workspace ($workspaceStore, which stays put).
|
||||
// fork rather than the navigation workspace (`workspaceStore`, which stays put).
|
||||
// indicatorPath is the matching draft path.
|
||||
const opWorkspace = $derived(autosaveWorkspace ?? $workspaceStore)
|
||||
const opWorkspace = $derived(autosaveWorkspace ?? $operatingWorkspace)
|
||||
const indicatorPath = $derived(autosavePath ?? liveEditorDraftStoragePath)
|
||||
|
||||
let initialPathStore = writable(initialPath)
|
||||
@@ -607,7 +609,7 @@
|
||||
await deployTriggers(
|
||||
triggersToDeploy,
|
||||
opWorkspace,
|
||||
!!$userStore?.is_admin || !!$userStore?.is_super_admin,
|
||||
!!actingUser?.is_admin || !!actingUser?.is_super_admin,
|
||||
usedTriggerKinds,
|
||||
$pathStore,
|
||||
true
|
||||
@@ -618,7 +620,7 @@
|
||||
await deployTriggers(
|
||||
triggersToDeploy,
|
||||
opWorkspace,
|
||||
!!$userStore?.is_admin || !!$userStore?.is_super_admin,
|
||||
!!actingUser?.is_admin || !!actingUser?.is_super_admin,
|
||||
usedTriggerKinds,
|
||||
initialPath
|
||||
)
|
||||
@@ -1394,7 +1396,7 @@
|
||||
<AIChangesWarningModal bind:open={aiChangesWarningOpen} onConfirm={aiChangesConfirmCallback} />
|
||||
|
||||
{#key renderCount}
|
||||
{#if !$userStore?.operator}
|
||||
{#if !actingUser?.operator}
|
||||
{#if $pathStore}
|
||||
<FlowHistory bind:this={flowHistory} path={$pathStore} {onHistoryRestore} />
|
||||
{/if}
|
||||
|
||||
@@ -10,10 +10,12 @@
|
||||
import FlowGraphViewerStep from './FlowGraphViewerStep.svelte'
|
||||
import FlowGraphV2 from './graph/FlowGraphV2.svelte'
|
||||
import { dfs } from './flows/dfs'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { untrack } from 'svelte'
|
||||
import { publishLinkedAgentTools } from './flows/flowState'
|
||||
import { linkedToolsScope } from './flows/linkedAgentToolsStore.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
flow: {
|
||||
@@ -45,7 +47,7 @@
|
||||
noGraph = false,
|
||||
triggerNode = false,
|
||||
stepDetail = $bindable(undefined),
|
||||
workspace = $workspaceStore,
|
||||
workspace = $operatingWorkspace,
|
||||
minHeight = 400,
|
||||
noBorder = false,
|
||||
hideDefaultInputs = false,
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import SchemaViewer from './SchemaViewer.svelte'
|
||||
import { scriptPathToHref } from '$lib/scripts'
|
||||
import { cleanExpr, copyToClipboard } from '$lib/utils'
|
||||
import { hubBaseUrlStore, workspaceStore } from '$lib/stores'
|
||||
import { hubBaseUrlStore } from '$lib/stores'
|
||||
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import FlowModuleScript from './flows/content/FlowModuleScript.svelte'
|
||||
@@ -20,6 +20,9 @@
|
||||
import HighlightTheme from './HighlightTheme.svelte'
|
||||
import LanguageIcon from './common/languageIcons/LanguageIcon.svelte'
|
||||
import FlowGraphViewerStepHeader from './FlowGraphViewerStepHeader.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
schema?: any | undefined
|
||||
@@ -41,7 +44,7 @@
|
||||
workspace = undefined,
|
||||
onBack = undefined
|
||||
}: Props = $props()
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
let codeViewer: Drawer | undefined = $state()
|
||||
</script>
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import PopoverV2 from '$lib/components/meltComponents/Popover.svelte'
|
||||
import HistoricInputs from './HistoricInputs.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { JobService } from '$lib/gen'
|
||||
import { Button } from './common'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
path: string
|
||||
@@ -27,7 +29,7 @@
|
||||
async function loadInitial() {
|
||||
loading = true
|
||||
let jobs = await JobService.listJobs({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
scriptPathExact: path,
|
||||
jobKinds: ['flow', 'flowpreview'].join(','),
|
||||
perPage: 1
|
||||
@@ -43,7 +45,7 @@
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if ($workspaceStore && !newFlow) {
|
||||
if ($operatingWorkspace && !newFlow) {
|
||||
untrack(() => loadInitial())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
Keyboard
|
||||
} from 'lucide-svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import ObjectViewer from './propertyPicker/ObjectViewer.svelte'
|
||||
import LogViewer from './LogViewer.svelte'
|
||||
import FlowLogViewer from './FlowLogViewer.svelte'
|
||||
@@ -26,6 +25,9 @@
|
||||
import { Tooltip } from './meltComponents'
|
||||
import FlowTimelineBar from './FlowTimelineBar.svelte'
|
||||
import { getActiveReplay } from './recording/replay.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
type RootJobData = Partial<Job>
|
||||
|
||||
@@ -96,7 +98,7 @@
|
||||
|
||||
function getJobLink(jobId: string | undefined): string {
|
||||
if (!jobId) return ''
|
||||
return `${base}/run/${jobId}?workspace=${workspaceId ?? $workspaceStore}`
|
||||
return `${base}/run/${jobId}?workspace=${workspaceId ?? $operatingWorkspace}`
|
||||
}
|
||||
|
||||
function getStatusColor(status: FlowStatusModule['type'] | undefined): string {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { type Job, JobService, type FlowModule, type RestartedFrom } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Button } from './common'
|
||||
import { createEventDispatcher, getContext } from 'svelte'
|
||||
import type { FlowEditorContext } from './flows/types'
|
||||
@@ -11,6 +10,9 @@
|
||||
import FlowProgressBar from './flows/FlowProgressBar.svelte'
|
||||
import { CornerDownLeft, Play, RefreshCw, X } from 'lucide-svelte'
|
||||
import type { Schema } from '$lib/common'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
open: boolean
|
||||
@@ -165,7 +167,7 @@
|
||||
try {
|
||||
jobId &&
|
||||
(await JobService.cancelQueuedJob({
|
||||
workspace: opWorkspace?.() ?? $workspaceStore ?? '',
|
||||
workspace: opWorkspace?.() ?? $operatingWorkspace ?? '',
|
||||
id: jobId,
|
||||
requestBody: {}
|
||||
}))
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
type OpenFlow,
|
||||
type ScriptLang
|
||||
} from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Badge, Button } from './common'
|
||||
import { createEventDispatcher, getContext, untrack } from 'svelte'
|
||||
import type { FlowEditorContext } from './flows/types'
|
||||
@@ -44,6 +43,9 @@
|
||||
import FlowRestartButton from './FlowRestartButton.svelte'
|
||||
import { useNestedRestartState } from './useNestedRestartState.svelte'
|
||||
import { buildFlowRecording, downloadRecordingJson } from './recording/runRecording'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
previewMode: 'upTo' | 'whole'
|
||||
@@ -138,7 +140,7 @@
|
||||
opWorkspace
|
||||
} = $state(getContext<FlowEditorContext>('FlowEditorContext'))
|
||||
// Acting workspace when previewing inside an AI session; else the nav workspace.
|
||||
let opWs = $derived(opWorkspace?.() ?? $workspaceStore)
|
||||
let opWs = $derived(opWorkspace?.() ?? $operatingWorkspace)
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let renderCount: number = $state(0)
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
import Popover from './meltComponents/Popover.svelte'
|
||||
import { Play, RefreshCw } from 'lucide-svelte'
|
||||
import { FlowService, JobService, type FlowVersion } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
import { emptyString, sendUserToast } from '$lib/utils'
|
||||
|
||||
interface Props {
|
||||
@@ -166,7 +168,7 @@
|
||||
flow_version: flowVersion
|
||||
}
|
||||
let run = await JobService.restartFlowAtStep({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
id: jobId,
|
||||
requestBody
|
||||
})
|
||||
@@ -178,7 +180,7 @@
|
||||
loadingVersions = true
|
||||
try {
|
||||
flowVersions = await FlowService.getFlowHistory({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
path: flowPath
|
||||
})
|
||||
if (flowVersions.length > 0) {
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
import { setContext, untrack } from 'svelte'
|
||||
import type { DurationStatus, FlowStatusViewerContext, GraphModuleState } from './graph'
|
||||
import { isOwner as loadIsOwner, type StateStore } from '$lib/utils'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { userStore } from '$lib/stores'
|
||||
import type { CompletedJob, FlowModule, FlowNote, FlowValue, Job } from '$lib/gen'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
jobId: string
|
||||
@@ -98,7 +101,7 @@
|
||||
})
|
||||
|
||||
function loadOwner(path: string) {
|
||||
isOwner = loadIsOwner(path, $userStore!, workspaceId ?? $workspaceStore!)
|
||||
isOwner = loadIsOwner(path, $userStore!, workspaceId ?? $operatingWorkspace!)
|
||||
}
|
||||
|
||||
async function updateJobId() {
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
type FlowNote,
|
||||
type FlowValue
|
||||
} from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import FlowJobResult from './FlowJobResult.svelte'
|
||||
import WorkflowTimeline from './WorkflowTimeline.svelte'
|
||||
@@ -69,6 +68,9 @@
|
||||
releaseLinkedToolsScope,
|
||||
retainLinkedToolsScope
|
||||
} from './flows/linkedAgentToolsStore.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
let {
|
||||
flowState: flowStateStore,
|
||||
@@ -168,7 +170,7 @@
|
||||
isSubflow = false,
|
||||
reducedPolling = false,
|
||||
wideResults = false,
|
||||
workspace = $workspaceStore,
|
||||
workspace = $operatingWorkspace,
|
||||
prefix = undefined,
|
||||
topModuleStates = undefined,
|
||||
refreshGlobal,
|
||||
@@ -242,7 +244,7 @@
|
||||
resourceMetadataCache[asset.path] = undefined
|
||||
if (!isReplay) {
|
||||
ResourceService.getResource({
|
||||
workspace: workspace ?? $workspaceStore!,
|
||||
workspace: workspace ?? $operatingWorkspace!,
|
||||
path: asset.path
|
||||
})
|
||||
.then((r) => (resourceMetadataCache[asset.path] = r))
|
||||
@@ -278,7 +280,7 @@
|
||||
// resolving in the navigation one finds nothing, or an unrelated resource sharing the path. The
|
||||
// store scope stays keyed on `workspace` to match what FlowGraphV2 reads — the job id in the key
|
||||
// already makes the bucket unique.
|
||||
let agentFetchWorkspace = $derived(workspaceId ?? job?.workspace_id ?? $workspaceStore)
|
||||
let agentFetchWorkspace = $derived(workspaceId ?? job?.workspace_id ?? $operatingWorkspace)
|
||||
// Hold this scope for as long as the viewer is mounted, so the store's cap can't drop tools the
|
||||
// run still needs (nothing would refetch them — the set of linked steps hasn't changed).
|
||||
$effect(() => {
|
||||
@@ -627,7 +629,7 @@
|
||||
) {
|
||||
if (!isReplay) {
|
||||
JobService.getJob({
|
||||
workspace: workspaceId ?? $workspaceStore ?? '',
|
||||
workspace: workspaceId ?? $operatingWorkspace ?? '',
|
||||
id: mod.job ?? '',
|
||||
noLogs: true,
|
||||
noCode: true
|
||||
@@ -722,7 +724,7 @@
|
||||
})
|
||||
if (!isReplay) {
|
||||
JobService.getStartedAtByIds({
|
||||
workspace: workspaceId ?? $workspaceStore ?? '',
|
||||
workspace: workspaceId ?? $operatingWorkspace ?? '',
|
||||
requestBody: missingStartedAtIds
|
||||
})
|
||||
.then((jobs) => {
|
||||
@@ -1569,7 +1571,7 @@
|
||||
let storedJob = storedListJobs[j]
|
||||
if (!storedJob && !isReplay) {
|
||||
storedJob = await JobService.getJob({
|
||||
workspace: workspaceId ?? $workspaceStore ?? '',
|
||||
workspace: workspaceId ?? $operatingWorkspace ?? '',
|
||||
id: loopJobId,
|
||||
noLogs: true,
|
||||
noCode: true
|
||||
@@ -2135,7 +2137,7 @@
|
||||
id={isReplay ? undefined : job.id}
|
||||
workspace={isReplay
|
||||
? undefined
|
||||
: (job.workspace_id ?? $workspaceStore ?? 'no_w')}
|
||||
: (job.workspace_id ?? $operatingWorkspace ?? 'no_w')}
|
||||
args={job.args}
|
||||
/>
|
||||
{:else}
|
||||
@@ -2202,7 +2204,7 @@
|
||||
id={isReplay ? undefined : node.job_id}
|
||||
workspace={isReplay
|
||||
? undefined
|
||||
: (job.workspace_id ?? $workspaceStore ?? 'no_w')}
|
||||
: (job.workspace_id ?? $operatingWorkspace ?? 'no_w')}
|
||||
args={node.args}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { cleanValueProperties, replaceFalseWithUndefined } from '$lib/utils'
|
||||
import { orderedYamlStringify } from '$lib/utils/orderedYaml'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { watch } from 'runed'
|
||||
|
||||
import HighlightTheme from './HighlightTheme.svelte'
|
||||
import FlowViewerInner from './FlowViewerInner.svelte'
|
||||
import FlowInputViewer from './FlowInputViewer.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface PreviousFlow {
|
||||
summary: string
|
||||
@@ -86,7 +88,7 @@
|
||||
return
|
||||
}
|
||||
previousFlow = await FlowService.getFlowVersion({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
version
|
||||
})
|
||||
previousFlowCache[version] = previousFlow
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
import {
|
||||
type Folder,
|
||||
type FolderDefaultPermissionedAs,
|
||||
@@ -89,8 +90,12 @@
|
||||
workspace
|
||||
}: Props = $props()
|
||||
|
||||
const targetWorkspace = $derived(workspace ?? $workspaceStore ?? '')
|
||||
const aimedElsewhere = $derived(!!workspace && workspace !== $workspaceStore)
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const targetWorkspace = $derived(workspace ?? $operatingWorkspace ?? '')
|
||||
const aimedElsewhere = $derived(!!targetWorkspace && targetWorkspace !== $workspaceStore)
|
||||
// The group editor and permission history act on the operating workspace and take no
|
||||
// workspace of their own, so they can only follow a drawer aimed at that one.
|
||||
const offOperating = $derived(!!targetWorkspace && targetWorkspace !== $operatingWorkspace)
|
||||
|
||||
// `$userStore` describes the workspace the app is *in*. Aimed at another one it answers
|
||||
// the wrong question — a folder admin there would get read-only controls, and a
|
||||
@@ -121,9 +126,9 @@
|
||||
})
|
||||
|
||||
async function loadTargetUser(): Promise<void> {
|
||||
if (!aimedElsewhere || !workspace) return
|
||||
if (!aimedElsewhere) return
|
||||
try {
|
||||
targetUser = await UserService.whoami({ workspace })
|
||||
targetUser = await UserService.whoami({ workspace: targetWorkspace })
|
||||
} catch {
|
||||
// Not a member, or the call failed: no membership means read-only controls,
|
||||
// which is the safe reading — the write would be refused anyway.
|
||||
@@ -551,7 +556,7 @@
|
||||
let loadStarted = false
|
||||
$effect.pre(() => {
|
||||
if (loadStarted) return
|
||||
if ($workspaceStore && $userStore) {
|
||||
if (targetWorkspace && $userStore) {
|
||||
loadStarted = true
|
||||
untrack(() => {
|
||||
load()
|
||||
@@ -675,10 +680,7 @@
|
||||
class="grow min-w-0"
|
||||
>
|
||||
{#snippet endSnippet({ item, close: closeSelect })}
|
||||
<!-- GroupEditor reads and writes `$workspaceStore` and takes no workspace of its
|
||||
own, so it cannot follow a drawer aimed at another one: viewing a group
|
||||
there would edit the same-named group in the active workspace. -->
|
||||
{#if ownerKind == 'group' && !aimedElsewhere}
|
||||
{#if ownerKind == 'group' && !offOperating}
|
||||
<Button
|
||||
title="View group"
|
||||
variant="subtle"
|
||||
@@ -696,7 +698,7 @@
|
||||
{/if}
|
||||
{/snippet}
|
||||
{#snippet bottomSnippet({ close: closeSelect })}
|
||||
{#if ownerKind == 'group' && !aimedElsewhere}
|
||||
{#if ownerKind == 'group' && !offOperating}
|
||||
<Button
|
||||
variant="subtle"
|
||||
unifiedSize="sm"
|
||||
@@ -838,11 +840,9 @@
|
||||
</Cell>
|
||||
<Cell last actions>
|
||||
<div class="flex items-center justify-end">
|
||||
<!-- The group editor reads `$workspaceStore`, so it can only be opened for the
|
||||
workspace the app is in — see the picker's own buttons. It decides on its
|
||||
own whether the group is editable here; a member with no write on it still
|
||||
gets to see who is in it. -->
|
||||
{#if ownerKindOf(perm.owner_name) === 'group' && !aimedElsewhere}
|
||||
<!-- The group editor decides on its own whether the group is editable here; a
|
||||
member with no write on it still gets to see who is in it. -->
|
||||
{#if ownerKindOf(perm.owner_name) === 'group' && !offOperating}
|
||||
<Button
|
||||
title="Manage group"
|
||||
variant="subtle"
|
||||
@@ -1001,9 +1001,7 @@
|
||||
</CollapseLink>
|
||||
{/if}
|
||||
|
||||
<!-- PermissionHistory fetches against `$workspaceStore`; aimed elsewhere it would show
|
||||
another folder's history entirely. -->
|
||||
{#if !isNew && !aimedElsewhere && reloadHistory > 0}
|
||||
{#if !isNew && !offOperating && reloadHistory > 0}
|
||||
{#key reloadHistory}
|
||||
<PermissionHistory
|
||||
{name}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { FolderService, UserService, type User } from '$lib/gen'
|
||||
import { workspaceStore, userStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
import { isDemoWorkspaceRestricted } from '$lib/cloud'
|
||||
import { ChevronDown, Pen, PlusIcon } from 'lucide-svelte'
|
||||
import { Button } from './common'
|
||||
@@ -39,14 +40,15 @@
|
||||
workspace
|
||||
}: Props = $props()
|
||||
|
||||
const targetWorkspace = $derived(workspace ?? $workspaceStore ?? '')
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const targetWorkspace = $derived(workspace ?? $operatingWorkspace ?? '')
|
||||
|
||||
// `$userStore` describes the workspace the app is *in*. When this picker is aimed
|
||||
// somewhere else, those memberships answer the wrong question — and since a folder
|
||||
// without write access renders disabled, a stale answer makes the real folders
|
||||
// unpickable. Resolve the membership for the workspace actually being listed.
|
||||
let targetUser: User | undefined = $state(undefined)
|
||||
const aimedElsewhere = $derived(!!workspace && workspace !== $workspaceStore)
|
||||
const aimedElsewhere = $derived(!!targetWorkspace && targetWorkspace !== $workspaceStore)
|
||||
const membership = $derived(aimedElsewhere ? targetUser : ($userStore ?? undefined))
|
||||
|
||||
const restricted = $derived(
|
||||
@@ -129,9 +131,9 @@
|
||||
}
|
||||
|
||||
async function loadTargetUser(): Promise<void> {
|
||||
if (!workspace || workspace === $workspaceStore) return
|
||||
if (!aimedElsewhere) return
|
||||
try {
|
||||
targetUser = await UserService.whoami({ workspace })
|
||||
targetUser = await UserService.whoami({ workspace: targetWorkspace })
|
||||
} catch {
|
||||
// Not a member, or the call failed: every folder stays read-only, which is
|
||||
// the safe reading — the import would be refused anyway.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { workspaceStore, enterpriseLicense, userStore } from '$lib/stores'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import Popover from './meltComponents/Popover.svelte'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { Loader2, Github, RotateCw, Plus, Minus, Download, AlertTriangle } from 'lucide-svelte'
|
||||
@@ -18,6 +18,14 @@
|
||||
type GitHubAppState
|
||||
} from '$lib/githubApp'
|
||||
import RepositorySelector from './RepositorySelector.svelte'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
interface Props {
|
||||
resourceType: string
|
||||
@@ -70,14 +78,14 @@
|
||||
|
||||
let showGitHubApp = $derived(
|
||||
resourceType === 'git_repository' &&
|
||||
$workspaceStore &&
|
||||
($userStore?.is_admin || $userStore?.is_super_admin)
|
||||
$operatingWorkspace &&
|
||||
(actingUser?.is_admin || actingUser?.is_super_admin)
|
||||
)
|
||||
|
||||
// Load GitHub installations when conditions are met
|
||||
$effect(() => {
|
||||
if (showGitHubApp && $enterpriseLicense && $workspaceStore) {
|
||||
loadGithubInstallations(githubState, $workspaceStore).catch((error) => {
|
||||
if (showGitHubApp && $enterpriseLicense && $operatingWorkspace) {
|
||||
loadGithubInstallations(githubState, $operatingWorkspace).catch((error) => {
|
||||
console.error('Failed to load GitHub installations:', error)
|
||||
})
|
||||
}
|
||||
@@ -113,11 +121,11 @@
|
||||
}
|
||||
|
||||
async function handleDeleteInstallation(installationId: number) {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
|
||||
try {
|
||||
await deleteInstallation($workspaceStore, installationId, () =>
|
||||
loadGithubInstallations(githubState, $workspaceStore!)
|
||||
await deleteInstallation($operatingWorkspace, installationId, () =>
|
||||
loadGithubInstallations(githubState, $operatingWorkspace!)
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Failed to delete installation:', error)
|
||||
@@ -125,11 +133,11 @@
|
||||
}
|
||||
|
||||
async function handleAddInstallation(installationId: number, workspaceId: string) {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
|
||||
try {
|
||||
await addInstallationToWorkspace($workspaceStore, installationId, workspaceId, () =>
|
||||
loadGithubInstallations(githubState, $workspaceStore!)
|
||||
await addInstallationToWorkspace($operatingWorkspace, installationId, workspaceId, () =>
|
||||
loadGithubInstallations(githubState, $operatingWorkspace!)
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Failed to add installation:', error)
|
||||
@@ -137,22 +145,22 @@
|
||||
}
|
||||
|
||||
async function handleExportInstallation(installationId: number) {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
|
||||
try {
|
||||
await exportInstallation($workspaceStore, installationId)
|
||||
await exportInstallation($operatingWorkspace, installationId)
|
||||
} catch (error) {
|
||||
console.error('Failed to export installation:', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleImportInstallation() {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
|
||||
try {
|
||||
await importInstallation($workspaceStore, githubState.importJwt, () => {
|
||||
await importInstallation($operatingWorkspace, githubState.importJwt, () => {
|
||||
githubState.importJwt = ''
|
||||
loadGithubInstallations(githubState, $workspaceStore!)
|
||||
loadGithubInstallations(githubState, $operatingWorkspace!)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Failed to import installation:', error)
|
||||
@@ -160,17 +168,17 @@
|
||||
}
|
||||
|
||||
function handleRefreshInstallations() {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
|
||||
loadGithubInstallations(githubState, $workspaceStore).catch((error) => {
|
||||
loadGithubInstallations(githubState, $operatingWorkspace).catch((error) => {
|
||||
console.error('Failed to refresh installations:', error)
|
||||
})
|
||||
}
|
||||
|
||||
function handleInstallClickWithPopover() {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
|
||||
handleInstallClick(githubState, $workspaceStore, () => {
|
||||
handleInstallClick(githubState, $operatingWorkspace, () => {
|
||||
githubAppPopover?.open()
|
||||
})
|
||||
}
|
||||
@@ -297,9 +305,9 @@
|
||||
target="_blank"
|
||||
disabled={githubState.isCheckingInstallation}
|
||||
on:click={() => {
|
||||
if ($workspaceStore) {
|
||||
startInstallationCheck(githubState, $workspaceStore, () =>
|
||||
loadGithubInstallations(githubState, $workspaceStore!)
|
||||
if ($operatingWorkspace) {
|
||||
startInstallationCheck(githubState, $operatingWorkspace, () =>
|
||||
loadGithubInstallations(githubState, $operatingWorkspace!)
|
||||
)
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { workspaceStore, userStore, enterpriseLicense } from '$lib/stores'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import { GitSyncService, type GitlabProject } from '$lib/gen'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import Popover from './meltComponents/Popover.svelte'
|
||||
@@ -8,6 +8,14 @@
|
||||
import TextInput from './text_input/TextInput.svelte'
|
||||
import Select from './select/Select.svelte'
|
||||
import { GitBranch, Gitlab, Loader2 } from 'lucide-svelte'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
interface Props {
|
||||
resourceType: string
|
||||
@@ -30,7 +38,7 @@
|
||||
onArgsUpdate
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let baseUrl = $state('https://gitlab.com')
|
||||
let token = $state('')
|
||||
@@ -50,7 +58,7 @@
|
||||
let show = $derived(
|
||||
resourceType === 'git_repository' &&
|
||||
!!ws &&
|
||||
($userStore?.is_admin || $userStore?.is_super_admin)
|
||||
(actingUser?.is_admin || actingUser?.is_super_admin)
|
||||
)
|
||||
// The project listing is served by an enterprise-only route, so on a build
|
||||
// without it the form's first request would 404. The button still shows,
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Popover } from './meltComponents'
|
||||
import { GitBranch, Loader2 } from 'lucide-svelte'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
isOpen?: boolean
|
||||
@@ -20,12 +22,12 @@
|
||||
let gitRepoResources = $state<{ path: string; description?: string }[]>([])
|
||||
|
||||
async function loadGitRepoResources() {
|
||||
if (!$workspaceStore || loading) return
|
||||
if (!$operatingWorkspace || loading) return
|
||||
|
||||
loading = true
|
||||
try {
|
||||
const resources = await ResourceService.listResource({
|
||||
workspace: $workspaceStore,
|
||||
workspace: $operatingWorkspace,
|
||||
resourceType: 'git_repository'
|
||||
})
|
||||
|
||||
@@ -39,7 +41,7 @@
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if (isOpen && $workspaceStore) {
|
||||
if (isOpen && $operatingWorkspace) {
|
||||
untrack(() => loadGitRepoResources())
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { HelpersService, ResourceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Button, Drawer, DrawerContent } from './common'
|
||||
import { GitBranch, Loader2, FolderOpen } from 'lucide-svelte'
|
||||
import Select from './select/Select.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
open: boolean
|
||||
@@ -27,7 +29,7 @@
|
||||
workspace: workspaceProp = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspaceProp ?? $workspaceStore)
|
||||
let ws = $derived(workspaceProp ?? $operatingWorkspace)
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
selected: {
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
import { untrack } from 'svelte'
|
||||
import { Alert, Button } from './common'
|
||||
import S3FilePickerInner from './S3FilePickerInner.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { Loader, Loader2, ChevronDown, ChevronRight, ExternalLink } from 'lucide-svelte'
|
||||
import { hubPaths } from '$lib/hub'
|
||||
import { sleep } from '$lib/utils'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
const CLONE_MARKER_FILE = '.windmill_clone_complete'
|
||||
const POLL_INTERVAL_MS = 1500
|
||||
@@ -42,7 +44,7 @@
|
||||
workspace: workspaceProp = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspaceProp ?? $workspaceStore)
|
||||
let ws = $derived(workspaceProp ?? $operatingWorkspace)
|
||||
|
||||
let commitHash = $derived(commitHashInput)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
type Group,
|
||||
type InstanceGroup
|
||||
} from '$lib/gen'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { onMount, tick, untrack } from 'svelte'
|
||||
import { Button } from './common'
|
||||
import Skeleton from './common/skeleton/Skeleton.svelte'
|
||||
@@ -34,6 +34,14 @@
|
||||
type GroupDraft,
|
||||
type GroupRole
|
||||
} from '$lib/groupDraft'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
const ROLE_TOOLTIPS = {
|
||||
member:
|
||||
@@ -74,10 +82,18 @@
|
||||
}: Props = $props()
|
||||
|
||||
const restricted = $derived(
|
||||
isDemoWorkspaceRestricted($workspaceStore, $userStore?.is_admin, $userStore?.is_super_admin)
|
||||
isDemoWorkspaceRestricted($operatingWorkspace, actingUser?.is_admin, actingUser?.is_super_admin)
|
||||
)
|
||||
|
||||
let can_write = $state(false)
|
||||
let groupPerms = $state<Record<string, boolean> | undefined>(undefined)
|
||||
// A verdict that does not come from a loaded group: a new one is writable, one that failed
|
||||
// to load is not.
|
||||
let writeVerdict = $state<boolean | undefined>(undefined)
|
||||
// Derived for the same reason as the trigger editors: the acting user's role can land after
|
||||
// the group does, and a snapshot taken first would stay read-only.
|
||||
const can_write = $derived(
|
||||
writeVerdict ?? (groupPerms !== undefined && canWrite(name, groupPerms, actingUser))
|
||||
)
|
||||
let group: Group | undefined
|
||||
let instance_group: InstanceGroup | undefined = $state()
|
||||
let usernames: string[] = $state([])
|
||||
@@ -123,11 +139,11 @@
|
||||
}
|
||||
|
||||
async function loadUsernames(): Promise<void> {
|
||||
usernames = await UserService.listUsernames({ workspace: $workspaceStore! })
|
||||
usernames = await UserService.listUsernames({ workspace: $operatingWorkspace! })
|
||||
}
|
||||
|
||||
async function loadGroupNames(): Promise<void> {
|
||||
groupNames = (await GroupService.listGroupNames({ workspace: $workspaceStore! })) ?? []
|
||||
groupNames = (await GroupService.listGroupNames({ workspace: $operatingWorkspace! })) ?? []
|
||||
}
|
||||
|
||||
async function loadInstanceGroup(): Promise<void> {
|
||||
@@ -142,7 +158,7 @@
|
||||
loadAside(loadUsernames)
|
||||
if (isNew) {
|
||||
loadAside(loadGroupNames)
|
||||
can_write = true
|
||||
writeVerdict = true
|
||||
setDraft(emptyDraft())
|
||||
loaded = true
|
||||
} else {
|
||||
@@ -159,8 +175,9 @@
|
||||
const apply = (value: GroupDraft) =>
|
||||
opts?.baselineOnly ? (baseline = structuredClone(value)) : setDraft(value)
|
||||
try {
|
||||
group = await GroupService.getGroup({ workspace: $workspaceStore!, name })
|
||||
can_write = canWrite(name, group.extra_perms ?? {}, $userStore)
|
||||
group = await GroupService.getGroup({ workspace: $operatingWorkspace!, name })
|
||||
groupPerms = group.extra_perms ?? {}
|
||||
writeVerdict = undefined
|
||||
apply({
|
||||
summary: group.summary ?? '',
|
||||
members: Array.from(
|
||||
@@ -179,7 +196,7 @@
|
||||
sendUserToast(e?.body ?? String(e), true)
|
||||
// Only the opening read decides this. Revoking it on a failed reconcile would
|
||||
// disable Save against a draft that is still dirty, with nothing left to reload.
|
||||
if (!opts?.baselineOnly) can_write = false
|
||||
if (!opts?.baselineOnly) writeVerdict = false
|
||||
} finally {
|
||||
loaded = true
|
||||
}
|
||||
@@ -245,7 +262,7 @@
|
||||
* membership goes through the endpoints that name who was added or promoted — which is
|
||||
* what the permission history reads back. The diff itself is in `groupDraft.ts`. */
|
||||
async function applyMemberChanges(next: GroupDraft['members'], prev: GroupDraft['members']) {
|
||||
const workspace = $workspaceStore ?? ''
|
||||
const workspace = $operatingWorkspace ?? ''
|
||||
for (const call of groupMemberDiff(prev, next, $userStore?.username)) {
|
||||
switch (call.kind) {
|
||||
case 'addUser':
|
||||
@@ -289,7 +306,7 @@
|
||||
try {
|
||||
if (created) {
|
||||
await GroupService.createGroup({
|
||||
workspace: $workspaceStore ?? '',
|
||||
workspace: $operatingWorkspace ?? '',
|
||||
requestBody: { name, summary: next.summary }
|
||||
})
|
||||
alreadyCreated = true
|
||||
@@ -299,7 +316,7 @@
|
||||
} else {
|
||||
if (next.summary !== prev.summary) {
|
||||
await GroupService.updateGroup({
|
||||
workspace: $workspaceStore ?? '',
|
||||
workspace: $operatingWorkspace ?? '',
|
||||
name,
|
||||
requestBody: { summary: next.summary }
|
||||
})
|
||||
@@ -335,7 +352,7 @@
|
||||
let loadStarted = false
|
||||
$effect.pre(() => {
|
||||
if (loadStarted) return
|
||||
if ($workspaceStore && $userStore) {
|
||||
if ($operatingWorkspace && $userStore) {
|
||||
loadStarted = true
|
||||
untrack(() => {
|
||||
load()
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
import { DataTable } from '$lib/components/table'
|
||||
import HistoricList from './HistoricList.svelte'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
runnableId?: string | undefined
|
||||
@@ -32,7 +34,7 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let historicList: HistoricList | undefined = $state(undefined)
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { InputService, type RunnableType } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { onDestroy, untrack } from 'svelte'
|
||||
import InfiniteList from './InfiniteList.svelte'
|
||||
import JobSchemaPicker from './schema/JobSchemaPicker.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
runnableId: string | undefined
|
||||
@@ -52,7 +54,7 @@
|
||||
refreshInterval()
|
||||
loadInputsPageFn = async (page: number, perPage: number) => {
|
||||
const inputs = await InputService.getInputHistory({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
runnableId,
|
||||
runnableType,
|
||||
page,
|
||||
@@ -109,7 +111,7 @@
|
||||
if (!id) return
|
||||
const payloadData = await InputService.getArgsFromHistoryOrSavedInput({
|
||||
jobOrInputId: id,
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
input,
|
||||
allowLarge
|
||||
})
|
||||
@@ -122,7 +124,11 @@
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
$workspaceStore && runnableId && runnableType && infiniteList && untrack(() => initLoadInputs())
|
||||
$operatingWorkspace &&
|
||||
runnableId &&
|
||||
runnableType &&
|
||||
infiniteList &&
|
||||
untrack(() => initLoadInputs())
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { VariableService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { watch } from 'runed'
|
||||
import { Plus } from 'lucide-svelte'
|
||||
import { Button } from './common'
|
||||
import ItemPicker from './ItemPicker.svelte'
|
||||
import VariableEditor from './VariableEditor.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
/** The transforms being edited. A picked variable is written into `pickForField`'s. */
|
||||
@@ -26,7 +28,7 @@
|
||||
variableEditor = $bindable()
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
watch(
|
||||
() => ws,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { Schema } from '$lib/common'
|
||||
import { type InputTransform } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { allTrue, type DynamicInput as DynamicInputTypes } from '$lib/utils'
|
||||
import { untrack } from 'svelte'
|
||||
import StepInputsGen from './copilot/StepInputsGen.svelte'
|
||||
@@ -12,6 +11,9 @@
|
||||
import type ItemPicker from './ItemPicker.svelte'
|
||||
import type VariableEditor from './VariableEditor.svelte'
|
||||
import ResizeTransitionWrapper from './common/ResizeTransitionWrapper.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
schema: Schema | { properties?: Record<string, any> }
|
||||
@@ -54,7 +56,7 @@
|
||||
workspace
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let inputCheck: { [id: string]: boolean } = $state({})
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
type WorkflowStatus,
|
||||
type OpenFlow
|
||||
} from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { getViewToken } from '$lib/viewToken'
|
||||
import { WM_LOGS_SKIPPED } from '$lib/consts'
|
||||
import { getContext, onDestroy, tick, untrack } from 'svelte'
|
||||
@@ -22,6 +21,9 @@
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { DynamicInput, isScriptPreview } from '$lib/utils'
|
||||
import { getActiveReplay, getReplayStartTime } from './recording/replay.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
// Will be set to number if job is not a flow
|
||||
|
||||
@@ -75,7 +77,7 @@
|
||||
children
|
||||
}: Props = $props()
|
||||
|
||||
let workspace = $derived(workspaceOverride ?? $workspaceStore)
|
||||
let workspace = $derived(workspaceOverride ?? $operatingWorkspace)
|
||||
|
||||
let syncIteration: number = 0
|
||||
let errorIteration = 0
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Alert, Skeleton } from './common'
|
||||
import { Activity } from 'lucide-svelte'
|
||||
import { JobService } from '$lib/gen'
|
||||
import { msToReadableTime } from '$lib/utils'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
// OTEL SpanKind enum values from opentelemetry-proto/opentelemetry/proto/trace/v1/trace.proto
|
||||
const SpanKind = {
|
||||
@@ -54,14 +56,14 @@
|
||||
})
|
||||
|
||||
async function loadTraces() {
|
||||
if (!$workspaceStore || !jobId) return
|
||||
if (!$operatingWorkspace || !jobId) return
|
||||
|
||||
loading = true
|
||||
error = null
|
||||
|
||||
try {
|
||||
const response = await JobService.getJobOtelTraces({
|
||||
workspace: $workspaceStore,
|
||||
workspace: $operatingWorkspace,
|
||||
id: jobId
|
||||
})
|
||||
traces = response as unknown as OtelSpan[]
|
||||
@@ -123,12 +125,18 @@
|
||||
|
||||
function getKindLabel(kind: number): string {
|
||||
switch (kind) {
|
||||
case SpanKind.INTERNAL: return 'Internal'
|
||||
case SpanKind.SERVER: return 'Server'
|
||||
case SpanKind.CLIENT: return 'Client'
|
||||
case SpanKind.PRODUCER: return 'Producer'
|
||||
case SpanKind.CONSUMER: return 'Consumer'
|
||||
default: return 'Unknown'
|
||||
case SpanKind.INTERNAL:
|
||||
return 'Internal'
|
||||
case SpanKind.SERVER:
|
||||
return 'Server'
|
||||
case SpanKind.CLIENT:
|
||||
return 'Client'
|
||||
case SpanKind.PRODUCER:
|
||||
return 'Producer'
|
||||
case SpanKind.CONSUMER:
|
||||
return 'Consumer'
|
||||
default:
|
||||
return 'Unknown'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,17 +190,15 @@
|
||||
<Activity size={48} class="mb-4 opacity-50" />
|
||||
<p class="text-lg font-medium">No HTTP requests captured</p>
|
||||
<p class="text-sm mt-2">
|
||||
This job did not make any HTTP/HTTPS requests, or HTTP Request Tracing is not enabled in instance settings.
|
||||
This job did not make any HTTP/HTTPS requests, or HTTP Request Tracing is not enabled in
|
||||
instance settings.
|
||||
</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-lg font-semibold">Traces ({traces.length} spans)</h3>
|
||||
<button
|
||||
class="text-sm text-blue-600 hover:underline"
|
||||
onclick={loadTraces}
|
||||
>
|
||||
<button class="text-sm text-blue-600 hover:underline" onclick={loadTraces}>
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
@@ -219,10 +225,7 @@
|
||||
{@const statusCode = span.status?.code ?? 0}
|
||||
|
||||
<div class="hover:bg-surface-hover">
|
||||
<button
|
||||
class="w-full px-4 py-2 text-left"
|
||||
onclick={() => toggleSpan(span.span_id)}
|
||||
>
|
||||
<button class="w-full px-4 py-2 text-left" onclick={() => toggleSpan(span.span_id)}>
|
||||
<div class="grid grid-cols-12 gap-2 items-center">
|
||||
<div class="col-span-4 flex items-center gap-2">
|
||||
<span class="text-xs text-secondary">
|
||||
@@ -293,7 +296,9 @@
|
||||
{#each Object.entries(parsedAttrs) as [key, value]}
|
||||
<div class="flex gap-2">
|
||||
<span class="text-secondary font-medium shrink-0">{key}:</span>
|
||||
<span class="font-mono break-all">{typeof value === 'object' ? JSON.stringify(value) : value}</span>
|
||||
<span class="font-mono break-all"
|
||||
>{typeof value === 'object' ? JSON.stringify(value) : value}</span
|
||||
>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
import Badge from './common/badge/Badge.svelte'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { Plus, Tag, X } from 'lucide-svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
labels: string[] | undefined
|
||||
@@ -53,7 +55,7 @@
|
||||
|
||||
async function loadExistingLabels() {
|
||||
try {
|
||||
const resp = await fetch(`/api/w/${workspace ?? $workspaceStore}/labels/list`)
|
||||
const resp = await fetch(`/api/w/${workspace ?? $operatingWorkspace}/labels/list`)
|
||||
if (resp.ok) existingLabels = await resp.json()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import DarkModeObserver from './DarkModeObserver.svelte'
|
||||
import { Button, Drawer, DrawerContent } from './common'
|
||||
@@ -11,6 +10,9 @@
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import { addResourceTitle } from './resourceTypeDisplay'
|
||||
import { loadResourceTypeDisplayName } from './displayNameLoaders'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
value: string | undefined
|
||||
@@ -35,7 +37,7 @@
|
||||
let open = $state(false)
|
||||
let refreshCount = $state(0)
|
||||
const appViewerContext = getContext<AppViewerContext>('AppViewerContext')
|
||||
let ws = $derived(workspace ?? appViewerContext?.workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? appViewerContext?.workspace ?? $operatingWorkspace)
|
||||
|
||||
let collection = $state(value ? [{ value, label: value }] : [])
|
||||
|
||||
@@ -139,7 +141,7 @@
|
||||
title="App connection"
|
||||
class="w-full h-full"
|
||||
src="{base}/embed_connect?resource_type={resourceType}&workspace={appViewerContext?.workspace ??
|
||||
$workspaceStore}&express=false"
|
||||
$operatingWorkspace}&express=false"
|
||||
/> -->
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
import { withExternalDomain } from '$lib/externalDomain'
|
||||
import { downloadViaClient, shouldDownloadViaClient } from '$lib/utils/downloadFile'
|
||||
import { appendViewToken } from '$lib/viewToken'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { AnsiUp } from 'ansi_up'
|
||||
import NoWorkerWithTagWarning from './runs/NoWorkerWithTagWarning.svelte'
|
||||
import { JobService } from '$lib/gen'
|
||||
@@ -27,6 +26,9 @@
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import QueuePosition from './QueuePosition.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
content: string | undefined
|
||||
@@ -111,7 +113,7 @@
|
||||
const id = jobId
|
||||
fetchedSkippedJobId = id
|
||||
untrack(() => {
|
||||
JobService.getJob({ workspace: $workspaceStore ?? '', id })
|
||||
JobService.getJob({ workspace: $operatingWorkspace ?? '', id })
|
||||
.then((j) => {
|
||||
if (fetchedSkippedJobId === id) {
|
||||
const logs = (j as { logs?: string })['logs'] ?? ''
|
||||
@@ -219,7 +221,7 @@
|
||||
if (downloadStartUrl) {
|
||||
scroll = false
|
||||
let res = (await JobService.getLogFileFromStore({
|
||||
workspace: $workspaceStore ?? '',
|
||||
workspace: $operatingWorkspace ?? '',
|
||||
path: downloadStartUrl
|
||||
})) as string
|
||||
LOG_LIMIT += Math.min(LOG_INC, res.length)
|
||||
@@ -250,7 +252,7 @@
|
||||
fetchedSkippedJobId = undefined
|
||||
}
|
||||
})
|
||||
let logsApiPath = $derived(appendViewToken(`/w/${$workspaceStore}/jobs_u/get_logs/${jobId}`))
|
||||
let logsApiPath = $derived(appendViewToken(`/w/${$operatingWorkspace}/jobs_u/get_logs/${jobId}`))
|
||||
let downloadHref = $derived(withExternalDomain(`${base}/api${logsApiPath}`))
|
||||
let downloadName = $derived(`windmill_logs_${jobId}.txt`)
|
||||
let truncatedContent = $derived(
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
import type SimpleEditor from './SimpleEditor.svelte'
|
||||
import { getResourceTypes } from './resourceTypesStore'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { AGENT_FIELDS, initialVisibleAgentFields } from './flows/agentFormFields'
|
||||
import { openAgentFields } from './flows/content/AiAgentStepInputs.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
schema: Schema | { properties?: Record<string, any>; required?: string[] }
|
||||
@@ -47,7 +49,7 @@
|
||||
const { stepsInputArgs, flowStateStore, flowStore, previewArgs, opWorkspace } =
|
||||
getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
let opWs = $derived(opWorkspace?.() ?? $workspaceStore)
|
||||
let opWs = $derived(opWorkspace?.() ?? $operatingWorkspace)
|
||||
|
||||
let inputCheck: { [id: string]: boolean } = $state({})
|
||||
$effect(() => {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
type JavascriptTransform,
|
||||
type Job
|
||||
} from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { getScriptByPath } from '$lib/scripts'
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import type { FlowEditorContext } from './flows/types'
|
||||
@@ -23,6 +22,9 @@
|
||||
import { AGENT_FLOW_LOCAL_KEYS } from './flows/agentResourceUtils'
|
||||
import { AGENT_HISTORY_KEYS } from './flows/agentFormFields'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
mod: FlowModule
|
||||
@@ -56,7 +58,7 @@
|
||||
let previewBase = $derived($pathStore ?? '')
|
||||
|
||||
// Acting workspace when the flow editor runs in an AI session; else the nav workspace.
|
||||
let opWs = $derived(opWorkspace?.() ?? $workspaceStore)
|
||||
let opWs = $derived(opWorkspace?.() ?? $operatingWorkspace)
|
||||
|
||||
let jobLoader: JobLoader | undefined = $state(undefined)
|
||||
let jobProgressReset: () => void = () => {}
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
import { AppService, HelpersService } from '$lib/gen'
|
||||
import { base } from '$lib/base'
|
||||
import { downloadViaClient, shouldDownloadViaClient } from '$lib/utils/downloadFile'
|
||||
import { enterpriseLicense, workspaceStore } from '$lib/stores'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import { Download } from 'lucide-svelte'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
// import 'ag-grid-community/dist/styles/ag-theme-alpine-dark.css'
|
||||
|
||||
@@ -53,7 +56,7 @@
|
||||
// is set, else the viewer-scoped helpers. Same request/response shape either
|
||||
// way — the only difference is which identity authorizes the S3 read.
|
||||
function loadRowCount(searchCol: string | undefined, searchTerm: string | undefined) {
|
||||
const workspace = workspaceId ?? $workspaceStore!
|
||||
const workspace = workspaceId ?? $operatingWorkspace!
|
||||
return appPath
|
||||
? AppService.appLoadTableCount({
|
||||
workspace,
|
||||
@@ -82,7 +85,7 @@
|
||||
searchTerm?: string
|
||||
csvSeparator?: string
|
||||
}) {
|
||||
const workspace = workspaceId ?? $workspaceStore!
|
||||
const workspace = workspaceId ?? $operatingWorkspace!
|
||||
const csv = s3resource.endsWith('.csv')
|
||||
if (appPath) {
|
||||
const data = {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { VariableService } from '$lib/gen'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { ephemeralSecretPrefix, mintEphemeralSecret } from './secretArgUtils'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { Button } from './common'
|
||||
import Password from './Password.svelte'
|
||||
import { untrack } from 'svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
value?: string | undefined
|
||||
@@ -18,7 +21,7 @@
|
||||
|
||||
let { value = $bindable(undefined), disabled, minRows, workspace }: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let path = $state('')
|
||||
// Workspace the variable at `path` actually lives in; `ws` can move away from it.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
AzureTriggerService,
|
||||
EmailTriggerService
|
||||
} from '$lib/gen'
|
||||
import { superadmin, userStore, workspaceStore, type UserExt } from '$lib/stores'
|
||||
import { superadmin, type UserExt } from '$lib/stores'
|
||||
import { createEventDispatcher, getContext, untrack } from 'svelte'
|
||||
import { writable } from 'svelte/store'
|
||||
import { Alert, Button } from './common'
|
||||
@@ -45,6 +45,15 @@
|
||||
import Select from './select/Select.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import InputError from './InputError.svelte'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace,
|
||||
useOperatingWorkspaceHref
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const operatingHref = useOperatingWorkspaceHref()
|
||||
|
||||
type PathKind =
|
||||
| 'resource'
|
||||
@@ -81,15 +90,12 @@
|
||||
disableEditing?: boolean
|
||||
size?: 'sm' | 'md'
|
||||
drawerOffset?: number
|
||||
/** Workspace the folder list and path-existence checks run against.
|
||||
* Defaults to the navigation `$workspaceStore`; pass the session's acting
|
||||
* workspace when the editor operates on a workspace other than the one the
|
||||
* top nav points at (see the sessions preview / dev-workspace flows). */
|
||||
/** Workspace the folder list and path-existence checks run against. Defaults to the
|
||||
* operating workspace (see `useOperatingWorkspace`). */
|
||||
workspaceOverride?: string
|
||||
/** The user acting in `workspaceOverride`, for the owner suggestion and the folder
|
||||
* write flags. Omit it to stand in the navigation `$userStore`, who is a member of
|
||||
* the navigation workspace only; pass `null` for "not known (yet)", which that user
|
||||
* must not answer for either. */
|
||||
* write flags. Omit it to stand in the user acting in the operating workspace; pass
|
||||
* `null` for "not known (yet)", which no user must answer for. */
|
||||
actingUser?: UserExt | null
|
||||
/** One path that does not count as taken, for a caller creating something that may
|
||||
* already have written there itself — a setup flow correcting its own failed attempt.
|
||||
@@ -121,11 +127,11 @@
|
||||
warnOnRename = true
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspaceOverride ?? $workspaceStore)
|
||||
// Sole place this component falls back to the ambient user, and only for a caller that
|
||||
// passed none; everything below reads `user`, so a caller acting on another workspace is
|
||||
// never mixed with the navigation user's memberships.
|
||||
let user = $derived(actingUser === undefined ? $userStore : (actingUser ?? undefined))
|
||||
let ws = $derived(workspaceOverride ?? $operatingWorkspace)
|
||||
// Sole place this component falls back to an ambient user, and only for a caller that passed
|
||||
// none: the one acting in `ws`, never the navigation user, whose memberships belong to
|
||||
// another workspace. Everything below reads `user`.
|
||||
let user = $derived(actingUser === undefined ? operatingUser.in(ws) : (actingUser ?? undefined))
|
||||
|
||||
$effect.pre(() => {
|
||||
if (path == undefined) {
|
||||
@@ -612,13 +618,13 @@
|
||||
<Tooltip>
|
||||
<ul>
|
||||
{#each scripts || [] as path}
|
||||
<li><a target="_blank" href="/scripts/edit/{path}">{path}</a></li>
|
||||
<li><a target="_blank" href={operatingHref(`/scripts/edit/${path}`)}>{path}</a></li>
|
||||
{/each}
|
||||
{#each flows || [] as path}
|
||||
<li><a target="_blank" href="/flows/edit/{path}">{path}</a></li>
|
||||
<li><a target="_blank" href={operatingHref(`/flows/edit/${path}`)}>{path}</a></li>
|
||||
{/each}
|
||||
{#each apps || [] as path}
|
||||
<li><a target="_blank" href="/apps/edit/{path}">{path}</a></li>
|
||||
<li><a target="_blank" href={operatingHref(`/apps/edit/${path}`)}>{path}</a></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</Tooltip>
|
||||
@@ -632,21 +638,33 @@
|
||||
<ul class="list-disc">
|
||||
{#each scripts || [] as scriptPath}
|
||||
<li>
|
||||
<a href={`/scripts/edit/${scriptPath}`} class="text-blue-400" target="_blank">
|
||||
<a
|
||||
href={operatingHref(`/scripts/edit/${scriptPath}`)}
|
||||
class="text-blue-400"
|
||||
target="_blank"
|
||||
>
|
||||
{scriptPath}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
{#each flows || [] as flowPath}
|
||||
<li>
|
||||
<a href={`/flows/edit/${flowPath}`} class="text-blue-400" target="_blank">
|
||||
<a
|
||||
href={operatingHref(`/flows/edit/${flowPath}`)}
|
||||
class="text-blue-400"
|
||||
target="_blank"
|
||||
>
|
||||
{flowPath}
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
{#each apps || [] as appPath}
|
||||
<li>
|
||||
<a href={`/apps/edit/${appPath}`} class="text-blue-400" target="_blank">
|
||||
<a
|
||||
href={operatingHref(`/apps/edit/${appPath}`)}
|
||||
class="text-blue-400"
|
||||
target="_blank"
|
||||
>
|
||||
{appPath}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -87,7 +87,9 @@
|
||||
<script lang="ts">
|
||||
import TextInput from '$lib/components/text_input/TextInput.svelte'
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
import { untrack } from 'svelte'
|
||||
|
||||
type Props = {
|
||||
@@ -101,9 +103,8 @@
|
||||
error?: string | boolean
|
||||
textInputClass?: string
|
||||
onkeyup?: (e: KeyboardEvent) => void
|
||||
/** Workspace whose paths feed the autocomplete. Defaults to the navigation
|
||||
* `$workspaceStore`; pass the acting workspace when the editor operates on
|
||||
* a workspace other than the one the top nav points at. */
|
||||
/** Workspace whose paths feed the autocomplete. Defaults to the operating workspace
|
||||
* (see `useOperatingWorkspace`). */
|
||||
workspace?: string
|
||||
}
|
||||
|
||||
@@ -121,7 +122,7 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let inputEl: TextInput | undefined = $state(undefined)
|
||||
export function focus() {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { untrack } from 'svelte'
|
||||
import TableCustom from './TableCustom.svelte'
|
||||
import Skeleton from './common/skeleton/Skeleton.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface PermissionChange {
|
||||
id?: number
|
||||
@@ -31,10 +33,10 @@
|
||||
let perPage = $state(50)
|
||||
|
||||
async function loadHistory() {
|
||||
if (!$workspaceStore) return
|
||||
if (!$operatingWorkspace) return
|
||||
loading = true
|
||||
try {
|
||||
history = await fetchHistory($workspaceStore, name, page, perPage)
|
||||
history = await fetchHistory($operatingWorkspace, name, page, perPage)
|
||||
} catch (e) {
|
||||
console.error('Failed to load permission history:', e)
|
||||
history = []
|
||||
@@ -56,7 +58,7 @@
|
||||
}
|
||||
|
||||
$effect.pre(() => {
|
||||
if ($workspaceStore && name) {
|
||||
if ($operatingWorkspace && name) {
|
||||
untrack(() => {
|
||||
loadHistory()
|
||||
})
|
||||
@@ -80,13 +82,13 @@
|
||||
{:else}
|
||||
<TableCustom>
|
||||
{#snippet headerRow()}
|
||||
<tr >
|
||||
<tr>
|
||||
<th>Changed By</th>
|
||||
<th>Change Type</th>
|
||||
<th>Affected</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
{/snippet}
|
||||
{/snippet}
|
||||
{#snippet body()}
|
||||
<tbody>
|
||||
{#each history as change}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { JobService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { forLater, getDbClockNow } from '$lib/forLater'
|
||||
import { displayDate } from '$lib/utils'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
let {
|
||||
jobId,
|
||||
@@ -15,7 +17,7 @@
|
||||
|
||||
let fetchingQueuePosition = false
|
||||
|
||||
let workspace = $derived(workspaceId ?? $workspaceStore)
|
||||
let workspace = $derived(workspaceId ?? $operatingWorkspace)
|
||||
|
||||
let scheduledFor = $state(undefined) as undefined | number
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
} from '$lib/gen'
|
||||
import { canWrite } from '$lib/utils'
|
||||
import { createEventDispatcher, onDestroy, untrack } from 'svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { clearJsonSchemaResourceCache } from './schema/jsonSchemaResource.svelte'
|
||||
import ResourceForm from './ResourceForm.svelte'
|
||||
@@ -22,6 +21,9 @@
|
||||
import { UserDraftDbSyncer } from '$lib/userDraftDbSyncer.svelte'
|
||||
import { setLocalDraftHint } from '$lib/localDraftHints.svelte'
|
||||
import { onUserInput } from '$lib/userDraftEditGate'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
canSave?: boolean
|
||||
@@ -74,7 +76,7 @@
|
||||
|
||||
// Sole ambient read in this file: the acting workspace is an input, and only its
|
||||
// default comes from the navigation store.
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore!)
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace!)
|
||||
// Fallback to `effectiveWorkspace` insulates against reactify-style
|
||||
// parents that re-spread props without `selected` — otherwise it
|
||||
// transiently resets and the form below remounts on every keystroke.
|
||||
@@ -471,6 +473,12 @@
|
||||
current.path = npath
|
||||
}
|
||||
|
||||
/** The path the resource has in `ws`: after a save, the one it was saved under. Each
|
||||
* workspace-specific version keeps its own, so the selected one says nothing about `ws`. */
|
||||
export function pathIn(ws: string): string | undefined {
|
||||
return initialStates[ws]?.path
|
||||
}
|
||||
|
||||
/** Whether the write landed. It toasts its own failure, so most callers ignore this;
|
||||
* one that follows the save with bookkeeping of its own has to know not to. */
|
||||
export async function save(): Promise<boolean> {
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
import { History, Loader2, Save } from 'lucide-svelte'
|
||||
import WsSpecificVersions from './WsSpecificVersions.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { isOwner } from '$lib/utils'
|
||||
import { useActingUser } from '$lib/actingUser.svelte'
|
||||
import LocalDraftBanner from './LocalDraftBanner.svelte'
|
||||
import OpenInSessionButton from './sessions/OpenInSessionButton.svelte'
|
||||
import {
|
||||
clearPageDrawerAnchor,
|
||||
handOffPageDrawer,
|
||||
pageDrawerSessionSource,
|
||||
setPageDrawerAnchor
|
||||
} from './sessions/pageDrawerSession'
|
||||
@@ -20,10 +20,15 @@
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import { addResourceTitle } from './resourceTypeDisplay'
|
||||
import { loadResourceTypeDisplayName } from './displayNameLoaders'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
let {
|
||||
workspace = undefined,
|
||||
disableChatOffset = false,
|
||||
inline = false,
|
||||
onClose = undefined,
|
||||
onRestored = undefined,
|
||||
onSaved = undefined
|
||||
}: {
|
||||
@@ -31,10 +36,17 @@
|
||||
* once, at `effectiveWorkspace`, and nowhere else in this file. */
|
||||
workspace?: string
|
||||
disableChatOffset?: boolean
|
||||
/** Render in place, filling the parent, with no drawer or close button — for a host
|
||||
* that gives the editor a whole pane. Saving and restoring then leave it open: the
|
||||
* host remounts it on what was written. */
|
||||
inline?: boolean
|
||||
/** With `inline`, closes whatever hosts the editor; the header has a close button only when set. */
|
||||
onClose?: () => void
|
||||
onRestored?: () => void
|
||||
/** Fires after Save has written, for a caller showing state derived from the
|
||||
* resource — `onRestored` only covers restoring an old version. */
|
||||
onSaved?: () => void
|
||||
* resource — `onRestored` only covers restoring an old version. `path` is where the
|
||||
* resource now lives in this drawer's workspace, undefined when the save failed. */
|
||||
onSaved?: (path: string | undefined) => void
|
||||
} = $props()
|
||||
|
||||
let drawer: Drawer | undefined = $state()
|
||||
@@ -45,7 +57,8 @@
|
||||
|
||||
let resourceEditor:
|
||||
| {
|
||||
save: () => void
|
||||
save: () => Promise<boolean>
|
||||
pathIn: (ws: string) => string | undefined
|
||||
localDraftDeployed: () => unknown
|
||||
localDraftCurrent: () => unknown
|
||||
discardLocalDraft: () => void
|
||||
@@ -58,7 +71,7 @@
|
||||
let selected: string | undefined = $state(undefined)
|
||||
let viewJsonSchema = $state(false)
|
||||
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore!)
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace!)
|
||||
// The editor renders whichever workspace-specific variant `selected` points at, so history has
|
||||
// to follow it too — otherwise a restore would write over the variant the user is not looking at.
|
||||
let historyWorkspace = $derived(selected ?? effectiveWorkspace)
|
||||
@@ -85,6 +98,7 @@
|
||||
* dedicated editor elsewhere: the generic form would render its configuration field by field,
|
||||
* and materialize a default into every one the value leaves out. */
|
||||
export async function initEdit(p: string, opts?: { json?: boolean }): Promise<void> {
|
||||
if (handOffPageDrawer(RESOURCES_PATH, p)) return
|
||||
// A `close({ keepAnchor })` on an already-closed drawer emits no close event, so the flag
|
||||
// would still be standing when the next drawer session ends and would swallow that one's
|
||||
// anchor clear. Every session starts having to clear its own.
|
||||
@@ -126,22 +140,35 @@
|
||||
)
|
||||
</script>
|
||||
|
||||
<Drawer
|
||||
bind:this={drawer}
|
||||
size="50rem"
|
||||
{disableChatOffset}
|
||||
on:close={() => {
|
||||
if (keepAnchorOnClose) {
|
||||
keepAnchorOnClose = false
|
||||
return
|
||||
}
|
||||
clearPageDrawerAnchor(RESOURCES_PATH)
|
||||
}}
|
||||
>
|
||||
{#if inline}
|
||||
<!-- ResourceEditor reads its path once, at mount — a drawer mounts it only when opened. -->
|
||||
{#if path !== undefined || resource_type !== undefined}
|
||||
{@render content()}
|
||||
{/if}
|
||||
{:else}
|
||||
<Drawer
|
||||
bind:this={drawer}
|
||||
size="50rem"
|
||||
{disableChatOffset}
|
||||
on:close={() => {
|
||||
if (keepAnchorOnClose) {
|
||||
keepAnchorOnClose = false
|
||||
return
|
||||
}
|
||||
clearPageDrawerAnchor(RESOURCES_PATH)
|
||||
}}
|
||||
>
|
||||
{@render content()}
|
||||
</Drawer>
|
||||
{/if}
|
||||
|
||||
{#snippet content()}
|
||||
<DrawerContent
|
||||
title={mode == 'edit' ? 'Edit ' + path : addResourceTitle(resource_type)}
|
||||
bannerReserved={mode == 'edit'}
|
||||
on:close={drawer?.closeDrawer}
|
||||
hideClose={inline && !onClose}
|
||||
fullScreen={!inline}
|
||||
on:close={() => (inline ? onClose?.() : drawer?.closeDrawer())}
|
||||
>
|
||||
{#snippet titleExtra()}
|
||||
{#if mode == 'new' && resource_type}
|
||||
@@ -201,10 +228,10 @@
|
||||
// Closed before the write is awaited, the way it always was: `save()` toasts its
|
||||
// own failures and never rejects, so waiting would only add visible lag to every
|
||||
// caller of this drawer. `onSaved` still fires after the write lands.
|
||||
const saved = resourceEditor?.save()
|
||||
const editor = resourceEditor
|
||||
const saved = editor?.save()
|
||||
drawer?.closeDrawer()
|
||||
await saved
|
||||
onSaved?.()
|
||||
onSaved?.((await saved) ? editor?.pathIn(effectiveWorkspace) : undefined)
|
||||
}}
|
||||
disabled={!canSave}
|
||||
>
|
||||
@@ -212,7 +239,7 @@
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
{/snippet}
|
||||
|
||||
<Drawer bind:this={historyDrawer} size="1200px">
|
||||
<DrawerContent title="Versions History" on:close={historyDrawer?.closeDrawer} noPadding>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { Alert, Skeleton } from './common'
|
||||
import Path from './Path.svelte'
|
||||
import LabelsInput from './LabelsInput.svelte'
|
||||
import { workspaceStore, type UserExt } from '$lib/stores'
|
||||
import { type UserExt } from '$lib/stores'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import SimpleEditor from './SimpleEditor.svelte'
|
||||
import FilesetEditor from './FilesetEditor.svelte'
|
||||
@@ -22,6 +22,9 @@
|
||||
import SyncResourceTypes from './SyncResourceTypes.svelte'
|
||||
import Label from './Label.svelte'
|
||||
import ResourcePathHint from './ResourcePathHint.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
path: string
|
||||
@@ -81,7 +84,7 @@
|
||||
onCredentialStored
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let rawCode: string | undefined = $state(undefined)
|
||||
let textFileContent: string = $state('')
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { ResourceService, WorkspaceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { onMount, untrack } from 'svelte'
|
||||
import AppConnect from './AppConnectDrawer.svelte'
|
||||
import ResourceEditorDrawer from './ResourceEditorDrawer.svelte'
|
||||
@@ -12,6 +11,9 @@
|
||||
import ExploreAssetButton, { assetCanBeExplored } from './ExploreAssetButton.svelte'
|
||||
import DropdownV2 from './DropdownV2.svelte'
|
||||
import { appIconComponent } from './icons'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
initialValue?: string | undefined
|
||||
@@ -62,7 +64,7 @@
|
||||
onValueChange = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore!)
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace!)
|
||||
|
||||
if (initialValue && value == undefined) {
|
||||
value = initialValue
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import { ResourceService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import IconedResourceType from './IconedResourceType.svelte'
|
||||
import { Button, ClearableInput } from './common'
|
||||
import Label from './Label.svelte'
|
||||
@@ -14,6 +13,9 @@
|
||||
setResourceTypeDisplayNames,
|
||||
sortResourceTypesByMatch
|
||||
} from './resourceTypeDisplay'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
interface Props {
|
||||
value: string | undefined
|
||||
notPickable?: boolean
|
||||
@@ -25,7 +27,7 @@
|
||||
let resources: { name: string; description?: string; searchText: string }[] = $state([])
|
||||
|
||||
async function loadResources() {
|
||||
const types = await ResourceService.listResourceType({ workspace: $workspaceStore! })
|
||||
const types = await ResourceService.listResourceType({ workspace: $operatingWorkspace! })
|
||||
setResourceTypeDisplayNames(types)
|
||||
resources = types.map((t) => ({
|
||||
name: t.name,
|
||||
@@ -42,7 +44,7 @@
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
if ($workspaceStore) {
|
||||
if ($operatingWorkspace) {
|
||||
untrack(() => {
|
||||
loadResources()
|
||||
})
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { ResourceService, type ResourceVersion } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import HighlightCode from './HighlightCode.svelte'
|
||||
@@ -12,6 +11,9 @@
|
||||
import VersionListItem from './VersionListItem.svelte'
|
||||
import { displayDate } from '$lib/utils'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
let {
|
||||
path,
|
||||
@@ -27,7 +29,7 @@
|
||||
onRestore?: () => void
|
||||
} = $props()
|
||||
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore!)
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace!)
|
||||
|
||||
let versions = $state<ResourceVersion[] | undefined>(undefined)
|
||||
// Which row is highlighted, updated on click. `loaded` is dropped the moment the selection
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
import Select from './select/Select.svelte'
|
||||
import { FileUp } from 'lucide-svelte'
|
||||
import { SettingService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
import { resource } from 'runed'
|
||||
|
||||
interface Props {
|
||||
@@ -54,7 +56,7 @@
|
||||
* asset lives in a different workspace than this picker was mounted for. */
|
||||
let workspaceOverride: string | undefined = $state(undefined)
|
||||
let effectiveWorkspace = $derived(workspaceOverride ?? workspace)
|
||||
let ws = $derived(effectiveWorkspace ?? $workspaceStore)
|
||||
let ws = $derived(effectiveWorkspace ?? $operatingWorkspace)
|
||||
let uploadModalOpen = $state(false)
|
||||
|
||||
let allFilesByKey: Record<
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
Trash,
|
||||
MoveRight
|
||||
} from 'lucide-svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import {
|
||||
CancelablePromise,
|
||||
HelpersService,
|
||||
@@ -48,6 +47,9 @@
|
||||
import FileUploadModal from './common/fileUpload/FileUploadModal.svelte'
|
||||
import S3FilePreview from './S3FilePreview.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
let deletionModalOpen = $state(false)
|
||||
let fileDeletionInProgress = $state(false)
|
||||
@@ -137,7 +139,7 @@
|
||||
testConnectionRequest = HelpersService.datasetStorageTestConnection
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let rootPath = $state(initialRootPath)
|
||||
let rootPathNestingLevel = $derived(1 * (rootPath.split('/').length - 1))
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
// need to hand it a `fileKey`. CSV separator/header are local state so
|
||||
// the user can re-preview the same file with different parsing flags.
|
||||
import { FileX2, Loader2 } from 'lucide-svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import {
|
||||
HelpersService,
|
||||
type CancelablePromise,
|
||||
@@ -20,6 +19,9 @@
|
||||
import { displayDate, displaySize, emptyString } from '$lib/utils'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ExpandableImage from '$lib/components/common/image/ExpandableImage.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
fileKey: string | undefined
|
||||
@@ -115,7 +117,7 @@
|
||||
// existence after an upstream run completes — moving from the
|
||||
// "not yet materialized" empty state to the actual preview without
|
||||
// requiring the user to re-click the asset.
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
$effect(() => {
|
||||
const key = fileKey
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { displayDate } from '$lib/utils.js'
|
||||
import { InputService, type CreateInput, type RunnableType } from '$lib/gen/index.js'
|
||||
import { workspaceStore } from '$lib/stores.js'
|
||||
import { Button } from '$lib/components/common'
|
||||
import { Save } from 'lucide-svelte'
|
||||
import { sendUserToast } from '$lib/utils.js'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -30,7 +32,7 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let savingInputs = $state(false)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/common'
|
||||
import { InputService, type Input, type RunnableType } from '$lib/gen/index.js'
|
||||
import { userStore, workspaceStore } from '$lib/stores.js'
|
||||
import { userStore } from '$lib/stores.js'
|
||||
import { sendUserToast } from '$lib/utils.js'
|
||||
import { createEventDispatcher, onDestroy, untrack } from 'svelte'
|
||||
import { Trash2, Save, Pencil } from 'lucide-svelte'
|
||||
@@ -12,6 +12,14 @@
|
||||
import InfiniteList from './InfiniteList.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import SavedInputsPickerViewer from './SavedInputsPickerViewer.svelte'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
interface Props {
|
||||
previewArgs?: any
|
||||
@@ -36,7 +44,7 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
interface EditableInput extends Input {
|
||||
isEditing?: boolean
|
||||
@@ -254,8 +262,8 @@
|
||||
{#snippet children({ item, hover })}
|
||||
{@const editOptions =
|
||||
item.created_by == $userStore?.username ||
|
||||
$userStore?.is_admin ||
|
||||
$userStore?.is_super_admin}
|
||||
actingUser?.is_admin ||
|
||||
actingUser?.is_super_admin}
|
||||
<Cell>
|
||||
<div class="center-center">
|
||||
<Save size={12} />
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
const bubble = createBubbler()
|
||||
import type { Schema } from '$lib/common'
|
||||
import { VariableService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { allTrue, computeShow, type DynamicInput } from '$lib/utils'
|
||||
import { Button } from './common'
|
||||
import ItemPicker from './ItemPicker.svelte'
|
||||
@@ -26,6 +25,9 @@
|
||||
import type { ComponentCustomCSS } from './apps/types'
|
||||
import ResizeTransitionWrapper from './common/ResizeTransitionWrapper.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
schema: Schema | any
|
||||
@@ -122,7 +124,7 @@
|
||||
actions: actions_render = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
workerTags,
|
||||
workspaceStore
|
||||
} from '$lib/stores'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
import {
|
||||
emptySchema,
|
||||
emptyString,
|
||||
@@ -189,7 +193,10 @@
|
||||
// (forked) workspace, so an embedded editor acts on the session's fork rather
|
||||
// than the navigation workspace ($workspaceStore, which stays put). indicatorPath
|
||||
// is the matching draft path (URL path full-page, session target in preview).
|
||||
const opWorkspace = $derived(autosaveWorkspace ?? $workspaceStore)
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
const opWorkspace = $derived(autosaveWorkspace ?? $operatingWorkspace)
|
||||
const indicatorPath = $derived(autosavePath ?? userDraftPath)
|
||||
|
||||
// The shared `workerTags` store caches tags for the navigation workspace. A
|
||||
@@ -223,8 +230,8 @@
|
||||
let preserveOnBehalfOf = $state(false)
|
||||
|
||||
const WM_DEPLOYERS_GROUP = 'wm_deployers'
|
||||
let isDeployer = $derived($userStore?.groups?.includes(WM_DEPLOYERS_GROUP) ?? false)
|
||||
let canPreserve = $derived(!!$userStore?.is_admin || !!$userStore?.is_super_admin || isDeployer)
|
||||
let isDeployer = $derived(actingUser?.groups?.includes(WM_DEPLOYERS_GROUP) ?? false)
|
||||
let canPreserve = $derived(!!actingUser?.is_admin || !!actingUser?.is_super_admin || isDeployer)
|
||||
let originalOnBehalfOfEmail = $derived(savedScript?.on_behalf_of_email)
|
||||
let originalOnBehalfOfPermissionedAs = $derived(savedScript?.on_behalf_of)
|
||||
let onBehalfOfChoice: OnBehalfOfChoice = $state(undefined)
|
||||
@@ -740,7 +747,7 @@
|
||||
await deployTriggers(
|
||||
triggersToDeploy,
|
||||
opWorkspace,
|
||||
!!$userStore?.is_admin || !!$userStore?.is_super_admin,
|
||||
!!actingUser?.is_admin || !!actingUser?.is_super_admin,
|
||||
usedTriggerKinds,
|
||||
script.path,
|
||||
true
|
||||
@@ -1158,7 +1165,7 @@
|
||||
on:confirmed={handleDraftTriggersConfirmed}
|
||||
/>
|
||||
|
||||
{#if !$userStore?.operator}
|
||||
{#if !actingUser?.operator}
|
||||
<Drawer
|
||||
placement="right"
|
||||
bind:open={metadataOpen}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
type ScriptLang,
|
||||
type ScriptModule
|
||||
} from '$lib/gen'
|
||||
import { enterpriseLicense, userStore, workspaceStore } from '$lib/stores'
|
||||
import { enterpriseLicense, userStore } from '$lib/stores'
|
||||
import { copyToClipboard, emptySchema, sendUserToast } from '$lib/utils'
|
||||
import Editor from './Editor.svelte'
|
||||
import { inferArgs, inferAssets, inferAnsibleExecutionMode } from '$lib/infer'
|
||||
@@ -129,6 +129,9 @@
|
||||
import { resource, watch } from 'runed'
|
||||
import { buildScriptRecording, downloadRecordingJson } from './recording/runRecording'
|
||||
import DropdownV2 from './DropdownV2.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
// Exported
|
||||
@@ -226,10 +229,8 @@
|
||||
// built by the pipeline page from the resolved graph. Absent outside the
|
||||
// pipeline editor — the check still runs, just without suppression.
|
||||
schemaContractContext?: SchemaContractGraphContext
|
||||
// Workspace to scope this editor's calls to. Defaults to the nav
|
||||
// `$workspaceStore`; an AI-session live editor passes the session's
|
||||
// acting workspace (a fork) so tests, captures and toolbar lookups hit
|
||||
// the right workspace instead of the nav one.
|
||||
// Workspace to scope this editor's calls to (tests, captures, toolbar lookups).
|
||||
// Defaults to the operating workspace (see `useOperatingWorkspace`).
|
||||
workspaceOverride?: string
|
||||
}
|
||||
|
||||
@@ -278,7 +279,7 @@
|
||||
workspaceOverride = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let opWs = $derived(workspaceOverride ?? $workspaceStore)
|
||||
let opWs = $derived(workspaceOverride ?? $operatingWorkspace)
|
||||
|
||||
// Publish this editor's hand-off for AI entry points below it (the preview
|
||||
// panel's "AI Fix"), withheld under `disableAi` so an embed that turned AI off
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { ScriptService, FlowService, type Script, AppService } from '$lib/gen'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
|
||||
@@ -18,6 +17,9 @@
|
||||
import FlowIcon from './home/FlowIcon.svelte'
|
||||
import DarkModeObserver from './DarkModeObserver.svelte'
|
||||
import { truncate } from '$lib/utils'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
initialPath?: string | undefined
|
||||
@@ -30,9 +32,8 @@
|
||||
allowEdit?: boolean
|
||||
allowView?: boolean
|
||||
clearable?: boolean
|
||||
/** Workspace to list runnables from. Defaults to the navigation
|
||||
* `$workspaceStore`; pass the session's acting workspace so a forked
|
||||
* session lists its own scripts/flows/apps rather than the parent's. */
|
||||
/** Workspace to list runnables from. Defaults to the operating workspace (see
|
||||
* `useOperatingWorkspace`). */
|
||||
workspace?: string
|
||||
}
|
||||
|
||||
@@ -50,10 +51,11 @@
|
||||
workspace = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let effectiveWorkspace = $derived(workspace ?? $workspaceStore)
|
||||
// Only carry the workspace onto Edit/View routes when an explicit override
|
||||
// was passed, so existing callers' links are unchanged.
|
||||
let wsParam = $derived(workspace ? `?workspace=${encodeURIComponent(workspace)}` : '')
|
||||
let effectiveWorkspace = $derived(workspace ?? $operatingWorkspace)
|
||||
// Edit/View routes open in the workspace listed here, not wherever the tab lands.
|
||||
let wsParam = $derived(
|
||||
effectiveWorkspace ? `?workspace=${encodeURIComponent(effectiveWorkspace)}` : ''
|
||||
)
|
||||
|
||||
let items: { value: string; label: string }[] = $state([])
|
||||
let drawerViewer: Drawer | undefined = $state()
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { emptyString } from '$lib/utils'
|
||||
import { ScriptService, type ScriptHistory } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import FlowModuleScript from './flows/content/FlowModuleScript.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
@@ -11,6 +10,9 @@
|
||||
import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte'
|
||||
import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte'
|
||||
import VersionListItem from './VersionListItem.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -27,7 +29,7 @@
|
||||
async function loadVersions() {
|
||||
loading = true
|
||||
versions = await ScriptService.getScriptHistoryByPath({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
path: scriptPath
|
||||
})
|
||||
loading = false
|
||||
@@ -42,7 +44,7 @@
|
||||
return
|
||||
}
|
||||
await ScriptService.updateScriptHistory({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
path: scriptPath,
|
||||
hash: scriptHash,
|
||||
requestBody: {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { runScriptAndPollResult } from './jobs/utils'
|
||||
import { writingJobOptions } from './jobs/writingJob'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { untrack } from 'svelte'
|
||||
import { getLanguageByResourceType } from './apps/components/display/dbtable/utils'
|
||||
@@ -14,6 +13,9 @@
|
||||
import { wrapDucklakeQuery } from './ducklake'
|
||||
import { splitSqlStatements, pruneComments } from './sqlDdl'
|
||||
import DdlMigrationGuard from './DdlMigrationGuard.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
type Props = {
|
||||
input: DbInput
|
||||
@@ -39,7 +41,7 @@
|
||||
workspace = undefined,
|
||||
tag = undefined
|
||||
}: Props = $props()
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
let dbType = $derived(getDbType(input))
|
||||
|
||||
// A datatable REPL targets `datatable://<name>`; surface DDL statements as
|
||||
|
||||
@@ -4,13 +4,21 @@
|
||||
import Popover from '$lib/components/meltComponents/Popover.svelte'
|
||||
import TextInput from '$lib/components/text_input/TextInput.svelte'
|
||||
import Path from '$lib/components/Path.svelte'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { updateItemPathAndSummary, checkFlowOnBehalfOf } from './moveRenameManager'
|
||||
import Label from './Label.svelte'
|
||||
import LabelsInput from './LabelsInput.svelte'
|
||||
import InheritedLabels from './InheritedLabels.svelte'
|
||||
import Badge from './common/badge/Badge.svelte'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
interface Props {
|
||||
summary?: string
|
||||
@@ -36,7 +44,11 @@
|
||||
let editPath = $state('')
|
||||
let dirtyPath = $state(false)
|
||||
let popoverOpen = $state(false)
|
||||
let own = $state(false)
|
||||
let ownPath = $state<string | undefined>(undefined)
|
||||
// Derived: ownership answers about the operating workspace, whose user resolves asynchronously.
|
||||
const own = $derived(
|
||||
ownPath === undefined ? false : isOwner(ownPath, actingUser, $operatingWorkspace)
|
||||
)
|
||||
let onBehalfOfEmail = $state<string | undefined>(undefined)
|
||||
let summaryInput: ReturnType<typeof TextInput> | undefined = $state()
|
||||
let labelsDirty = $state(false)
|
||||
@@ -47,10 +59,10 @@
|
||||
editSummary = summary ?? ''
|
||||
editPath = path ?? ''
|
||||
labelsDirty = false
|
||||
own = isOwner(path ?? '', $userStore, $workspaceStore)
|
||||
ownPath = path ?? ''
|
||||
onBehalfOfEmail = undefined
|
||||
if (kind === 'flow' && $workspaceStore && path) {
|
||||
checkFlowOnBehalfOf($workspaceStore, path).then((email) => {
|
||||
if (kind === 'flow' && $operatingWorkspace && path) {
|
||||
checkFlowOnBehalfOf($operatingWorkspace, path).then((email) => {
|
||||
onBehalfOfEmail = email
|
||||
})
|
||||
}
|
||||
@@ -63,7 +75,7 @@
|
||||
|
||||
try {
|
||||
await updateItemPathAndSummary({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
kind,
|
||||
initialPath,
|
||||
newPath,
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
import Button from './common/button/Button.svelte'
|
||||
import Tooltip from './meltComponents/Tooltip.svelte'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
import { tryEvery } from '$lib/utils'
|
||||
|
||||
interface Props {
|
||||
@@ -268,7 +270,7 @@ export async function main(bucket: any, api_token: string) {
|
||||
loading = true
|
||||
|
||||
const resourceScript = scripts[resourceType]
|
||||
const workspace = workspaceOverride ?? $workspaceStore!
|
||||
const workspace = workspaceOverride ?? $operatingWorkspace!
|
||||
const objectStorageArgs: Record<string, any> | undefined =
|
||||
resourceType in objectStorageBody ? objectStorageBody[resourceType](args) : undefined
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { VariableService, WorkspaceService } from '$lib/gen'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Button } from './common'
|
||||
import Drawer from './common/drawer/Drawer.svelte'
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import OpenInSessionButton from './sessions/OpenInSessionButton.svelte'
|
||||
import {
|
||||
clearPageDrawerAnchor,
|
||||
handOffPageDrawer,
|
||||
pageDrawerSessionSource,
|
||||
setPageDrawerAnchor
|
||||
} from './sessions/pageDrawerSession'
|
||||
@@ -25,6 +25,9 @@
|
||||
import LocalDraftBanner from './LocalDraftBanner.svelte'
|
||||
import { isEncryptedDraftValue } from '$lib/encryptedDraft'
|
||||
import { setLocalDraftHint } from '$lib/localDraftHints.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -38,10 +41,25 @@
|
||||
// The "current" workspace this editor defaults New/Edit actions to. Session
|
||||
// editors pass their acting workspace so secrets are created/updated there
|
||||
// rather than in the navigation workspace.
|
||||
let { workspace = undefined }: { workspace?: string } = $props()
|
||||
let {
|
||||
workspace = undefined,
|
||||
inline = false,
|
||||
onClose = undefined,
|
||||
onSaved = undefined
|
||||
}: {
|
||||
workspace?: string
|
||||
/** Render in place, filling the parent, with no drawer or close button — for a host
|
||||
* that gives the editor a whole pane. */
|
||||
inline?: boolean
|
||||
/** With `inline`, closes whatever hosts the editor; the header has a close button only when set. */
|
||||
onClose?: () => void
|
||||
/** Fires once a save lands, with the path the variable now lives at in `workspace` —
|
||||
* not in the workspace-specific version selected, which can be another's. */
|
||||
onSaved?: (path: string) => void
|
||||
} = $props()
|
||||
// Sole ambient read in this file: the acting workspace is an input, and only its
|
||||
// default comes from the navigation store.
|
||||
let curWs = $derived(workspace ?? $workspaceStore)
|
||||
let curWs = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
let editPath: string | undefined = $state(undefined)
|
||||
|
||||
@@ -233,6 +251,7 @@
|
||||
}
|
||||
|
||||
export function editVariable(edit_path: string): void {
|
||||
if (handOffPageDrawer(VARIABLES_PATH, edit_path)) return
|
||||
reset()
|
||||
editPath = edit_path
|
||||
selected = curWs!
|
||||
@@ -256,6 +275,7 @@
|
||||
|
||||
async function save(): Promise<void> {
|
||||
const dirty = dirtyWorkspaces
|
||||
const savedPath = (curWs ? states[curWs]?.draft?.path : undefined) ?? editPath ?? ''
|
||||
try {
|
||||
for (const ws of dirty) {
|
||||
const s = states[ws].draft!
|
||||
@@ -303,6 +323,7 @@
|
||||
}
|
||||
sendUserToast(edit ? `Updated variable in ${dirty.length} workspace(s)` : `Created variable`)
|
||||
dispatch('create')
|
||||
onSaved?.(savedPath)
|
||||
drawer?.closeDrawer()
|
||||
} catch (err) {
|
||||
sendUserToast(`Could not save variable: ${err.body}`, true)
|
||||
@@ -310,11 +331,21 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={drawer} size="50rem" on:close={() => clearPageDrawerAnchor(VARIABLES_PATH)}>
|
||||
{#if inline}
|
||||
{@render content()}
|
||||
{:else}
|
||||
<Drawer bind:this={drawer} size="50rem" on:close={() => clearPageDrawerAnchor(VARIABLES_PATH)}>
|
||||
{@render content()}
|
||||
</Drawer>
|
||||
{/if}
|
||||
|
||||
{#snippet content()}
|
||||
<DrawerContent
|
||||
title={edit ? `Update variable at ${initialPath}` : 'Add a variable'}
|
||||
bannerReserved={edit}
|
||||
on:close={drawer?.closeDrawer}
|
||||
hideClose={inline && !onClose}
|
||||
fullScreen={!inline}
|
||||
on:close={() => (inline ? onClose?.() : drawer?.closeDrawer())}
|
||||
>
|
||||
{#snippet banner()}
|
||||
<LocalDraftBanner
|
||||
@@ -382,4 +413,4 @@
|
||||
</Button>
|
||||
{/snippet}
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
{/snippet}
|
||||
|
||||
@@ -10,10 +10,13 @@
|
||||
import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte'
|
||||
import { Loader2, RotateCcw } from 'lucide-svelte'
|
||||
import autosize from '$lib/autosize'
|
||||
import { workspaceStore, type UserExt } from '$lib/stores'
|
||||
import { type UserExt } from '$lib/stores'
|
||||
import { isOwner } from '$lib/utils'
|
||||
import { isEncryptedDraftValue } from '$lib/encryptedDraft'
|
||||
import EncryptedDraftField from './EncryptedDraftField.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Variable {
|
||||
value: string
|
||||
@@ -56,7 +59,7 @@
|
||||
actingUser
|
||||
}: Props = $props()
|
||||
|
||||
let ws = $derived(workspace ?? $workspaceStore)
|
||||
let ws = $derived(workspace ?? $operatingWorkspace)
|
||||
|
||||
// Loading the deployed secret overwrites the draft row this form shares with the AI
|
||||
// chat, so every path that would trigger it has to be blocked while that row stages a
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { Button } from '$lib/components/common'
|
||||
import { ExternalLink, RotateCw, Loader2 } from 'lucide-svelte'
|
||||
import { workerTags, workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
import AssignableTags from './AssignableTags.svelte'
|
||||
import { WorkerService } from '$lib/gen'
|
||||
import WorkerTagSelect from './WorkerTagSelect.svelte'
|
||||
@@ -11,8 +12,8 @@
|
||||
popupPlacement?: 'bottom-end' | 'top-end'
|
||||
disabled?: boolean
|
||||
placeholder?: string
|
||||
// Workspace to read tags from; defaults to $workspaceStore. A fork-scoped
|
||||
// session passes its effective workspace so the picker matches the deploy target.
|
||||
// Workspace to read tags from; defaults to the operating workspace (see
|
||||
// `useOperatingWorkspace`).
|
||||
workspaceId?: string
|
||||
}
|
||||
|
||||
@@ -26,8 +27,11 @@
|
||||
|
||||
// See WorkerTagSelect: the shared `workerTags` cache is navigation-scoped, so a
|
||||
// different target workspace reads/writes a local list to avoid clobbering it.
|
||||
let effectiveWorkspace = $derived(workspaceId ?? $workspaceStore)
|
||||
let usesLocal = $derived(workspaceId != undefined && workspaceId !== $workspaceStore)
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
let effectiveWorkspace = $derived(workspaceId ?? $operatingWorkspace)
|
||||
let usesLocal = $derived(
|
||||
effectiveWorkspace != undefined && effectiveWorkspace !== $workspaceStore
|
||||
)
|
||||
let localWorkerTags = $state<string[] | undefined>(undefined)
|
||||
let currentTags = $derived(usesLocal ? localWorkerTags : $workerTags)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { workerTags, workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
import { WorkerService } from '$lib/gen'
|
||||
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||
@@ -31,10 +32,8 @@
|
||||
/** Forwarded to the underlying Select — controls the input height. The
|
||||
* condensed session top bar passes `sm` to match its smaller buttons. */
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
// Workspace to read custom tags and worker availability from. Defaults to
|
||||
// $workspaceStore. Session editors act on a workspace that differs from the
|
||||
// navigation one, so they pass their effective workspace to keep the tag
|
||||
// list and availability dots matching the deploy target.
|
||||
// Workspace to read custom tags and worker availability from. Defaults to the
|
||||
// operating workspace (see `useOperatingWorkspace`).
|
||||
workspaceId?: string
|
||||
} = $props()
|
||||
|
||||
@@ -46,8 +45,11 @@
|
||||
// The shared `workerTags` store caches tags for the navigation workspace. When
|
||||
// this select targets a different workspace, read/write a local list instead so
|
||||
// it neither shows the navigation workspace's tags nor clobbers the shared cache.
|
||||
let effectiveWorkspace = $derived(workspaceId ?? $workspaceStore)
|
||||
let usesLocal = $derived(workspaceId != undefined && workspaceId !== $workspaceStore)
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
let effectiveWorkspace = $derived(workspaceId ?? $operatingWorkspace)
|
||||
let usesLocal = $derived(
|
||||
effectiveWorkspace != undefined && effectiveWorkspace !== $workspaceStore
|
||||
)
|
||||
let localWorkerTags = $state<string[] | undefined>(undefined)
|
||||
let currentTags = $derived(usesLocal ? localWorkerTags : $workerTags)
|
||||
|
||||
|
||||
@@ -9,11 +9,19 @@
|
||||
import ObjectViewer from './propertyPicker/ObjectViewer.svelte'
|
||||
import { CheckCircle2, XCircle } from 'lucide-svelte'
|
||||
import { JobService, type Job, type WorkflowStatus } from '$lib/gen'
|
||||
import { enterpriseLicense, userStore, workspaceStore } from '$lib/stores'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import { Button } from '$lib/components/common'
|
||||
import { Alert } from '$lib/components/common'
|
||||
import SchemaForm from '$lib/components/SchemaForm.svelte'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
interface Props {
|
||||
flow_status: Record<string, WorkflowStatus>
|
||||
@@ -97,7 +105,7 @@
|
||||
}
|
||||
|
||||
async function fetchChildJob(id: string) {
|
||||
const ws = $workspaceStore
|
||||
const ws = $operatingWorkspace
|
||||
if (!ws) return
|
||||
loadingJobs[id] = true
|
||||
try {
|
||||
@@ -126,7 +134,7 @@
|
||||
let approvalFormArgs: Record<string, Record<string, any>> = $state({})
|
||||
|
||||
async function handleApprove(key: string, formSchema: any) {
|
||||
const ws = $workspaceStore
|
||||
const ws = $operatingWorkspace
|
||||
if (!ws || !jobId) return
|
||||
approvalLoading[key] = true
|
||||
try {
|
||||
@@ -147,7 +155,7 @@
|
||||
|
||||
let cancelLoading = $state(false)
|
||||
async function handleCancel() {
|
||||
const ws = $workspaceStore
|
||||
const ws = $operatingWorkspace
|
||||
if (!ws || !jobId) return
|
||||
cancelLoading = true
|
||||
try {
|
||||
@@ -260,7 +268,7 @@
|
||||
<span class="text-tertiary">{msToSec(v.duration_ms ?? 0)}s</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if canApprove && selfApprovalDisabled && $userStore?.is_admin}
|
||||
{#if canApprove && selfApprovalDisabled && actingUser?.is_admin}
|
||||
<div class="mt-1 ml-5 text-yellow-600 text-2xs">
|
||||
Self-approval is disabled but allowed because you are an admin/owner
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,6 @@ standalone editor autosaves and surfacing those in the breadcrumb picker
|
||||
would be surprising.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import RowIcon from '$lib/components/common/table/RowIcon.svelte'
|
||||
import { untrack } from 'svelte'
|
||||
import {
|
||||
@@ -32,6 +31,9 @@ would be surprising.
|
||||
} from '$lib/components/copilot/chat/global/userDraftAdapter'
|
||||
import { isGlobalAiEnabled } from '$lib/components/copilot/chat/global/gate'
|
||||
import { resource } from 'runed'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
type Kind = WorkspaceItemKind
|
||||
type ScopeKind = Kind | 'all'
|
||||
@@ -52,9 +54,8 @@ would be surprising.
|
||||
externalFilter?: string
|
||||
autoFocus?: boolean
|
||||
flush?: boolean
|
||||
// Load items and drafts from this workspace instead of the navigation
|
||||
// workspace. Set by session live editors, whose acting workspace can
|
||||
// differ from $workspaceStore; falls back to $workspaceStore otherwise.
|
||||
// Load items and drafts from this workspace; defaults to the operating workspace
|
||||
// (see `useOperatingWorkspace`).
|
||||
workspaceId?: string
|
||||
}
|
||||
|
||||
@@ -70,7 +71,7 @@ would be surprising.
|
||||
workspaceId
|
||||
}: Props = $props()
|
||||
|
||||
const effectiveWorkspace = $derived(workspaceId ?? $workspaceStore)
|
||||
const effectiveWorkspace = $derived(workspaceId ?? $operatingWorkspace)
|
||||
|
||||
let inner = $state<DrillPickerHandle | undefined>(undefined)
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
type Scorer,
|
||||
type ScorerMean
|
||||
} from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { onDestroy, onMount, untrack } from 'svelte'
|
||||
import {
|
||||
@@ -52,6 +51,9 @@
|
||||
subjectLabel,
|
||||
type EvalsLocation
|
||||
} from './evalUtils'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
/** A dataset is capped at this many cases, so one page holds the whole set. */
|
||||
const CASE_PAGE_SIZE = 1000
|
||||
@@ -84,7 +86,7 @@
|
||||
active?: boolean
|
||||
} = $props()
|
||||
|
||||
let ws = $derived(opWorkspace ?? $workspaceStore)
|
||||
let ws = $derived(opWorkspace ?? $operatingWorkspace)
|
||||
let datasets = $state<EvalDataset[]>([])
|
||||
let dataset = $state<EvalDataset | undefined>(undefined)
|
||||
let selectedDataset = $state<string | undefined>(undefined)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { Alert } from '$lib/components/common'
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { enterpriseLicense, userStore, workspaceStore } from '$lib/stores'
|
||||
import { enterpriseLicense, userStore } from '$lib/stores'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
@@ -26,6 +26,14 @@
|
||||
import { canUserBypassRuleKind, protectionRulesState } from '$lib/workspaceProtectionRules.svelte'
|
||||
import { FRONTEND_SDK_SCOPES } from '$lib/components/raw_apps/sdkScopes'
|
||||
import { logFeatureUsage } from '$lib/utils/featureUsage'
|
||||
import {
|
||||
useOperatingUser,
|
||||
useOperatingWorkspace
|
||||
} from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspaceStore = useOperatingWorkspace()
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
const WM_DEPLOYERS_GROUP = 'wm_deployers'
|
||||
|
||||
@@ -74,29 +82,27 @@
|
||||
* (`/secret_of/...` 404s with no `app` row) and renders a placeholder
|
||||
* instead of the eternally-spinning link. */
|
||||
newApp?: boolean
|
||||
/** Workspace the app is deployed to — the session's acting workspace when
|
||||
* embedded in a session preview, else the navigation `$workspaceStore`.
|
||||
* The secret-URL / custom-path / folder / on-behalf-of lookups must target
|
||||
* it, not `$workspaceStore` (which stays on the nav workspace in a session). */
|
||||
/** Workspace the app is deployed to. The secret-URL / custom-path / folder /
|
||||
* on-behalf-of lookups target it; defaults to the operating workspace. */
|
||||
operatingWorkspace?: string
|
||||
} = $props()
|
||||
|
||||
const opWs = $derived(operatingWorkspace ?? $workspaceStore)
|
||||
const opWs = $derived(operatingWorkspace ?? $operatingWorkspaceStore)
|
||||
|
||||
let isDeployer = $derived($userStore?.groups?.includes(WM_DEPLOYERS_GROUP) ?? false)
|
||||
let isDeployer = $derived(actingUser?.groups?.includes(WM_DEPLOYERS_GROUP) ?? false)
|
||||
// Admins always pass the backend check. For everyone else, fail closed
|
||||
// while the workspace protection rules are still loading so the toggle
|
||||
// is never briefly enabled for a user the rules will end up restricting.
|
||||
let rulesetsLoaded = $derived(protectionRulesState.rulesets !== undefined)
|
||||
let canSetAnonymous = $derived(
|
||||
!!$userStore?.is_admin ||
|
||||
!!$userStore?.is_super_admin ||
|
||||
!!actingUser?.is_admin ||
|
||||
!!actingUser?.is_super_admin ||
|
||||
(rulesetsLoaded &&
|
||||
canUserBypassRuleKind('RestrictAnonymousAppDeployment', $userStore ?? undefined))
|
||||
)
|
||||
let canSetGuest = $derived(
|
||||
!!$userStore?.is_admin ||
|
||||
!!$userStore?.is_super_admin ||
|
||||
!!actingUser?.is_admin ||
|
||||
!!actingUser?.is_super_admin ||
|
||||
(rulesetsLoaded &&
|
||||
canUserBypassRuleKind('RestrictGuestAppDeployment', $userStore ?? undefined))
|
||||
)
|
||||
@@ -143,7 +149,7 @@
|
||||
setPublishState()
|
||||
}
|
||||
}
|
||||
let canPreserve = $derived(!!$userStore?.is_admin || !!$userStore?.is_super_admin || isDeployer)
|
||||
let canPreserve = $derived(!!actingUser?.is_admin || !!actingUser?.is_super_admin || isDeployer)
|
||||
let savedOnBehalfOfEmail = $derived(savedApp?.policy?.on_behalf_of_email)
|
||||
let savedOnBehalfOf = $derived(savedApp?.policy?.on_behalf_of)
|
||||
let onBehalfOfChoice: OnBehalfOfChoice = $state(undefined)
|
||||
@@ -596,7 +602,7 @@
|
||||
{/if}
|
||||
|
||||
<div class="mt-4">
|
||||
{#if !($userStore?.is_admin || $userStore?.is_super_admin)}
|
||||
{#if !(actingUser?.is_admin || actingUser?.is_super_admin)}
|
||||
<Alert type="warning" title="Admin only" size="xs">
|
||||
Custom path can only be set by workspace admins
|
||||
</Alert>
|
||||
@@ -617,7 +623,7 @@
|
||||
options={{
|
||||
right: 'Use a custom URL'
|
||||
}}
|
||||
disabled={!$enterpriseLicense || !($userStore?.is_admin || $userStore?.is_super_admin)}
|
||||
disabled={!$enterpriseLicense || !(actingUser?.is_admin || actingUser?.is_super_admin)}
|
||||
/>
|
||||
|
||||
{#if customPath !== undefined}
|
||||
@@ -625,7 +631,7 @@
|
||||
<div>Custom path</div>
|
||||
</div>
|
||||
<input
|
||||
disabled={!($userStore?.is_admin || $userStore?.is_super_admin)}
|
||||
disabled={!(actingUser?.is_admin || actingUser?.is_super_admin)}
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
bind:value={customPath}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
import JobArgs from '$lib/components/JobArgs.svelte'
|
||||
import LogViewer from '$lib/components/LogViewer.svelte'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { BellOff, Loader2, RefreshCw } from 'lucide-svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { classNames, truncateRev, isFlowPreview } from '../../../utils'
|
||||
@@ -21,6 +20,9 @@
|
||||
import type { Job } from '$lib/gen'
|
||||
import type { JobById } from '../types'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
open?: boolean
|
||||
@@ -163,7 +165,7 @@
|
||||
<Pane size={90} minSize={10} class="text-sm text-secondary">
|
||||
<div class="relative h-full px-2">
|
||||
<DisplayResult
|
||||
workspaceId={$workspaceStore}
|
||||
workspaceId={$operatingWorkspace}
|
||||
jobId={selectedJobId}
|
||||
result={jobResult.result}
|
||||
/>
|
||||
@@ -192,7 +194,7 @@
|
||||
<div class="p-2">
|
||||
<JobArgs
|
||||
id={job?.id}
|
||||
workspace={job?.workspace_id ?? $workspaceStore ?? 'no_w'}
|
||||
workspace={job?.workspace_id ?? $operatingWorkspace ?? 'no_w'}
|
||||
args={job?.args}
|
||||
/>
|
||||
</div>
|
||||
@@ -219,7 +221,7 @@
|
||||
{#if job != undefined && 'result' in job && job?.result != undefined}<div
|
||||
class="relative h-full px-2"
|
||||
><DisplayResult
|
||||
workspaceId={$workspaceStore}
|
||||
workspaceId={$operatingWorkspace}
|
||||
jobId={selectedJobId}
|
||||
result={job?.result}
|
||||
/></div
|
||||
@@ -240,7 +242,7 @@
|
||||
{#if job != undefined && 'result' in job && job?.result != undefined}
|
||||
<div class="relative h-full px-2">
|
||||
<DisplayResult
|
||||
workspaceId={$workspaceStore}
|
||||
workspaceId={$operatingWorkspace}
|
||||
jobId={selectedJobId}
|
||||
result={jobResult?.transformer}
|
||||
/>
|
||||
|
||||
@@ -14,12 +14,14 @@
|
||||
} from '$lib/utils'
|
||||
import { orderedYamlStringify } from '$lib/utils/orderedYaml'
|
||||
import { AppService, type AppWithLastVersion, type AppHistory } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { Pencil, ArrowRight, X, Loader2 } from 'lucide-svelte'
|
||||
import Select from '$lib/components/select/Select.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
appPath: string | undefined
|
||||
@@ -48,7 +50,7 @@
|
||||
return cached
|
||||
}
|
||||
|
||||
const app = await AppService.getAppByVersion({ workspace: $workspaceStore!, id: version })
|
||||
const app = await AppService.getAppByVersion({ workspace: $operatingWorkspace!, id: version })
|
||||
versionCache[version] = app
|
||||
return app
|
||||
}
|
||||
@@ -60,7 +62,7 @@
|
||||
|
||||
loading = true
|
||||
versions = await AppService.getAppHistoryByPath({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
path: appPath
|
||||
})
|
||||
loading = false
|
||||
@@ -90,7 +92,7 @@
|
||||
return
|
||||
}
|
||||
await AppService.updateAppHistory({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
id: appId,
|
||||
version: appVersion,
|
||||
requestBody: {
|
||||
@@ -107,7 +109,9 @@
|
||||
}
|
||||
|
||||
function toVersionLabel(version: AppHistory): string {
|
||||
return emptyString(version.deployment_msg) ? `Version ${version.version}` : version.deployment_msg!
|
||||
return emptyString(version.deployment_msg)
|
||||
? `Version ${version.version}`
|
||||
: version.deployment_msg!
|
||||
}
|
||||
|
||||
let availableVersions = $derived(
|
||||
|
||||
+7
-5
@@ -19,7 +19,6 @@
|
||||
CtxAppInput
|
||||
} from '../../inputType'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { computeFields } from './utils'
|
||||
@@ -35,6 +34,9 @@
|
||||
import FlowEditorDrawer from '$lib/components/flows/content/FlowEditorDrawer.svelte'
|
||||
import { FlowService, ScriptService, type OpenFlow } from '$lib/gen'
|
||||
import { replaceScriptPlaceholderWithItsValues } from '$lib/hub'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
runnable: RunnableByPath
|
||||
@@ -131,7 +133,7 @@
|
||||
return
|
||||
}
|
||||
|
||||
const loaded = await loadSchema($workspaceStore ?? '', runnable.path, 'flow')
|
||||
const loaded = await loadSchema($operatingWorkspace ?? '', runnable.path, 'flow')
|
||||
const schema = loaded?.schema ?? emptySchema()
|
||||
if (!deepEqual(runnable.schema, schema)) {
|
||||
runnable.schema = schema
|
||||
@@ -167,7 +169,7 @@
|
||||
async function openScriptEditor(path: string) {
|
||||
try {
|
||||
const script = await ScriptService.getScriptByPath({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
path
|
||||
})
|
||||
scriptEditorDrawer?.openDrawer(script.hash, () => {
|
||||
@@ -344,7 +346,7 @@
|
||||
startIcon={{ icon: Eye }}
|
||||
endIcon={{ icon: ExternalLink }}
|
||||
target="_blank"
|
||||
href="{base}/flows/get/{runnable.path}?workspace={$workspaceStore}"
|
||||
href="{base}/flows/get/{runnable.path}?workspace={$operatingWorkspace}"
|
||||
>
|
||||
Details
|
||||
</Button>
|
||||
@@ -425,7 +427,7 @@
|
||||
{#if runnable.runType == 'flow' && isHubFlowPath(runnable.path)}
|
||||
Hub flow not found at {runnable.path}
|
||||
{:else}
|
||||
{runnable.runType} not found at {runnable.path} in workspace {$workspaceStore}
|
||||
{runnable.runType} not found at {runnable.path} in workspace {$operatingWorkspace}
|
||||
{/if}
|
||||
</div>
|
||||
{:else if runnable.runType == 'script' || runnable.runType == 'hubscript'}
|
||||
|
||||
+5
-8
@@ -11,15 +11,12 @@
|
||||
import type { Schema } from '$lib/common'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import { loadSchema } from '$lib/infer'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
import { buildPathRunnableSelection } from './runnableSelectorUtils'
|
||||
|
||||
type TabType =
|
||||
| 'hubscripts'
|
||||
| 'hubflows'
|
||||
| 'workspacescripts'
|
||||
| 'workspaceflows'
|
||||
| 'inlinescripts'
|
||||
type TabType = 'hubscripts' | 'hubflows' | 'workspacescripts' | 'workspaceflows' | 'inlinescripts'
|
||||
|
||||
interface Props {
|
||||
defaultUserInput?: boolean
|
||||
@@ -60,7 +57,7 @@
|
||||
path: string,
|
||||
runType: 'script' | 'flow' | 'hubscript'
|
||||
): Promise<{ schema: Schema; summary: string | undefined }> {
|
||||
const schema = await loadSchema($workspaceStore!, path, runType)
|
||||
const schema = await loadSchema($operatingWorkspace!, path, runType)
|
||||
if (!schema.schema.order) {
|
||||
schema.schema.order = Object.keys(schema.schema.properties ?? {})
|
||||
}
|
||||
|
||||
+4
-2
@@ -7,9 +7,11 @@
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
import RowIcon from '$lib/components/common/table/RowIcon.svelte'
|
||||
import { FlowService, type Flow } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptyString } from '$lib/utils'
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
filter?: string
|
||||
@@ -26,7 +28,7 @@
|
||||
|
||||
async function loadFlow(): Promise<void> {
|
||||
const loadedFlows = await FlowService.listFlows({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
perPage: 300,
|
||||
withoutDescription: true
|
||||
})
|
||||
|
||||
+4
-2
@@ -7,9 +7,11 @@
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
import RowIcon from '$lib/components/common/table/RowIcon.svelte'
|
||||
import { type Script, ScriptService } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptyString } from '$lib/utils'
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
filter?: string
|
||||
@@ -26,7 +28,7 @@
|
||||
|
||||
async function loadScripts(): Promise<void> {
|
||||
const loadedScripts = await ScriptService.listScripts({
|
||||
workspace: $workspaceStore!,
|
||||
workspace: $operatingWorkspace!,
|
||||
perPage: 300,
|
||||
withoutDescription: true
|
||||
})
|
||||
|
||||
@@ -48,7 +48,10 @@
|
||||
import AssetRunsPanel from './AssetRunsPanel.svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { userStore } from '$lib/stores'
|
||||
import { useOperatingUser } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingUser = useOperatingUser()
|
||||
const actingUser = $derived(operatingUser.current)
|
||||
|
||||
interface Props {
|
||||
// Regular selection — loads the script by path for inline editing.
|
||||
@@ -662,7 +665,7 @@
|
||||
// hand-rolled here because we need *two* confirm buttons, not one.
|
||||
let removeOpen = $state(false)
|
||||
let removing = $state(false)
|
||||
let canHardDelete = $derived(!!($userStore?.is_admin || $userStore?.is_super_admin))
|
||||
let canHardDelete = $derived(!!(actingUser?.is_admin || actingUser?.is_super_admin))
|
||||
|
||||
// React to the parent's remove-signal counter and pop the same modal
|
||||
// the in-pane trash button uses. Skipped for drafts (the parent calls
|
||||
|
||||
@@ -19,12 +19,15 @@
|
||||
XCircle
|
||||
} from 'lucide-svelte'
|
||||
import type { ScriptLang } from '$lib/gen'
|
||||
import { enterpriseLicense, workspaceStore } from '$lib/stores'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/utils'
|
||||
import { PIPELINE_LANGUAGES } from './pipelineLanguages'
|
||||
import type { PipelineOutputKind } from './pipelineTemplates'
|
||||
import type { DbtAssetProvenance } from './types'
|
||||
import DbtIcon from '$lib/components/icons/DbtIcon.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
// Shape used for both the data prop and the run callback. Drafts carry
|
||||
// `content` / `language` so the page-level run handler can dispatch to
|
||||
@@ -118,7 +121,7 @@
|
||||
|
||||
async function runProducers(e: MouseEvent) {
|
||||
e.stopPropagation()
|
||||
if (!$workspaceStore || running || !data.onRunProducer) return
|
||||
if (!$operatingWorkspace || running || !data.onRunProducer) return
|
||||
if (scriptProducers.length === 0) return
|
||||
running = true
|
||||
const handler = data.onRunProducer
|
||||
@@ -170,14 +173,14 @@
|
||||
}
|
||||
const cols = Object.entries(d.columns ?? {})
|
||||
if (cols.length) {
|
||||
lines.push(
|
||||
`columns: ${cols.map(([c, desc]) => (desc ? `${c} (${desc})` : c)).join(', ')}`
|
||||
)
|
||||
lines.push(`columns: ${cols.map(([c, desc]) => (desc ? `${c} (${desc})` : c)).join(', ')}`)
|
||||
}
|
||||
if (d.freshness) {
|
||||
const f = d.freshness as Record<string, { count?: number; period?: string }>
|
||||
const window = (k: string) =>
|
||||
f[k]?.count != null ? `${k.replace('_after', '')} after ${f[k].count}${f[k].period?.[0] ?? ''}` : ''
|
||||
f[k]?.count != null
|
||||
? `${k.replace('_after', '')} after ${f[k].count}${f[k].period?.[0] ?? ''}`
|
||||
: ''
|
||||
const windows = ['warn_after', 'error_after'].map(window).filter(Boolean)
|
||||
if (windows.length) lines.push(`freshness: ${windows.join(', ')}`)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
// seconds so the user sees status transitions without refreshing —
|
||||
// JobLoader handles streaming for the *selected* job.
|
||||
import { JobService, type Job } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { onDestroy, untrack } from 'svelte'
|
||||
import { displayDate } from '$lib/utils'
|
||||
import { CheckCircle2, Clock, History, Loader2, XCircle, Ban } from 'lucide-svelte'
|
||||
@@ -21,6 +20,9 @@
|
||||
import { Popover } from '$lib/components/meltComponents'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import DispatchEventsButton from '$lib/components/runs/DispatchEventsButton.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
// Producers of this asset. Each contributes its own listExtendedJobs
|
||||
@@ -88,7 +90,7 @@
|
||||
// Run only when the *content* of the producer set changes (string
|
||||
// key) or when the parent explicitly bumps `refreshKey` after
|
||||
// dispatching a new run. The producerKey debounce alone isn't
|
||||
// enough: refresh() synchronously reads $workspaceStore and
|
||||
// enough: refresh() synchronously reads $operatingWorkspace and
|
||||
// runnableProducers before the first await, and Svelte 5 records
|
||||
// those as deps of the surrounding $effect — which would then
|
||||
// re-fire whenever the parent re-derives `producers` (i.e. on
|
||||
@@ -174,11 +176,11 @@
|
||||
|
||||
async function refresh(): Promise<void> {
|
||||
if (refreshInFlight) return refreshInFlight
|
||||
if (!$workspaceStore || runnableProducers.length === 0) {
|
||||
if (!$operatingWorkspace || runnableProducers.length === 0) {
|
||||
jobs = []
|
||||
return
|
||||
}
|
||||
const ws = $workspaceStore
|
||||
const ws = $operatingWorkspace
|
||||
// Capture the producer paths *now* — using runnableProducers
|
||||
// directly inside the await would re-read after the array
|
||||
// identity churned, defeating the in-flight guard.
|
||||
@@ -286,12 +288,12 @@
|
||||
</span>
|
||||
<a
|
||||
class="text-3xs text-blue-600 hover:underline shrink-0"
|
||||
href={`${base}/run/${selectedJob.id}?workspace=${$workspaceStore}`}
|
||||
href={`${base}/run/${selectedJob.id}?workspace=${$operatingWorkspace}`}
|
||||
target="_blank">Open ↗</a
|
||||
>
|
||||
{#if $workspaceStore}
|
||||
{#if $operatingWorkspace}
|
||||
<DispatchEventsButton
|
||||
workspace={selectedJob.workspace_id ?? $workspaceStore}
|
||||
workspace={selectedJob.workspace_id ?? $operatingWorkspace}
|
||||
jobId={selectedJob.id}
|
||||
/>
|
||||
{/if}
|
||||
@@ -397,7 +399,7 @@
|
||||
<div class="flex flex-col gap-3 p-3">
|
||||
<JobArgs
|
||||
id={selectedJob.id}
|
||||
workspace={selectedJob.workspace_id ?? $workspaceStore ?? ''}
|
||||
workspace={selectedJob.workspace_id ?? $operatingWorkspace ?? ''}
|
||||
args={selectedJob.args}
|
||||
/>
|
||||
<div class="flex flex-col gap-1">
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
// just be noise.
|
||||
import DBTable from '$lib/components/DBTable.svelte'
|
||||
import { resource } from 'runed'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { loadAllTablesMetaData } from '$lib/components/apps/components/display/dbtable/metadata'
|
||||
import { dbTableOpsWithPreviewScripts } from '$lib/components/dbOps'
|
||||
import { WorkspaceService } from '$lib/gen'
|
||||
@@ -19,6 +18,9 @@
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
// Asset path as parsed from `datatable://<datatable>/<table>` —
|
||||
@@ -71,7 +73,7 @@
|
||||
// query, and the user needs to configure it before pipeline scripts
|
||||
// can write to it.
|
||||
let datatables = resource(
|
||||
() => $workspaceStore,
|
||||
() => $operatingWorkspace,
|
||||
async (ws) => {
|
||||
if (!ws) return [] as string[]
|
||||
try {
|
||||
@@ -117,9 +119,9 @@
|
||||
() => [input, refreshKey],
|
||||
async ([_input]) => {
|
||||
colDefsError = undefined
|
||||
if (!_input || !$workspaceStore) return undefined
|
||||
if (!_input || !$operatingWorkspace) return undefined
|
||||
try {
|
||||
return await loadAllTablesMetaData($workspaceStore, _input)
|
||||
return await loadAllTablesMetaData($operatingWorkspace, _input)
|
||||
} catch (e) {
|
||||
colDefsError = (e as Error)?.message || String(e)
|
||||
return undefined
|
||||
@@ -138,12 +140,12 @@
|
||||
})
|
||||
|
||||
let dbTableOps = $derived(
|
||||
input && tableColDefs && parsed.table && $workspaceStore
|
||||
input && tableColDefs && parsed.table && $operatingWorkspace
|
||||
? dbTableOpsWithPreviewScripts({
|
||||
input,
|
||||
tableKey: parsed.table,
|
||||
colDefs: tableColDefs,
|
||||
workspace: $workspaceStore
|
||||
workspace: $operatingWorkspace
|
||||
})
|
||||
: undefined
|
||||
)
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
// ("This partition") or show the full table ("Whole table") via a toggle.
|
||||
import DBTable from '$lib/components/DBTable.svelte'
|
||||
import { resource } from 'runed'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { loadAllTablesMetaData } from '$lib/components/apps/components/display/dbtable/metadata'
|
||||
import { dbTableOpsWithPreviewScripts } from '$lib/components/dbOps'
|
||||
import type { DbInput } from '$lib/components/dbTypes'
|
||||
@@ -18,6 +17,9 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ToggleButtonGroup from '$lib/components/common/toggleButton-v2/ToggleButtonGroup.svelte'
|
||||
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
// Full asset URI, e.g. `ducklake://main/orders_daily`.
|
||||
@@ -61,9 +63,9 @@
|
||||
() => [input, refreshKey] as const,
|
||||
async ([_input]) => {
|
||||
colDefsError = undefined
|
||||
if (!_input || !$workspaceStore) return undefined
|
||||
if (!_input || !$operatingWorkspace) return undefined
|
||||
try {
|
||||
return await loadAllTablesMetaData($workspaceStore, _input)
|
||||
return await loadAllTablesMetaData($operatingWorkspace, _input)
|
||||
} catch (e) {
|
||||
colDefsError = (e as Error)?.message || String(e)
|
||||
return undefined
|
||||
@@ -89,12 +91,12 @@
|
||||
})
|
||||
|
||||
let dbTableOps = $derived.by(() => {
|
||||
if (!(input && tableColDefs && tableKey && $workspaceStore)) return undefined
|
||||
if (!(input && tableColDefs && tableKey && $operatingWorkspace)) return undefined
|
||||
const ops = dbTableOpsWithPreviewScripts({
|
||||
input,
|
||||
tableKey,
|
||||
colDefs: tableColDefs,
|
||||
workspace: $workspaceStore,
|
||||
workspace: $operatingWorkspace,
|
||||
whereClause
|
||||
})
|
||||
// Read-only preview: drop the mutation handlers so DBTable hides its
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
// hand is shown above the grid so the affordance is self-documenting.
|
||||
import DBTable from '$lib/components/DBTable.svelte'
|
||||
import { resource } from 'runed'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import {
|
||||
fetchDucklakeColumnsAtVersion,
|
||||
dbTableOpsWithPreviewScripts
|
||||
@@ -17,6 +16,9 @@
|
||||
import { AlertTriangle, Loader2, ClipboardCopy } from 'lucide-svelte'
|
||||
import { Button } from '$lib/components/common'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
interface Props {
|
||||
// Full asset URI, e.g. `ducklake://main/orders_daily`.
|
||||
@@ -56,9 +58,10 @@
|
||||
let columns = resource(
|
||||
() => [ducklake, tableKey, version] as const,
|
||||
async ([_ducklake, _tableKey, _version]) => {
|
||||
if (!_ducklake || !_tableKey || _version == undefined || !$workspaceStore) return undefined
|
||||
if (!_ducklake || !_tableKey || _version == undefined || !$operatingWorkspace)
|
||||
return undefined
|
||||
const colDefs = await fetchDucklakeColumnsAtVersion({
|
||||
workspace: $workspaceStore,
|
||||
workspace: $operatingWorkspace,
|
||||
ducklake: _ducklake,
|
||||
tableKey: _tableKey,
|
||||
version: _version
|
||||
@@ -73,13 +76,13 @@
|
||||
let tableColDefs = $derived(ready ? columns.current!.colDefs : undefined)
|
||||
|
||||
let dbTableOps = $derived.by(() => {
|
||||
if (!(input && tableColDefs && tableKey && $workspaceStore && version != undefined))
|
||||
if (!(input && tableColDefs && tableKey && $operatingWorkspace && version != undefined))
|
||||
return undefined
|
||||
const ops = dbTableOpsWithPreviewScripts({
|
||||
input,
|
||||
tableKey,
|
||||
colDefs: tableColDefs,
|
||||
workspace: $workspaceStore,
|
||||
workspace: $operatingWorkspace,
|
||||
version
|
||||
})
|
||||
// Historical reads are immutable: drop every mutation handler so DBTable
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
import PipelineRunForm from './PipelineRunForm.svelte'
|
||||
import AssetRunsPanel from './AssetRunsPanel.svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
import { parsePipelineAnnotations } from './parsePipelineAnnotations'
|
||||
|
||||
interface Props {
|
||||
@@ -201,7 +203,7 @@
|
||||
bind:args
|
||||
bind:isValid
|
||||
{partitionSpec}
|
||||
workspace={$workspaceStore ?? ''}
|
||||
workspace={$operatingWorkspace ?? ''}
|
||||
{materializeTarget}
|
||||
{upstreamAssets}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/utils'
|
||||
import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte'
|
||||
import type { NativeTriggerKind } from './types'
|
||||
@@ -24,7 +23,10 @@
|
||||
import EmailTriggerEditor from '$lib/components/triggers/email/EmailTriggerEditor.svelte'
|
||||
import ScheduleEditor from '$lib/components/triggers/schedules/ScheduleEditor.svelte'
|
||||
import WebhookEditor from '$lib/components/triggers/webhook/WebhookEditor.svelte'
|
||||
import { setTriggerWorkspace } from '$lib/components/triggers/triggerWorkspace'
|
||||
import { setOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
|
||||
// Owns the native-trigger drawer wiring for the pipeline canvas: the nine
|
||||
// editor instances, the create/edit dispatch by kind, and the delete
|
||||
@@ -40,9 +42,8 @@
|
||||
type Props = { onUpdate: () => void; mountTriggerEditors: boolean; workspace?: string }
|
||||
let { onUpdate, mountTriggerEditors, workspace: triggerWorkspace }: Props = $props()
|
||||
|
||||
// Register the trigger-workspace resolver for the whole editor subtree (the
|
||||
// nine editors + the delete handler below). See triggerWorkspace.ts.
|
||||
setTriggerWorkspace(() => triggerWorkspace ?? $workspaceStore)
|
||||
// The nine editors below act on this workspace (see operatingWorkspace.svelte.ts).
|
||||
setOperatingWorkspace(() => triggerWorkspace)
|
||||
|
||||
let kafkaEditor: KafkaTriggerEditor | undefined = $state()
|
||||
let mqttEditor: MqttTriggerEditor | undefined = $state()
|
||||
@@ -127,7 +128,7 @@
|
||||
}
|
||||
|
||||
async function confirmDeleteAttachedTrigger() {
|
||||
const workspace = triggerWorkspace ?? $workspaceStore
|
||||
const workspace = triggerWorkspace ?? $operatingWorkspace
|
||||
if (!triggerDeleteTarget || !workspace) return
|
||||
const { kind, path: triggerPath } = triggerDeleteTarget
|
||||
triggerDeleteLoading = true
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
import DropdownV2 from '$lib/components/DropdownV2.svelte'
|
||||
import Popover from '$lib/components/meltComponents/Popover.svelte'
|
||||
import type { Item } from '$lib/utils'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { useOperatingWorkspace } from '$lib/components/operatingWorkspace.svelte'
|
||||
|
||||
const operatingWorkspace = useOperatingWorkspace()
|
||||
import { sendUserToast, msToReadableTimeShort } from '$lib/utils'
|
||||
|
||||
interface Props {
|
||||
@@ -129,7 +131,7 @@
|
||||
|
||||
async function runSelf(e: MouseEvent, cascade?: boolean) {
|
||||
e.stopPropagation()
|
||||
if (!$workspaceStore || running || !data.onRunSelf) return
|
||||
if (!$operatingWorkspace || running || !data.onRunSelf) return
|
||||
running = true
|
||||
try {
|
||||
await data.onRunSelf(cascade != undefined ? { cascade } : undefined)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user