mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 00:02:13 +00:00
feat: add workspace to URL via /w/<workspace_id>/ prefix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
0885d8c986
commit
1a0c975fa5
@@ -1,3 +1,5 @@
|
||||
import type { Reroute } from '@sveltejs/kit'
|
||||
|
||||
/** @type {import('@sveltejs/kit').Handle} */
|
||||
export async function handle({ event, resolve }) {
|
||||
const response = await resolve(event, {
|
||||
@@ -6,3 +8,11 @@ export async function handle({ event, resolve }) {
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
export const reroute: Reroute = ({ url }) => {
|
||||
const match = url.pathname.match(/^\/w\/([^/]+)(\/.*)?$/)
|
||||
if (match) {
|
||||
return match[2] || '/'
|
||||
}
|
||||
return url.pathname
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
import MultiSelect from './select/MultiSelect.svelte'
|
||||
import { safeSelectItems } from './select/utils.svelte'
|
||||
import S3ArgInput from './common/fileUpload/S3ArgInput.svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { getJsonSchemaFromResource } from './schema/jsonSchemaResource.svelte'
|
||||
import AIProviderPicker from './AIProviderPicker.svelte'
|
||||
@@ -568,7 +568,7 @@
|
||||
{#if value && typeof value == 'string' && value?.startsWith('$res:')}
|
||||
Linked to resource <a
|
||||
target="_blank"
|
||||
href="{base}/resources#/resource/{value.slice(5)}"
|
||||
href="{$wsBase}/resources#/resource/{value.slice(5)}"
|
||||
class="text-blue-500 underline"
|
||||
>{value.slice(5)} <span class="inline-block -mb-0.5"><ExternalLink size={14} /></span></a
|
||||
>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
import type { TriggerKind } from './triggers'
|
||||
import { triggerDisplayNamesMap, triggerKindToTriggerType } from './triggers/utils'
|
||||
import { getEmailAddress, getEmailDomain } from './triggers/email/utils'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import ToggleButtonGroup from './common/toggleButton-v2/ToggleButtonGroup.svelte'
|
||||
import ToggleButton from './common/toggleButton-v2/ToggleButton.svelte'
|
||||
|
||||
@@ -683,7 +683,7 @@
|
||||
|
||||
function getTriggerHref(triggerKind: TriggerKind): string | undefined {
|
||||
const pagePath = triggerKindToPagePath[triggerKind]
|
||||
return pagePath ? `${base}${pagePath}` : undefined
|
||||
return pagePath ? `${$wsBase}${pagePath}` : undefined
|
||||
}
|
||||
|
||||
// Fetch triggers when workspace is available
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { enterpriseLicense, superadmin, workspaceStore } from '$lib/stores'
|
||||
import {
|
||||
AppService,
|
||||
@@ -422,7 +422,7 @@
|
||||
>
|
||||
{:else}
|
||||
<Alert type="info" title="Shareable page"
|
||||
>Share this <a href="{base}/deploy/{kind}/{initialPath}">link</a> to have another properly permissioned
|
||||
>Share this <a href="{$wsBase}/deploy/{kind}/{initialPath}">link</a> to have another properly permissioned
|
||||
user do the deployment</Alert
|
||||
>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import { ResourceService, VariableService, WorkspaceService, type Script } from '$lib/gen'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import type Editor from './Editor.svelte'
|
||||
import ItemPicker from './ItemPicker.svelte'
|
||||
import VariableEditor from './VariableEditor.svelte'
|
||||
@@ -681,7 +681,7 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
|
||||
startIcon={{ icon: Plus }}
|
||||
target="_blank"
|
||||
variant="accent"
|
||||
href="{base}/resources?connect_app=undefined"
|
||||
href="{$wsBase}/resources?connect_app=undefined"
|
||||
>
|
||||
Add resource
|
||||
</Button>
|
||||
@@ -739,7 +739,7 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
|
||||
startIcon={{ icon: Settings }}
|
||||
target="_blank"
|
||||
variant="accent"
|
||||
href="{base}/workspace_settings?tab=windmill_lfs"
|
||||
href="{$wsBase}/workspace_settings?tab=windmill_lfs"
|
||||
>
|
||||
Go to settings
|
||||
</Button>
|
||||
@@ -782,7 +782,7 @@ JsonNode ${windmillPathToCamelCaseName(path)} = JsonNode.Parse(await client.GetS
|
||||
startIcon={{ icon: Settings }}
|
||||
target="_blank"
|
||||
variant="accent"
|
||||
href="{base}/workspace_settings?tab=windmill_data_tables"
|
||||
href="{$wsBase}/workspace_settings?tab=windmill_data_tables"
|
||||
>
|
||||
Go to settings
|
||||
</Button>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
import ChannelSelector from '$lib/components/ChannelSelector.svelte'
|
||||
|
||||
import type { Schema, SupportedLanguage } from '$lib/common'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { enterpriseLicense, workspaceStore } from '$lib/stores'
|
||||
import MsTeamsIcon from '$lib/components/icons/MSTeamsIcon.svelte'
|
||||
import { classNames, emptySchema, emptyString, sendUserToast, tryEvery } from '$lib/utils'
|
||||
@@ -493,7 +493,7 @@
|
||||
|
||||
<a
|
||||
target="_blank"
|
||||
href={`${base}/run/${connectionTestJob.uuid}?workspace=${$workspaceStore}`}
|
||||
href={`${$wsBase}/run/${connectionTestJob.uuid}`}
|
||||
class="inline-flex items-center gap-1"
|
||||
>
|
||||
{connectionTestJob.uuid}
|
||||
@@ -585,7 +585,7 @@
|
||||
Message sent via Windmill job
|
||||
<a
|
||||
target="_blank"
|
||||
href={`${base}/run/${connectionTestJob.uuid}?workspace=${$workspaceStore}`}
|
||||
href={`${$wsBase}/run/${connectionTestJob.uuid}`}
|
||||
>
|
||||
{connectionTestJob.uuid}
|
||||
</a>
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
ExternalLink,
|
||||
Keyboard
|
||||
} from 'lucide-svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import ObjectViewer from './propertyPicker/ObjectViewer.svelte'
|
||||
import LogViewer from './LogViewer.svelte'
|
||||
import FlowLogViewer from './FlowLogViewer.svelte'
|
||||
@@ -98,7 +97,7 @@
|
||||
|
||||
function getJobLink(jobId: string | undefined): string {
|
||||
if (!jobId) return ''
|
||||
return `${base}/run/${jobId}?workspace=${workspaceId ?? $workspaceStore}`
|
||||
return `${$wsBase}/run/${jobId}`
|
||||
}
|
||||
|
||||
function getStatusColor(status: FlowStatusModule['type'] | undefined): string {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { type Job } from '$lib/gen'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import JobStatus from '$lib/components/JobStatus.svelte'
|
||||
import { displayDate, truncateRev } from '$lib/utils'
|
||||
import ScheduleEditor from '$lib/components/triggers/schedules/ScheduleEditor.svelte'
|
||||
import TimeAgo from './TimeAgo.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
import { Clock, MemoryStick, Calendar, Bot, User, Code2 } from 'lucide-svelte'
|
||||
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
|
||||
@@ -57,7 +56,7 @@
|
||||
<BarsStaggered size={SMALL_ICON_SIZE} class="min-w-3.5" />
|
||||
<span class="whitespace-nowrap">
|
||||
Step of flow
|
||||
<a href={`${base}/run/${job.parent_job}?workspace=${$workspaceStore}`}>
|
||||
<a href={`${$wsBase}/run/${job.parent_job}`}>
|
||||
{truncateRev(job.parent_job, 18)}
|
||||
</a>
|
||||
</span>
|
||||
@@ -67,7 +66,7 @@
|
||||
<Bot size={SMALL_ICON_SIZE} class="min-w-3.5" />
|
||||
<span class="whitespace-nowrap">
|
||||
Triggered by parent
|
||||
<a href={`${base}/run/${job.parent_job}?workspace=${$workspaceStore}`}>
|
||||
<a href={`${$wsBase}/run/${job.parent_job}`}>
|
||||
{job.parent_job}</a
|
||||
>
|
||||
</span>
|
||||
@@ -94,7 +93,7 @@
|
||||
{#if (job && job.job_kind == 'flow') || job?.job_kind == 'script'}
|
||||
{@const stem = `${job?.job_kind}s`}
|
||||
{@const isScript = job?.job_kind === 'script'}
|
||||
{@const viewHref = `${base}/${stem}/get/${isScript ? job?.script_hash : job?.script_path}`}
|
||||
{@const viewHref = `${$wsBase}/${stem}/get/${isScript ? job?.script_hash : job?.script_path}`}
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
{#if isScript}
|
||||
<Code2 size={SMALL_ICON_SIZE} class="min-w-3.5" />
|
||||
@@ -125,6 +124,6 @@
|
||||
</div>
|
||||
<div class="text-secondary text-2xs pt-2 whitespace-nowrap">
|
||||
run id:
|
||||
<a href={`${base}/run/${job.id}?workspace=${job.workspace_id}`}> {job.id} </a>
|
||||
<a href={`${$wsBase}/run/${job.id}`}> {job.id} </a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
type FlowValue
|
||||
} from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import FlowJobResult from './FlowJobResult.svelte'
|
||||
import WorkflowTimeline from './WorkflowTimeline.svelte'
|
||||
import DisplayResult from './DisplayResult.svelte'
|
||||
@@ -2058,8 +2058,8 @@
|
||||
class="text-right text-xs"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
href="{base}/run/{node.job_id ??
|
||||
''}?workspace={job?.workspace_id}"
|
||||
href="{$wsBase}/run/{node.job_id ??
|
||||
''}"
|
||||
>
|
||||
{truncateRev(node.job_id ?? '', 10)}
|
||||
<ExternalLink size={12} class="inline-block" />
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
import { usersWorkspaceStore, workspaceStore, userStore } from '$lib/stores'
|
||||
import { classNames, emptyString, escapeHtml, parseQueryParams } from '$lib/utils'
|
||||
import { base } from '$lib/base'
|
||||
import { extractWorkspaceFromPath } from '$lib/workspaceUrl'
|
||||
import { getUserExt } from '$lib/user'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
@@ -140,7 +141,10 @@
|
||||
if ($workspaceStore) {
|
||||
goto(rd ?? '/')
|
||||
} else {
|
||||
let workspaceTarget = parseQueryParams(rd ?? undefined)['workspace']
|
||||
// Extract workspace from rd path (/w/<ws>/...) or query param (?workspace=X)
|
||||
let workspaceTarget =
|
||||
extractWorkspaceFromPath(rd ?? '') ??
|
||||
parseQueryParams(rd ?? undefined)['workspace']
|
||||
if (rd && workspaceTarget) {
|
||||
$workspaceStore = workspaceTarget
|
||||
goto(rd)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { displayDate, sleep, sendUserToast } from '$lib/utils'
|
||||
import TableCustom from './TableCustom.svelte'
|
||||
import { Hourglass, Loader2, Play, RefreshCw } from 'lucide-svelte'
|
||||
@@ -139,7 +139,7 @@
|
||||
<td class="text-xs">
|
||||
<a
|
||||
class="pr-3"
|
||||
href="{base}/scripts/get/{scriptHash}?workspace={$workspaceStore}"
|
||||
href="{$wsBase}/scripts/get/{scriptHash}"
|
||||
target="_blank"
|
||||
>
|
||||
{scriptHash}
|
||||
@@ -148,7 +148,7 @@
|
||||
<td class="text-xs">
|
||||
<a
|
||||
class="pr-3"
|
||||
href="{base}/run/{jobId}?workspace={$workspaceStore}"
|
||||
href="{$wsBase}/run/{jobId}"
|
||||
target="_blank">{jobId.substring(24)}</a
|
||||
>
|
||||
</td>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
type MoveS3FileResponse
|
||||
} from '$lib/gen'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import {
|
||||
displayDate,
|
||||
displaySize,
|
||||
@@ -555,7 +556,7 @@
|
||||
<p class="text-clip grow min-w-0">
|
||||
The workspace needs to be connected to an S3 storage to use this feature. You can <a
|
||||
target="_blank"
|
||||
href="{base}/workspace_settings?tab=windmill_lfs">configure it here</a
|
||||
href="{$wsBase}/workspace_settings?tab=windmill_lfs">configure it here</a
|
||||
>.
|
||||
</p>
|
||||
<Button variant="default" on:click={reloadContent} startIcon={{ icon: RotateCw }} />
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
import CaptureButton from './triggers/CaptureButton.svelte'
|
||||
import { setContext } from 'svelte'
|
||||
import HideButton from './apps/editor/settingsPanel/HideButton.svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { SUPPORTED_CHAT_SCRIPT_LANGUAGES } from './copilot/chat/script/core'
|
||||
import { getStringError } from './copilot/chat/utils'
|
||||
import type { ScriptOptions } from './copilot/chat/ContextManager.svelte'
|
||||
@@ -1943,7 +1943,7 @@
|
||||
{#snippet popoverOverride()}
|
||||
<div class="text-sm">
|
||||
Enable Windmill AI in the <a
|
||||
href="{base}/workspace_settings?tab=ai"
|
||||
href="{$wsBase}/workspace_settings?tab=ai"
|
||||
target="_blank"
|
||||
class="inline-flex flex-row items-center gap-1"
|
||||
>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ScriptService, FlowService, type Script, AppService } from '$lib/gen'
|
||||
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
|
||||
import Select from './select/Select.svelte'
|
||||
@@ -158,7 +158,7 @@
|
||||
target="_blank"
|
||||
variant="default"
|
||||
size="xs"
|
||||
href="{base}/flows/edit/{scriptPath}">Edit</Button
|
||||
href="{$wsBase}/flows/edit/{scriptPath}">Edit</Button
|
||||
>
|
||||
{/if}
|
||||
{#if allowView}
|
||||
@@ -181,7 +181,7 @@
|
||||
target="_blank"
|
||||
variant="default"
|
||||
size="xs"
|
||||
href="{base}/apps/edit/{scriptPath}"
|
||||
href="{$wsBase}/apps/edit/{scriptPath}"
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
@@ -192,7 +192,7 @@
|
||||
size="xs"
|
||||
target="_blank"
|
||||
startIcon={{ icon: Code }}
|
||||
href="{base}/apps/get/{scriptPath}"
|
||||
href="{$wsBase}/apps/get/{scriptPath}"
|
||||
>
|
||||
View
|
||||
</Button>
|
||||
@@ -206,7 +206,7 @@
|
||||
target="_blank"
|
||||
variant="default"
|
||||
size="xs"
|
||||
href="{base}/scripts/edit/{scriptPath}"
|
||||
href="{$wsBase}/scripts/edit/{scriptPath}"
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { Button } from '$lib/components/common'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import SearchItems from './SearchItems.svelte'
|
||||
import { page } from '$app/state'
|
||||
import { goto as gotoUrl } from '$app/navigation'
|
||||
@@ -486,7 +487,7 @@
|
||||
{/key}
|
||||
{#if role_source === 'instance_group' && (super_admin || devops)}
|
||||
<a
|
||||
href="{base}/groups"
|
||||
href="{$wsBase}/groups"
|
||||
class="text-2xs text-tertiary mt-0.5 ml-1 hover:underline"
|
||||
title="Role set by instance group. You can upgrade to a higher role manually, but demoting to "User" requires removing them from the group."
|
||||
onclick={() => closeDrawer?.()}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { msToSec } from '$lib/utils'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { ExternalLink } from 'lucide-svelte'
|
||||
import Popover from './Popover.svelte'
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
: 'rounded-sm'} center-center text-white text-2xs whitespace-nowrap hover:outline outline-1 outline-black"
|
||||
>
|
||||
{#snippet text()}
|
||||
<a href="{base}/run/{id}" class="inline-flex items-center gap-1" target="_blank"
|
||||
<a href="{$wsBase}/run/{id}" class="inline-flex items-center gap-1" target="_blank"
|
||||
>{id} <ExternalLink size={14} /></a
|
||||
>
|
||||
{/snippet}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { displayDate, msToSec, emptyString } from '$lib/utils'
|
||||
import { onDestroy } from 'svelte'
|
||||
import { getDbClockNow } from '$lib/forLater'
|
||||
@@ -307,7 +307,7 @@
|
||||
<a
|
||||
target="_blank"
|
||||
class="inline-flex gap-2 items-baseline hover:underline whitespace-nowrap"
|
||||
href="{base}/run/{k}"
|
||||
href="{$wsBase}/run/{k}"
|
||||
onclick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{v.name ?? k}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
WorkspaceService
|
||||
} from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { emptyString, formatCron, sendUserToast, tryEvery } from '$lib/utils'
|
||||
import SchemaForm from '$lib/components/SchemaForm.svelte'
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
@@ -644,7 +644,7 @@
|
||||
<p class="text-clip grow min-w-0">
|
||||
The workspace needs to be connected to Slack to use this feature. You can <a
|
||||
target="_blank"
|
||||
href="{base}/workspace_settings?tab=slack">configure it here</a
|
||||
href="{$wsBase}/workspace_settings?tab=slack">configure it here</a
|
||||
>.
|
||||
</p>
|
||||
<Button
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { Button, Drawer, DrawerContent } from '$lib/components/common'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import FlowModuleScript from '$lib/components/flows/content/FlowModuleScript.svelte'
|
||||
import FlowPathViewer from '$lib/components/flows/content/FlowPathViewer.svelte'
|
||||
import { emptySchema, sendUserToast } from '$lib/utils'
|
||||
@@ -259,7 +259,7 @@
|
||||
startIcon={{ icon: Eye }}
|
||||
endIcon={{ icon: ExternalLink }}
|
||||
target="_blank"
|
||||
href="{base}/flows/get/{runnable.path}?workspace={$workspaceStore}"
|
||||
href="{$wsBase}/flows/get/{runnable.path}"
|
||||
>
|
||||
Details
|
||||
</Button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import Dropdown from '$lib/components/DropdownV2.svelte'
|
||||
import type MoveDrawer from '$lib/components/MoveDrawer.svelte'
|
||||
import SharedBadge from '$lib/components/SharedBadge.svelte'
|
||||
@@ -78,7 +78,7 @@
|
||||
{/if}
|
||||
|
||||
<Row
|
||||
href="{base}/apps{app.raw_app ? '_raw' : ''}/get/{app.path}"
|
||||
href="{$wsBase}/apps{app.raw_app ? '_raw' : ''}/get/{app.path}"
|
||||
kind="app"
|
||||
{marked}
|
||||
path={app.path}
|
||||
@@ -109,7 +109,7 @@
|
||||
variant="subtle"
|
||||
wrapperClasses="w-20"
|
||||
startIcon={{ icon: Pen }}
|
||||
href="{base}/apps{app.raw_app ? '_raw' : ''}/edit/{app.path}?nodraft=true"
|
||||
href="{$wsBase}/apps{app.raw_app ? '_raw' : ''}/edit/{app.path}?nodraft=true"
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
@@ -172,7 +172,7 @@
|
||||
{
|
||||
displayName: 'Duplicate/Fork',
|
||||
icon: GitFork,
|
||||
href: `${base}/apps${app.raw_app ? '_raw' : ''}/add?template=${path}`,
|
||||
href: `${$wsBase}/apps${app.raw_app ? '_raw' : ''}/add?template=${path}`,
|
||||
disabled: !showEditButton,
|
||||
hide: $userStore?.operator
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$lib/navigation'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import Dropdown from '$lib/components/DropdownV2.svelte'
|
||||
import type MoveDrawer from '$lib/components/MoveDrawer.svelte'
|
||||
import ScheduleEditor from '$lib/components/triggers/schedules/ScheduleEditor.svelte'
|
||||
@@ -102,8 +102,8 @@
|
||||
aiId={`flow-row-${flow.path}`}
|
||||
aiDescription={`Button to access the form to run the flow ${flow.summary ?? flow.path}`}
|
||||
href={flow.draft_only
|
||||
? `${base}/flows/edit/${flow.path}?nodraft=true`
|
||||
: `${base}/flows/get/${flow.path}?workspace=${$workspaceStore}`}
|
||||
? `${$wsBase}/flows/edit/${flow.path}?nodraft=true`
|
||||
: `${$wsBase}/flows/get/${flow.path}`}
|
||||
kind="flow"
|
||||
workspaceId={flow.workspace_id ?? $workspaceStore ?? ''}
|
||||
{marked}
|
||||
@@ -131,7 +131,7 @@
|
||||
wrapperClasses="w-20"
|
||||
unifiedSize="md"
|
||||
startIcon={{ icon: Pen }}
|
||||
href="{base}/flows/edit/{flow.path}?nodraft=true"
|
||||
href="{$wsBase}/flows/edit/{flow.path}?nodraft=true"
|
||||
aiId={`edit-flow-button-${flow.summary?.length > 0 ? flow.summary : flow.path}`}
|
||||
aiDescription={`Edits the flow ${flow.summary?.length > 0 ? flow.summary : flow.path}`}
|
||||
>
|
||||
@@ -187,12 +187,12 @@
|
||||
{
|
||||
displayName: 'View runs',
|
||||
icon: List,
|
||||
href: `${base}/runs/${path}`
|
||||
href: `${$wsBase}/runs/${path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Duplicate/Fork',
|
||||
icon: GitFork,
|
||||
href: `${base}/flows/add?template=${path}`,
|
||||
href: `${$wsBase}/flows/add?template=${path}`,
|
||||
disabled: !showEditButton,
|
||||
hide: $userStore?.operator
|
||||
},
|
||||
@@ -205,7 +205,7 @@
|
||||
{
|
||||
displayName: 'Audit logs',
|
||||
icon: Eye,
|
||||
href: `${base}/audit_logs?resource=${path}`,
|
||||
href: `${$wsBase}/audit_logs?resource=${path}`,
|
||||
hide: $userStore?.operator
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import Dropdown from '$lib/components/DropdownV2.svelte'
|
||||
import SharedBadge from '$lib/components/SharedBadge.svelte'
|
||||
import type ShareModal from '$lib/components/ShareModal.svelte'
|
||||
@@ -31,7 +31,7 @@
|
||||
</script>
|
||||
|
||||
<Row
|
||||
href="{base}/apps/get_raw/{app.version}/{app.path}"
|
||||
href="{$wsBase}/apps/get_raw/{app.version}/{app.path}"
|
||||
kind="raw_app"
|
||||
{marked}
|
||||
path={app.path}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$lib/navigation'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import Dropdown from '$lib/components/DropdownV2.svelte'
|
||||
import type MoveDrawer from '$lib/components/MoveDrawer.svelte'
|
||||
import ScheduleEditor from '$lib/components/triggers/schedules/ScheduleEditor.svelte'
|
||||
@@ -120,8 +120,8 @@
|
||||
aiId={`script-run-button-${script.path}`}
|
||||
aiDescription={`Button to access the form to run the script ${script.summary ?? script.path}`}
|
||||
href={script.draft_only || (script.auto_kind === 'lib' && script.kind !== 'preprocessor')
|
||||
? `${base}/scripts/edit/${script.path}`
|
||||
: `${base}/scripts/get/${script.hash}?workspace=${$workspaceStore}`}
|
||||
? `${$wsBase}/scripts/edit/${script.path}`
|
||||
: `${$wsBase}/scripts/get/${script.hash}`}
|
||||
kind="script"
|
||||
{marked}
|
||||
path={script.path}
|
||||
@@ -182,7 +182,7 @@
|
||||
wrapperClasses="w-20"
|
||||
unifiedSize="md"
|
||||
startIcon={{ icon: Pen }}
|
||||
href="{base}/scripts/edit/{script.path}"
|
||||
href="{$wsBase}/scripts/edit/{script.path}"
|
||||
>
|
||||
Edit
|
||||
</Button>
|
||||
@@ -264,7 +264,7 @@
|
||||
{
|
||||
displayName: 'Duplicate/Fork',
|
||||
icon: GitFork,
|
||||
href: `${base}/scripts/add?template=${script.path}`,
|
||||
href: `${$wsBase}/scripts/add?template=${script.path}`,
|
||||
disabled: !showEditButton,
|
||||
hide: $userStore?.operator
|
||||
},
|
||||
@@ -299,7 +299,7 @@
|
||||
{
|
||||
displayName: 'View runs',
|
||||
icon: List,
|
||||
href: `${base}/runs/${script.path}`
|
||||
href: `${$wsBase}/runs/${script.path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Versions',
|
||||
@@ -311,7 +311,7 @@
|
||||
{
|
||||
displayName: 'Audit logs',
|
||||
icon: Eye,
|
||||
href: `${base}/audit_logs?resource=${script.path}`,
|
||||
href: `${$wsBase}/audit_logs?resource=${script.path}`,
|
||||
hide: $userStore?.operator
|
||||
},
|
||||
{
|
||||
@@ -431,7 +431,7 @@
|
||||
openDetails
|
||||
on:openDetails={(e) => {
|
||||
if (script) {
|
||||
goto(`/scripts/get/${e.detail.version}?workspace=${$workspaceStore}`)
|
||||
goto(`/scripts/get/${e.detail.version}`)
|
||||
}
|
||||
versionsDrawerOpen = false
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$lib/navigation'
|
||||
import { base } from '$lib/base'
|
||||
|
||||
import { Button } from '$lib/components/common'
|
||||
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
|
||||
@@ -40,12 +39,12 @@
|
||||
|
||||
function selectLowCode() {
|
||||
appTypeModalOpen = false
|
||||
goto(`${base}/apps/add?nodraft=true`)
|
||||
goto('/apps/add?nodraft=true')
|
||||
}
|
||||
|
||||
function selectFullCode() {
|
||||
appTypeModalOpen = false
|
||||
goto(`${base}/apps_raw/add?nodraft=true`)
|
||||
goto('/apps_raw/add?nodraft=true')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$lib/navigation'
|
||||
import { base } from '$lib/base'
|
||||
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
|
||||
|
||||
import { Button } from '$lib/components/common'
|
||||
@@ -41,13 +40,13 @@
|
||||
const parsed =
|
||||
wacImportType === 'yaml' ? YAML.parse(pendingWacRaw ?? '') : JSON.parse(pendingWacRaw ?? '')
|
||||
$importScriptStore = parsed
|
||||
await goto(`${base}/scripts/add?import=true`)
|
||||
await goto('/scripts/add?import=true')
|
||||
wacDrawer?.closeDrawer?.()
|
||||
}
|
||||
|
||||
function handleFlowClick() {
|
||||
if (skipModal) {
|
||||
goto(`${base}/flows/add?nodraft=true`)
|
||||
goto('/flows/add?nodraft=true')
|
||||
} else {
|
||||
flowModalOpen = true
|
||||
}
|
||||
@@ -55,17 +54,17 @@
|
||||
|
||||
function selectFlowEditor() {
|
||||
flowModalOpen = false
|
||||
goto(`${base}/flows/add?nodraft=true`)
|
||||
goto('/flows/add?nodraft=true')
|
||||
}
|
||||
|
||||
function selectWacPython() {
|
||||
flowModalOpen = false
|
||||
goto(`${base}/scripts/add?nodraft=true&wac=python`)
|
||||
goto('/scripts/add?nodraft=true&wac=python')
|
||||
}
|
||||
|
||||
function selectWacTypescript() {
|
||||
flowModalOpen = false
|
||||
goto(`${base}/scripts/add?nodraft=true&wac=typescript`)
|
||||
goto('/scripts/add?nodraft=true&wac=typescript')
|
||||
}
|
||||
|
||||
function toggleSkipModal() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { Job } from '$lib/gen'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { ExternalLink } from 'lucide-svelte'
|
||||
import { emptyString } from '$lib/utils'
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
{#if !emptyString(job.id)}
|
||||
<a
|
||||
target="_blank"
|
||||
href="{base}/run/{job.id}?workspace={job.workspace_id}"
|
||||
href="{$wsBase}/run/{job.id}"
|
||||
class="text-right float-right text-gray-300 group-hover:text-gray-400 transition-all duration-200 dark:text-gray-500 dark:group-hover:text-gray-300"
|
||||
title="See run detail in a new tab"
|
||||
>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/common'
|
||||
import { GraduationCap, X } from 'lucide-svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { goto } from '$app/navigation'
|
||||
import { sendUserToast, type ToastAction } from '$lib/toast'
|
||||
import { getLocalSetting, storeLocalSetting } from '$lib/utils'
|
||||
@@ -115,7 +115,7 @@
|
||||
}
|
||||
|
||||
function goToTutorials() {
|
||||
goto(`${base}/tutorials`)
|
||||
goto(`${$wsBase}/tutorials`)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import type { CompletedJob, QueuedJob } from '$lib/gen'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
|
||||
import JobStatus from '../JobStatus.svelte'
|
||||
import { ExternalLinkIcon } from 'lucide-svelte'
|
||||
@@ -32,7 +32,7 @@
|
||||
<a
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
href="{base}/run/{job?.id}?workspace={job?.workspace_id}"
|
||||
href="{$wsBase}/run/{job?.id}"
|
||||
>
|
||||
{truncateRev(job?.id, 8)}
|
||||
<ExternalLinkIcon size={14} class="inline mb-1 ml-1" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { type Job } from '$lib/gen'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { displayDate, truncateRev, truncateHash } from '$lib/utils'
|
||||
import ScheduleEditor from '$lib/components/triggers/schedules/ScheduleEditor.svelte'
|
||||
import TimeAgo from '$lib/components/TimeAgo.svelte'
|
||||
@@ -189,14 +189,14 @@
|
||||
<Tooltip>
|
||||
{#snippet text()}
|
||||
This job was run on worker:
|
||||
<a href={`${base}/runs/?job_kinds=all&worker=${job?.worker}`}>
|
||||
<a href={`${$wsBase}/runs/?job_kinds=all&worker=${job?.worker}`}>
|
||||
{job?.worker}
|
||||
</a>
|
||||
<br />
|
||||
<WorkerHostname worker={job.worker!} minTs={job?.['created_at']} />
|
||||
{/snippet}
|
||||
<a
|
||||
href={`${base}/runs/?job_kinds=all&worker=${job?.worker}`}
|
||||
href={`${$wsBase}/runs/?job_kinds=all&worker=${job?.worker}`}
|
||||
class="flex items-center gap-1 text-primary"
|
||||
>
|
||||
<span class="truncate flex-shrink min-w-0">{displayValue}</span>
|
||||
@@ -231,7 +231,7 @@
|
||||
Triggered by
|
||||
{/if}
|
||||
<a
|
||||
href={`${base}/run/${job.parent_job}?workspace=${$workspaceStore}`}
|
||||
href={`${$wsBase}/run/${job.parent_job}`}
|
||||
class="flex items-center gap-1"
|
||||
>
|
||||
{displayValue}
|
||||
@@ -249,7 +249,7 @@
|
||||
icon: Link,
|
||||
action: () =>
|
||||
navigator.clipboard.writeText(
|
||||
`${window.location.origin}${base}/run/${job.id}?workspace=${job.workspace_id}`
|
||||
`${window.location.origin}${$wsBase}/run/${job.id}`
|
||||
)
|
||||
},
|
||||
{
|
||||
@@ -300,7 +300,7 @@
|
||||
<span class="text-secondary flex-shrink-0">Job ID</span>
|
||||
<span class="text-primary">
|
||||
<a
|
||||
href={`${base}/run/${job.id}?workspace=${job.workspace_id}`}
|
||||
href={`${$wsBase}/run/${job.id}`}
|
||||
class="flex items-center gap-1 min-w-0"
|
||||
>
|
||||
<span class="truncate flex-shrink min-w-0">{truncateRev(job.id, 8)}</span>
|
||||
@@ -388,7 +388,7 @@
|
||||
{#if job.script_path && (job.job_kind === 'script' || job.job_kind === 'flow' || job.job_kind === 'singlestepflow')}
|
||||
{@const stem = job.job_kind === 'script' ? 'scripts' : 'flows'}
|
||||
{@const isScript = job.job_kind === 'script'}
|
||||
{@const viewHref = `${base}/${stem}/get/${isScript ? job?.script_hash : job?.script_path}`}
|
||||
{@const viewHref = `${$wsBase}/${stem}/get/${isScript ? job?.script_hash : job?.script_path}`}
|
||||
<a
|
||||
href={viewHref}
|
||||
class="text-emphasis {compact
|
||||
@@ -479,7 +479,7 @@
|
||||
<span class="text-secondary flex-shrink-0">Job ID</span>
|
||||
<span class="text-primary">
|
||||
<a
|
||||
href={`${base}/run/${job.id}?workspace=${job.workspace_id}`}
|
||||
href={`${$wsBase}/run/${job.id}`}
|
||||
class="flex items-center gap-1 min-w-0"
|
||||
>
|
||||
<span class="truncate flex-shrink min-w-0">{truncateRev(job.id, 8)}</span>
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
import Tooltip from '$lib/components/meltComponents/Tooltip.svelte'
|
||||
import PreprocessedArgsDisplay from '$lib/components/runs/PreprocessedArgsDisplay.svelte'
|
||||
import { truncateHash } from '$lib/utils'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { truncateRev } from '$lib/utils'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { ListFilter } from 'lucide-svelte'
|
||||
@@ -33,7 +32,7 @@
|
||||
|
||||
{#if job.script_hash && showScriptHash && job.job_kind !== 'aiagent'}
|
||||
{#if job.job_kind == 'script'}
|
||||
<a href="{base}/scripts/get/{job.script_hash}?workspace={$workspaceStore}"
|
||||
<a href="{$wsBase}/scripts/get/{job.script_hash}"
|
||||
><Badge color="gray" title={`Script hash: ${job.script_hash}`} {large}
|
||||
>{truncateHash(job.script_hash)}
|
||||
</Badge></a
|
||||
@@ -104,7 +103,7 @@
|
||||
</Button>
|
||||
{:else}
|
||||
<a
|
||||
href={`${base}/runs/?job_kinds=all&graph=ConcurrencyChart&concurrency_key=${concurrencyKey}`}
|
||||
href={`${$wsBase}/runs/?job_kinds=all&graph=ConcurrencyChart&concurrency_key=${concurrencyKey}`}
|
||||
>
|
||||
{concurrencyKey}
|
||||
</a>
|
||||
@@ -116,7 +115,7 @@
|
||||
</button>
|
||||
{:else}
|
||||
<a
|
||||
href={`${base}/runs/?job_kinds=all&graph=ConcurrencyChart&concurrency_key=${concurrencyKey}`}
|
||||
href={`${$wsBase}/runs/?job_kinds=all&graph=ConcurrencyChart&concurrency_key=${concurrencyKey}`}
|
||||
>
|
||||
<Badge {large}>Concurrency: {truncateRev(concurrencyKey, 20)}</Badge>
|
||||
</a>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { goto } from '$lib/navigation'
|
||||
import type { Job } from '$lib/gen'
|
||||
import {
|
||||
@@ -162,12 +162,12 @@
|
||||
{/if}
|
||||
{#if job && job.is_flow_step && job.parent_job}
|
||||
<br /> Step of flow
|
||||
<a href={`${base}/run/${job.parent_job}?workspace=${job.workspace_id}`}>
|
||||
<a href={`${$wsBase}/run/${job.parent_job}`}>
|
||||
{truncateRev(job.parent_job, 10)}
|
||||
</a>
|
||||
{:else if job && job.parent_job}
|
||||
<br /> Parent
|
||||
<a href={`${base}/run/${job.parent_job}?workspace=${job.workspace_id}`}>
|
||||
<a href={`${$wsBase}/run/${job.parent_job}`}>
|
||||
{truncateRev(job.parent_job, 10)}
|
||||
</a>
|
||||
{/if}
|
||||
@@ -318,7 +318,7 @@
|
||||
<div class="flex justify-end pr-2">
|
||||
<a
|
||||
target="_blank"
|
||||
href="{base}/run/{job.id}?workspace={job.workspace_id}"
|
||||
href="{$wsBase}/run/{job.id}"
|
||||
class={twMerge(
|
||||
'text-right float-right px-2',
|
||||
selected ? 'text-accent' : 'text-secondary hover:text-accent'
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script lang="ts">
|
||||
import SchemaPickerRow from './SchemaPickerRow.svelte'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { ExternalLink } from 'lucide-svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
|
||||
interface Props {
|
||||
job: any
|
||||
@@ -60,7 +59,7 @@
|
||||
<div class="center-center">
|
||||
<a
|
||||
target="_blank"
|
||||
href="{base}/run/{job.id}?workspace={$workspaceStore}"
|
||||
href="{$wsBase}/run/{job.id}"
|
||||
class="text-right float-right text-secondary px-2"
|
||||
title="See run detail in a new tab"
|
||||
>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { createEventDispatcher, untrack } from 'svelte'
|
||||
import { ExternalLink } from 'lucide-svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { Cell, Row } from '$lib/components/table'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
<div class="center-center {hovering ? '' : '!hidden'}">
|
||||
<a
|
||||
target="_blank"
|
||||
href="{base}/run/{job.id}?workspace={$workspaceStore}"
|
||||
href="{$wsBase}/run/{job.id}"
|
||||
class="text-right float-right text-secondary"
|
||||
title="See run detail in a new tab"
|
||||
>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
type WorkflowStatus
|
||||
} from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { displayDate } from '$lib/utils'
|
||||
import Tabs from '../common/tabs/Tabs.svelte'
|
||||
import Tab from '../common/tabs/Tab.svelte'
|
||||
@@ -244,7 +244,7 @@
|
||||
<Cell first>
|
||||
<a
|
||||
class="pr-3"
|
||||
href="{base}/run/{id}?workspace={workspace ?? $workspaceStore}"
|
||||
href="{$wsBase}/run/{id}"
|
||||
target="_blank">{id.substring(30)}</a
|
||||
>
|
||||
</Cell>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { Code2, Plus } from 'lucide-svelte'
|
||||
import { Button } from '$lib/components/common'
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
unifiedSize="lg"
|
||||
variant="accent"
|
||||
startIcon={{ icon: Plus }}
|
||||
href="{base}/scripts/add"
|
||||
href="{$wsBase}/scripts/add"
|
||||
endIcon={{ icon: Code2 }}
|
||||
>
|
||||
Script
|
||||
|
||||
@@ -32,7 +32,8 @@
|
||||
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ContentSearchInner from '../ContentSearchInner.svelte'
|
||||
import { goto } from '$app/navigation'
|
||||
import { goto } from '$lib/navigation'
|
||||
import { toWorkspacePath } from '$lib/workspaceUrl'
|
||||
import QuickMenuItem from '../search/QuickMenuItem.svelte'
|
||||
import { devopsRole, enterpriseLicense, userStore, workspaceStore } from '$lib/stores'
|
||||
import uFuzzy from '@leeoniya/ufuzzy'
|
||||
@@ -420,7 +421,7 @@
|
||||
open = false
|
||||
goto(path)
|
||||
} else {
|
||||
window.open(path, '_blank')
|
||||
window.open(toWorkspacePath(path), '_blank')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { BellOff, Bell, ExternalLink, Settings } from 'lucide-svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import Notification from '$lib/components/common/alert/Notification.svelte'
|
||||
|
||||
interface Props {
|
||||
@@ -277,7 +278,7 @@
|
||||
<Button
|
||||
size="xs"
|
||||
color="light"
|
||||
href="{base}/workspace_settings?tab=error_handler"
|
||||
href="{$wsBase}/workspace_settings?tab=error_handler"
|
||||
target="_blank"
|
||||
>
|
||||
Workspace Critical Alert Settings <ExternalLink size="16" />
|
||||
@@ -290,7 +291,7 @@
|
||||
<Button
|
||||
size="xs"
|
||||
variant="default"
|
||||
href="{base}/workspace_settings?tab=error_handler"
|
||||
href="{$wsBase}/workspace_settings?tab=error_handler"
|
||||
target="_blank"
|
||||
>
|
||||
<List horizontal justify="between" gap="sm">
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
<script module lang="ts">
|
||||
import { getWsBase } from '$lib/workspaceUrl'
|
||||
|
||||
export type FavoriteKind = Exclude<
|
||||
NonNullable<StarData['requestBody']>['favorite_kind'],
|
||||
undefined
|
||||
>
|
||||
|
||||
export function getFavoriteHref(path: string, kind: FavoriteKind) {
|
||||
const wsPrefix = getWsBase()
|
||||
return {
|
||||
script: `/scripts/get/${path}`,
|
||||
flow: `/flows/get/${path}`,
|
||||
app: `/apps/get/${path}`,
|
||||
raw_app: `/apps_raw/get/${path}`,
|
||||
script: `${wsPrefix}/scripts/get/${path}`,
|
||||
flow: `${wsPrefix}/flows/get/${path}`,
|
||||
app: `${wsPrefix}/apps/get/${path}`,
|
||||
raw_app: `${wsPrefix}/apps_raw/get/${path}`,
|
||||
asset: '#'
|
||||
}[kind]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import type { MenubarMenuElements } from '@melt-ui/svelte'
|
||||
import { navigating, page } from '$app/stores'
|
||||
import Popover from '../Popover.svelte'
|
||||
import { base } from '$app/paths'
|
||||
import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte'
|
||||
import { goto } from '$app/navigation'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
@@ -40,7 +39,7 @@
|
||||
let isSelected = $state(false)
|
||||
|
||||
navigating.subscribe(() => {
|
||||
if (href === `${base}/`) {
|
||||
if (href.endsWith('/')) {
|
||||
isSelected = $page.url.pathname === href
|
||||
} else {
|
||||
isSelected = $page.url.pathname.startsWith(href)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
Table2
|
||||
} from 'lucide-svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
|
||||
import MultiplayerMenu from './MultiplayerMenu.svelte'
|
||||
import {
|
||||
@@ -52,16 +53,16 @@
|
||||
|
||||
let mainMenuLinks = $derived(
|
||||
[
|
||||
{ label: 'Home', id: 'home', href: `${base}/`, icon: Home },
|
||||
{ label: 'Runs', id: 'runs', href: `${base}/runs`, icon: Play },
|
||||
{ label: 'Schedules', id: 'schedules', href: `${base}/schedules`, icon: Calendar },
|
||||
{ label: 'Home', id: 'home', href: `${$wsBase}/`, icon: Home },
|
||||
{ label: 'Runs', id: 'runs', href: `${$wsBase}/runs`, icon: Play },
|
||||
{ label: 'Schedules', id: 'schedules', href: `${$wsBase}/schedules`, icon: Calendar },
|
||||
// Add Tutorials to main menu only if not all completed and not skipped
|
||||
...($tutorialsToDo.length > 0 && !$skippedAll
|
||||
? [
|
||||
{
|
||||
label: 'Tutorials',
|
||||
id: 'tutorials',
|
||||
href: `${base}/tutorials`,
|
||||
href: `${$wsBase}/tutorials`,
|
||||
icon: GraduationCap
|
||||
}
|
||||
]
|
||||
@@ -88,32 +89,32 @@
|
||||
{
|
||||
label: 'Resources',
|
||||
id: 'resources',
|
||||
href: `${base}/resources`
|
||||
href: `${$wsBase}/resources`
|
||||
},
|
||||
{
|
||||
label: 'Variables',
|
||||
id: 'variables',
|
||||
href: `${base}/variables`
|
||||
href: `${$wsBase}/variables`
|
||||
},
|
||||
{
|
||||
label: 'Assets',
|
||||
id: 'assets',
|
||||
href: `${base}/assets`
|
||||
href: `${$wsBase}/assets`
|
||||
},
|
||||
{
|
||||
label: 'Groups',
|
||||
id: 'groups',
|
||||
href: `${base}/groups`
|
||||
href: `${$wsBase}/groups`
|
||||
},
|
||||
{
|
||||
label: 'Folders',
|
||||
id: 'folders',
|
||||
href: `${base}/folders`
|
||||
href: `${$wsBase}/folders`
|
||||
},
|
||||
{
|
||||
label: 'Workers',
|
||||
id: 'workers',
|
||||
href: `${base}/workers`
|
||||
href: `${$wsBase}/workers`
|
||||
}
|
||||
].filter(filterLink)
|
||||
)
|
||||
@@ -122,52 +123,52 @@
|
||||
{
|
||||
label: 'Custom HTTP routes',
|
||||
id: 'triggers',
|
||||
href: `${base}/routes`
|
||||
href: `${$wsBase}/routes`
|
||||
},
|
||||
{
|
||||
label: 'Websocket triggers',
|
||||
id: 'triggers',
|
||||
href: `${base}/websocket_triggers`
|
||||
href: `${$wsBase}/websocket_triggers`
|
||||
},
|
||||
{
|
||||
label: 'Postgres triggers',
|
||||
id: 'triggers',
|
||||
href: `${base}/postgres_triggers`
|
||||
href: `${$wsBase}/postgres_triggers`
|
||||
},
|
||||
{
|
||||
label: 'Kafka triggers',
|
||||
id: 'triggers',
|
||||
href: `${base}/kafka_triggers`
|
||||
href: `${$wsBase}/kafka_triggers`
|
||||
},
|
||||
{
|
||||
label: 'NATS triggers',
|
||||
id: 'triggers',
|
||||
href: `${base}/nats_triggers`
|
||||
href: `${$wsBase}/nats_triggers`
|
||||
},
|
||||
{
|
||||
label: 'SQS triggers',
|
||||
id: 'triggers',
|
||||
href: `${base}/sqs_triggers`
|
||||
href: `${$wsBase}/sqs_triggers`
|
||||
},
|
||||
{
|
||||
label: 'GCP Pub/Sub triggers',
|
||||
id: 'triggers',
|
||||
href: `${base}/gcp_triggers`
|
||||
href: `${$wsBase}/gcp_triggers`
|
||||
},
|
||||
{
|
||||
label: 'MQTT triggers',
|
||||
id: 'triggers',
|
||||
href: `${base}/mqtt_triggers`
|
||||
href: `${$wsBase}/mqtt_triggers`
|
||||
},
|
||||
{
|
||||
label: 'Email triggers',
|
||||
id: 'triggers',
|
||||
href: `${base}/email_triggers`
|
||||
href: `${$wsBase}/email_triggers`
|
||||
},
|
||||
{
|
||||
label: 'Audit logs',
|
||||
id: 'audit_logs',
|
||||
href: `${base}/audit_logs`
|
||||
href: `${$wsBase}/audit_logs`
|
||||
}
|
||||
].filter(filterLink)
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
import ConfirmationModal from '../common/confirmationModal/ConfirmationModal.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { onMount } from 'svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase, stripWsPrefix } from '$lib/workspaceUrl'
|
||||
import { type Changelog, changelogs } from './changelogs'
|
||||
import { page } from '$app/state'
|
||||
import SideBarNotification from './SideBarNotification.svelte'
|
||||
@@ -140,7 +140,7 @@
|
||||
subItems: [
|
||||
{
|
||||
label: 'Tutorials',
|
||||
href: `${base}/tutorials`,
|
||||
href: `${$wsBase}/tutorials`,
|
||||
icon: GraduationCap,
|
||||
aiId: 'sidebar-menu-link-tutorials',
|
||||
aiDescription: 'Button to navigate to tutorials',
|
||||
@@ -206,7 +206,7 @@
|
||||
let mainMenuLinks = $derived([
|
||||
{
|
||||
label: 'Home',
|
||||
href: `${base}/`,
|
||||
href: `${$wsBase}/`,
|
||||
icon: Home,
|
||||
aiId: 'sidebar-menu-link-home',
|
||||
aiDescription:
|
||||
@@ -214,7 +214,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Runs',
|
||||
href: `${base}/runs`,
|
||||
href: `${$wsBase}/runs`,
|
||||
icon: Play,
|
||||
aiId: 'sidebar-menu-link-runs',
|
||||
aiDescription: 'Button to navigate to runs',
|
||||
@@ -226,7 +226,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Variables',
|
||||
href: `${base}/variables`,
|
||||
href: `${$wsBase}/variables`,
|
||||
icon: DollarSign,
|
||||
disabled: $userStore?.operator,
|
||||
aiId: 'sidebar-menu-link-variables',
|
||||
@@ -234,7 +234,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Resources',
|
||||
href: `${base}/resources`,
|
||||
href: `${$wsBase}/resources`,
|
||||
icon: Boxes,
|
||||
disabled: $userStore?.operator,
|
||||
aiId: 'sidebar-menu-link-resources',
|
||||
@@ -242,7 +242,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Assets',
|
||||
href: `${base}/assets`,
|
||||
href: `${$wsBase}/assets`,
|
||||
icon: Pyramid,
|
||||
disabled: $userStore?.operator,
|
||||
aiId: 'sidebar-menu-link-assets',
|
||||
@@ -253,7 +253,7 @@
|
||||
? [
|
||||
{
|
||||
label: 'Tutorials',
|
||||
href: `${base}/tutorials`,
|
||||
href: `${$wsBase}/tutorials`,
|
||||
icon: GraduationCap,
|
||||
aiId: 'sidebar-menu-link-tutorials-main',
|
||||
aiDescription: 'Button to navigate to tutorials'
|
||||
@@ -264,7 +264,7 @@
|
||||
let defaultExtraTriggerLinks = $derived([
|
||||
{
|
||||
label: 'HTTP',
|
||||
href: '/routes',
|
||||
href: `${$wsBase}/routes`,
|
||||
icon: Route,
|
||||
disabled: $userStore?.operator,
|
||||
kind: 'http',
|
||||
@@ -273,7 +273,7 @@
|
||||
},
|
||||
{
|
||||
label: 'WebSockets',
|
||||
href: '/websocket_triggers',
|
||||
href: `${$wsBase}/websocket_triggers`,
|
||||
icon: Unplug,
|
||||
disabled: $userStore?.operator,
|
||||
kind: 'ws',
|
||||
@@ -282,7 +282,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Postgres',
|
||||
href: '/postgres_triggers',
|
||||
href: `${$wsBase}/postgres_triggers`,
|
||||
icon: Database,
|
||||
disabled: $userStore?.operator,
|
||||
kind: 'postgres',
|
||||
@@ -291,7 +291,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Kafka' + ($enterpriseLicense ? '' : ' (EE)'),
|
||||
href: '/kafka_triggers',
|
||||
href: `${$wsBase}/kafka_triggers`,
|
||||
icon: KafkaIcon,
|
||||
disabled: $userStore?.operator || !$enterpriseLicense,
|
||||
kind: 'kafka',
|
||||
@@ -300,7 +300,7 @@
|
||||
},
|
||||
{
|
||||
label: 'NATS' + ($enterpriseLicense ? '' : ' (EE)'),
|
||||
href: '/nats_triggers',
|
||||
href: `${$wsBase}/nats_triggers`,
|
||||
icon: NatsIcon,
|
||||
disabled: $userStore?.operator || !$enterpriseLicense,
|
||||
kind: 'nats',
|
||||
@@ -309,7 +309,7 @@
|
||||
},
|
||||
{
|
||||
label: 'SQS' + ($enterpriseLicense ? '' : ' (EE)'),
|
||||
href: '/sqs_triggers',
|
||||
href: `${$wsBase}/sqs_triggers`,
|
||||
icon: AwsIcon,
|
||||
disabled: $userStore?.operator || !$enterpriseLicense,
|
||||
kind: 'sqs',
|
||||
@@ -318,7 +318,7 @@
|
||||
},
|
||||
{
|
||||
label: 'GCP Pub/Sub' + ($enterpriseLicense ? '' : ' (EE)'),
|
||||
href: '/gcp_triggers',
|
||||
href: `${$wsBase}/gcp_triggers`,
|
||||
icon: GoogleCloudIcon,
|
||||
disabled: $userStore?.operator || !$enterpriseLicense,
|
||||
kind: 'gcp',
|
||||
@@ -327,7 +327,7 @@
|
||||
},
|
||||
{
|
||||
label: 'MQTT',
|
||||
href: '/mqtt_triggers',
|
||||
href: `${$wsBase}/mqtt_triggers`,
|
||||
icon: MqttIcon,
|
||||
disabled: $userStore?.operator,
|
||||
kind: 'mqtt',
|
||||
@@ -336,7 +336,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Email',
|
||||
href: '/email_triggers',
|
||||
href: `${$wsBase}/email_triggers`,
|
||||
icon: MailIcon,
|
||||
disabled: $userStore?.operator,
|
||||
kind: 'email',
|
||||
@@ -348,7 +348,7 @@
|
||||
let nativeTriggerLinks = $derived(
|
||||
availableNativeServices.map(({ service, icon, config }) => ({
|
||||
label: config?.serviceDisplayName || service,
|
||||
href: `/native_triggers/${service}`,
|
||||
href: `${$wsBase}/native_triggers/${service}`,
|
||||
icon: icon,
|
||||
disabled: $userStore?.operator,
|
||||
kind: service,
|
||||
@@ -359,22 +359,28 @@
|
||||
|
||||
let allTriggerLinks = $derived([...defaultExtraTriggerLinks, ...nativeTriggerLinks])
|
||||
|
||||
let strippedPathname = $derived(stripWsPrefix(page.url.pathname))
|
||||
let triggerMenuLinks = $derived([
|
||||
{
|
||||
label: 'Schedules',
|
||||
href: `${base}/schedules`,
|
||||
href: `${$wsBase}/schedules`,
|
||||
icon: Calendar,
|
||||
disabled: !SIDEBAR_SHOW_SCHEDULES || $userStore?.operator,
|
||||
aiId: 'sidebar-menu-link-schedules',
|
||||
aiDescription: 'Button to navigate to schedules'
|
||||
},
|
||||
...allTriggerLinks.filter(
|
||||
(link) => $usedTriggerKinds.includes(link.kind) || page.url.pathname.includes(link.href)
|
||||
(link) =>
|
||||
$usedTriggerKinds.includes(link.kind) ||
|
||||
strippedPathname.includes(stripWsPrefix(link.href))
|
||||
)
|
||||
])
|
||||
let extraTriggerLinks = $derived(
|
||||
allTriggerLinks.filter((link) => {
|
||||
return !page.url.pathname.includes(link.href) && !$usedTriggerKinds.includes(link.kind)
|
||||
return (
|
||||
!strippedPathname.includes(stripWsPrefix(link.href)) &&
|
||||
!$usedTriggerKinds.includes(link.kind)
|
||||
)
|
||||
})
|
||||
)
|
||||
let secondaryMenuLinks = $derived([
|
||||
@@ -403,7 +409,7 @@
|
||||
? [
|
||||
{
|
||||
label: 'Workspace',
|
||||
href: `${base}/workspace_settings`,
|
||||
href: `${$wsBase}/workspace_settings`,
|
||||
icon: FolderCog,
|
||||
aiId: 'sidebar-menu-link-workspace',
|
||||
aiDescription: 'Button to navigate to workspace settings',
|
||||
@@ -453,7 +459,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Workers',
|
||||
href: `${base}/workers`,
|
||||
href: `${$wsBase}/workers`,
|
||||
icon: ServerCog,
|
||||
disabled: $userStore?.operator,
|
||||
aiId: 'sidebar-menu-link-workers',
|
||||
@@ -467,7 +473,7 @@
|
||||
subItems: [
|
||||
{
|
||||
label: 'Folders',
|
||||
href: `${base}/folders`,
|
||||
href: `${$wsBase}/folders`,
|
||||
icon: FolderOpen,
|
||||
disabled: $userStore?.operator,
|
||||
aiId: 'sidebar-menu-link-folders',
|
||||
@@ -476,7 +482,7 @@
|
||||
},
|
||||
{
|
||||
label: 'Groups',
|
||||
href: `${base}/groups`,
|
||||
href: `${$wsBase}/groups`,
|
||||
icon: UserCog,
|
||||
disabled: $userStore?.operator,
|
||||
aiId: 'sidebar-menu-link-groups',
|
||||
@@ -495,7 +501,7 @@
|
||||
subItems: [
|
||||
{
|
||||
label: 'Audit logs',
|
||||
href: `${base}/audit_logs`,
|
||||
href: `${$wsBase}/audit_logs`,
|
||||
icon: Eye,
|
||||
aiId: 'sidebar-menu-link-audit-logs',
|
||||
aiDescription: 'Button to navigate to audit logs'
|
||||
@@ -504,7 +510,7 @@
|
||||
? [
|
||||
{
|
||||
label: 'Service logs',
|
||||
href: `${base}/service_logs`,
|
||||
href: `${$wsBase}/service_logs`,
|
||||
icon: Logs,
|
||||
aiId: 'sidebar-menu-link-service-logs',
|
||||
aiDescription: 'Button to navigate to service logs'
|
||||
@@ -529,7 +535,7 @@
|
||||
}
|
||||
: {
|
||||
label: 'Audit logs',
|
||||
href: `${base}/audit_logs`,
|
||||
href: `${$wsBase}/audit_logs`,
|
||||
icon: Eye,
|
||||
disabled: $userStore?.operator,
|
||||
aiId: 'sidebar-menu-link-audit-logs',
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
import { base } from '$lib/base'
|
||||
import { page } from '$app/state'
|
||||
import { switchWorkspace } from '$lib/storeUtils'
|
||||
import { stripWsPrefix } from '$lib/workspaceUrl'
|
||||
import MultiplayerMenu from './MultiplayerMenu.svelte'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
@@ -58,14 +59,13 @@
|
||||
]
|
||||
const isOnEditPage = editPages.some((editPage) => page.route.id?.includes(editPage) ?? false)
|
||||
|
||||
if (!isOnEditPage) {
|
||||
switchWorkspace(id)
|
||||
if (page.url.searchParams.get('workspace')) {
|
||||
page.url.searchParams.set('workspace', id)
|
||||
}
|
||||
} else {
|
||||
switchWorkspace(id)
|
||||
switchWorkspace(id)
|
||||
if (isOnEditPage) {
|
||||
await goto('/')
|
||||
} else {
|
||||
// Stay on same page in new workspace
|
||||
const strippedPath = stripWsPrefix(page.url.pathname)
|
||||
await goto(strippedPath)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
import RelationPicker from './RelationPicker.svelte'
|
||||
import { invalidRelations, savePostgresTriggerFromCfg } from './utils'
|
||||
import CheckPostgresRequirement from './CheckPostgresRequirement.svelte'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { untrack, type Snippet } from 'svelte'
|
||||
import TriggerEditorToolbar from '../TriggerEditorToolbar.svelte'
|
||||
import PermissionedAsLine from '../PermissionedAsLine.svelte'
|
||||
@@ -431,7 +431,7 @@
|
||||
postgres_resource_path
|
||||
}
|
||||
})
|
||||
window.open(`${base}/scripts/add?id=${templateId}`)
|
||||
window.open(`${$wsBase}/scripts/add?id=${templateId}`)
|
||||
loading = false
|
||||
} catch (error) {
|
||||
loading = false
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
} from '$lib/gen'
|
||||
import { enterpriseLicense, userStore, workspaceStore } from '$lib/stores'
|
||||
import { canWrite, emptyString, formatCron, sendUserToast, cronV1toV2 } from '$lib/utils'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import Section from '$lib/components/Section.svelte'
|
||||
import { List, Loader2, Save, AlertTriangle } from 'lucide-svelte'
|
||||
import autosize from '$lib/autosize'
|
||||
@@ -664,7 +664,7 @@
|
||||
variant="default"
|
||||
startIcon={{ icon: List }}
|
||||
disabled={!allowSchedule || pathError != '' || emptyString(script_path)}
|
||||
href={`${base}/runs/${script_path}?show_schedules=true&show_future_jobs=true`}
|
||||
href={`${$wsBase}/runs/${script_path}?show_schedules=true&show_future_jobs=true`}
|
||||
>
|
||||
View runs
|
||||
</Button>
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import { goto as svelteGoto } from '$app/navigation'
|
||||
import { base as svelteBase } from '$app/paths'
|
||||
import { toWorkspacePath } from './workspaceUrl'
|
||||
|
||||
export function goto(path: string, options = {}) {
|
||||
if (svelteBase == '' || path.startsWith('?')) {
|
||||
if (path.startsWith('?') || path.startsWith('#')) {
|
||||
return svelteGoto(path, options)
|
||||
} else {
|
||||
const fullPath = path.startsWith(svelteBase) ? path : `${svelteBase}${path}`
|
||||
return svelteGoto(fullPath, options)
|
||||
}
|
||||
|
||||
let fullPath = toWorkspacePath(path)
|
||||
|
||||
if (svelteBase && !fullPath.startsWith(svelteBase)) {
|
||||
fullPath = `${svelteBase}${fullPath}`
|
||||
}
|
||||
|
||||
return svelteGoto(fullPath, options)
|
||||
}
|
||||
|
||||
export async function setQuery(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { get } from 'svelte/store'
|
||||
import { base } from '$lib/base'
|
||||
import { getWsBase } from '$lib/workspaceUrl'
|
||||
import type { Schema, SupportedLanguage } from './common'
|
||||
import { FlowService, type Script, ScriptService, ScheduleService } from './gen'
|
||||
import { workspaceStore } from './stores'
|
||||
@@ -125,7 +125,7 @@ export function scriptPathToHref(path: string, hubBaseUrl: string): string {
|
||||
if (path.startsWith('hub/')) {
|
||||
return hubBaseUrl + '/from_version/' + path.substring(4)
|
||||
} else {
|
||||
return `${base}/scripts/get/${path}?workspace=${get(workspaceStore)}`
|
||||
return `${getWsBase()}/scripts/get/${path}`
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import { base } from '$lib/base'
|
||||
import { getWsBase } from '$lib/workspaceUrl'
|
||||
|
||||
type ItemType = 'script' | 'flow' | 'app' | 'raw_app'
|
||||
|
||||
export function buildForkEditUrl(itemType: ItemType, itemPath: string): string {
|
||||
const wsBase = getWsBase()
|
||||
let editPath: string
|
||||
switch (itemType) {
|
||||
case 'script':
|
||||
editPath = `${base}/scripts/edit/${itemPath}`
|
||||
editPath = `${wsBase}/scripts/edit/${itemPath}`
|
||||
break
|
||||
case 'flow':
|
||||
editPath = `${base}/flows/edit/${itemPath}?nodraft=true`
|
||||
editPath = `${wsBase}/flows/edit/${itemPath}?nodraft=true`
|
||||
break
|
||||
case 'app':
|
||||
editPath = `${base}/apps/edit/${itemPath}?nodraft=true`
|
||||
editPath = `${wsBase}/apps/edit/${itemPath}?nodraft=true`
|
||||
break
|
||||
case 'raw_app':
|
||||
editPath = `${base}/apps_raw/edit/${itemPath}?nodraft=true`
|
||||
editPath = `${wsBase}/apps_raw/edit/${itemPath}?nodraft=true`
|
||||
break
|
||||
}
|
||||
return `${base}/user/fork_workspace?rd=${encodeURIComponent(editPath)}`
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { derived, get } from 'svelte/store'
|
||||
import { workspaceStore } from './stores'
|
||||
import { base } from './base'
|
||||
|
||||
const GLOBAL_PATH_PREFIXES = [
|
||||
'/user/',
|
||||
'/oauth/',
|
||||
'/approve/',
|
||||
'/public/',
|
||||
'/a/',
|
||||
'/api/',
|
||||
'/view_graph',
|
||||
'/kitchen_sink',
|
||||
'/gh_success',
|
||||
'/test_dev',
|
||||
'/dev'
|
||||
]
|
||||
|
||||
/** Extract workspace ID from a URL pathname matching `/w/<workspace>/...` */
|
||||
export function extractWorkspaceFromPath(pathname: string): string | undefined {
|
||||
const stripped = base && pathname.startsWith(base) ? pathname.slice(base.length) : pathname
|
||||
const match = stripped.match(/^\/w\/([^/]+)/)
|
||||
return match?.[1]
|
||||
}
|
||||
|
||||
/** Strip `/w/<workspace>` prefix from a pathname, returning the rest */
|
||||
export function stripWsPrefix(pathname: string): string {
|
||||
const stripped = base && pathname.startsWith(base) ? pathname.slice(base.length) : pathname
|
||||
const match = stripped.match(/^\/w\/[^/]+(\/.*)?$/)
|
||||
if (match) {
|
||||
return match[1] || '/'
|
||||
}
|
||||
return stripped
|
||||
}
|
||||
|
||||
/** Returns true if the path is global (not workspace-scoped) */
|
||||
export function isGlobalPath(path: string): boolean {
|
||||
if (path.startsWith('?') || path.startsWith('#')) return true
|
||||
const stripped = base && path.startsWith(base) ? path.slice(base.length) : path
|
||||
// Already has /w/ prefix
|
||||
if (stripped.match(/^\/w\/[^/]+/)) return true
|
||||
return GLOBAL_PATH_PREFIXES.some((prefix) => stripped.startsWith(prefix))
|
||||
}
|
||||
|
||||
/** Prepend `/w/<workspace>` to a workspace-scoped path */
|
||||
export function toWorkspacePath(path: string, workspace?: string): string {
|
||||
if (isGlobalPath(path)) return path
|
||||
const ws = workspace ?? get(workspaceStore)
|
||||
if (!ws) return path
|
||||
return `/w/${ws}${path}`
|
||||
}
|
||||
|
||||
/** Reactive store: `base + '/w/' + workspace` for use in `<a href>` attributes */
|
||||
export const wsBase = derived(workspaceStore, ($ws) => {
|
||||
if (!$ws) return base
|
||||
return `${base}/w/${$ws}`
|
||||
})
|
||||
|
||||
/** Imperative getter: returns `base + '/w/' + workspace` synchronously */
|
||||
export function getWsBase(workspace?: string): string {
|
||||
const ws = workspace ?? get(workspaceStore)
|
||||
if (!ws) return base
|
||||
return `${base}/w/${ws}`
|
||||
}
|
||||
@@ -56,6 +56,7 @@
|
||||
import GlobalSearchModal from '$lib/components/search/GlobalSearchModal.svelte'
|
||||
import MenuButton from '$lib/components/sidebar/MenuButton.svelte'
|
||||
import { loadProtectionRules } from '$lib/workspaceProtectionRules.svelte'
|
||||
import { extractWorkspaceFromPath, stripWsPrefix, isGlobalPath } from '$lib/workspaceUrl'
|
||||
import { setContext, untrack } from 'svelte'
|
||||
import { base } from '$app/paths'
|
||||
import { Menubar } from '$lib/components/meltComponents'
|
||||
@@ -107,14 +108,34 @@
|
||||
}
|
||||
|
||||
function onQueryChange() {
|
||||
let queryWorkspace = page.url.searchParams.get('workspace')
|
||||
if (queryWorkspace) {
|
||||
$workspaceStore = queryWorkspace
|
||||
// Extract workspace from URL path /w/<workspace>/...
|
||||
const wsFromUrl = extractWorkspaceFromPath(page.url.pathname)
|
||||
if (wsFromUrl && wsFromUrl !== $workspaceStore) {
|
||||
$workspaceStore = wsFromUrl
|
||||
}
|
||||
|
||||
// Backward compat: support ?workspace=X query param, redirect to /w/X/...
|
||||
let queryWorkspace = page.url.searchParams.get('workspace')
|
||||
if (queryWorkspace && !wsFromUrl) {
|
||||
$workspaceStore = queryWorkspace
|
||||
const strippedPath = stripWsPrefix(page.url.pathname)
|
||||
goto(`${strippedPath}${page.url.search.replace(/[?&]workspace=[^&]+/, '')}`, {
|
||||
replaceState: true
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Redirect old URLs (no /w/ prefix) to new format
|
||||
if (!wsFromUrl && $workspaceStore && !isGlobalPath(page.url.pathname)) {
|
||||
const strippedPath = stripWsPrefix(page.url.pathname)
|
||||
goto(`${strippedPath}${page.url.search}`, { replaceState: true })
|
||||
return
|
||||
}
|
||||
|
||||
const strippedPathname = stripWsPrefix(page.url.pathname)
|
||||
menuHidden =
|
||||
page.url.searchParams.get('nomenubar') === 'true' ||
|
||||
page.url.pathname.startsWith('/oauth/callback/')
|
||||
strippedPathname.startsWith('/oauth/callback/')
|
||||
}
|
||||
|
||||
async function updateUserStore(workspace: string | undefined) {
|
||||
@@ -144,8 +165,12 @@
|
||||
// This ensures the cross-origin isolation headers are fetched from the server
|
||||
// which are required for SharedArrayBuffer and TypeScript workers to work correctly
|
||||
const toPath = navigation.to?.url.pathname
|
||||
? stripWsPrefix(navigation.to.url.pathname)
|
||||
: undefined
|
||||
if (toPath && (toPath.startsWith('/apps_raw/add') || toPath.startsWith('/apps_raw/edit'))) {
|
||||
const currentPath = navigation.from?.url.pathname
|
||||
? stripWsPrefix(navigation.from.url.pathname)
|
||||
: undefined
|
||||
// Reload if we're not on an apps_raw path, or if we're on /apps/get_raw/ (viewing a raw app)
|
||||
// The /apps/get_raw/ path doesn't have cross-origin isolation headers, so we need to reload
|
||||
if (!currentPath?.startsWith('/apps_raw/') || currentPath?.startsWith('/apps_raw/get/')) {
|
||||
@@ -295,12 +320,13 @@
|
||||
|
||||
function pathInAppMode(pathname: string | undefined): boolean {
|
||||
if (!pathname) return false
|
||||
const stripped = stripWsPrefix(pathname)
|
||||
return (
|
||||
pathname.startsWith(base + '/apps') ||
|
||||
pathname.startsWith(base + '/flows/add') ||
|
||||
pathname.startsWith(base + '/flows/edit') ||
|
||||
pathname.startsWith(base + '/scripts/add') ||
|
||||
pathname.startsWith(base + '/scripts/edit')
|
||||
stripped.startsWith(base + '/apps') ||
|
||||
stripped.startsWith(base + '/flows/add') ||
|
||||
stripped.startsWith(base + '/flows/edit') ||
|
||||
stripped.startsWith(base + '/scripts/add') ||
|
||||
stripped.startsWith(base + '/scripts/edit')
|
||||
)
|
||||
}
|
||||
afterNavigate((n) => {
|
||||
@@ -315,7 +341,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
let devOnly = $derived(page.url.pathname.startsWith(base + '/scripts/dev'))
|
||||
let devOnly = $derived(stripWsPrefix(page.url.pathname).startsWith(base + '/scripts/dev'))
|
||||
|
||||
async function loadDefaultScripts(workspace: string, user: UserExt | undefined) {
|
||||
if (!user?.operator) {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
LayoutDashboard
|
||||
} from 'lucide-svelte'
|
||||
import { hubBaseUrlStore } from '$lib/stores'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
|
||||
import ItemsList from '$lib/components/home/ItemsList.svelte'
|
||||
import CreateActionsApp from '$lib/components/flows/CreateActionsApp.svelte'
|
||||
@@ -148,7 +148,7 @@
|
||||
</div>
|
||||
</Button>
|
||||
<Button
|
||||
href="{base}/scripts/add?hub={encodeURIComponent(codeViewerObj?.path ?? '')}"
|
||||
href="{$wsBase}/scripts/add?hub={encodeURIComponent(codeViewerObj?.path ?? '')}"
|
||||
startIcon={{ icon: GitFork }}
|
||||
variant="accent"
|
||||
size="xs"
|
||||
@@ -185,7 +185,7 @@
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
href="{base}/flows/add?hub={flowViewerFlow?.flow?.id}"
|
||||
href="{$wsBase}/flows/add?hub={flowViewerFlow?.flow?.id}"
|
||||
startIcon={{ icon: GitFork }}
|
||||
variant="accent"
|
||||
size="xs"
|
||||
@@ -227,7 +227,7 @@
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
href="{base}/apps/add?hub={appViewerApp?.app?.id}"
|
||||
href="{$wsBase}/apps/add?hub={appViewerApp?.app?.id}"
|
||||
startIcon={{ icon: GitFork }}
|
||||
variant="accent"
|
||||
disabled={appViewerApp == undefined}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import AppPreview from '$lib/components/apps/editor/AppPreview.svelte'
|
||||
import type { EditorBreakpoint } from '$lib/components/apps/types'
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
size="sm"
|
||||
startIcon={{ icon: Pen }}
|
||||
variant="subtle"
|
||||
href="{base}/apps/edit/{app.path}?nodraft=true">Edit</Button
|
||||
href="{$wsBase}/apps/edit/{app.path}?nodraft=true">Edit</Button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { afterNavigate, replaceState } from '$app/navigation'
|
||||
import { goto } from '$lib/navigation'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
|
||||
import RawAppEditor from '$lib/components/raw_apps/RawAppEditor.svelte'
|
||||
@@ -422,7 +423,7 @@
|
||||
{#if $userStore?.is_admin}
|
||||
Configure datatables in
|
||||
<a
|
||||
href="/workspace_settings?tab=windmill_data_tables"
|
||||
href="{$wsBase}/workspace_settings?tab=windmill_data_tables"
|
||||
target="_blank"
|
||||
class="inline-flex items-center gap-1"
|
||||
>workspace settings <ExternalLinkIcon size={16} />
|
||||
@@ -547,7 +548,7 @@
|
||||
{#if $userStore?.is_admin}
|
||||
Configure AI in
|
||||
<a
|
||||
href="/workspace_settings?tab=ai"
|
||||
href="{$wsBase}/workspace_settings?tab=ai"
|
||||
target="_blank"
|
||||
class="inline-flex items-center gap-1 font-semibold"
|
||||
>workspace settings <ExternalLinkIcon size={16} />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import type { ConcurrencyGroup } from '$lib/gen'
|
||||
import { ConcurrencyGroupsService } from '$lib/gen'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import { Button } from '$lib/components/common'
|
||||
@@ -91,7 +91,7 @@
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href={`${base}/runs/?job_kinds=all&graph=ConcurrencyChart&concurrency_key=${concurrency_key}`}
|
||||
href={`${$wsBase}/runs/?job_kinds=all&graph=ConcurrencyChart&concurrency_key=${concurrency_key}`}
|
||||
>{concurrency_key}
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import DetailPageLayout from '$lib/components/details/DetailPageLayout.svelte'
|
||||
import { goto } from '$lib/navigation'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import { Badge as HeaderBadge, Alert } from '$lib/components/common'
|
||||
import MoveDrawer from '$lib/components/MoveDrawer.svelte'
|
||||
import RunForm from '$lib/components/RunForm.svelte'
|
||||
@@ -197,7 +197,7 @@
|
||||
tag: overrideTag,
|
||||
skipPreprocessor: true
|
||||
})
|
||||
await goto('/run/' + run + '?workspace=' + $workspaceStore)
|
||||
await goto('/run/' + run)
|
||||
} catch (e) {
|
||||
throw e
|
||||
} finally {
|
||||
@@ -247,7 +247,7 @@
|
||||
buttons.push({
|
||||
label: 'Fork',
|
||||
buttonProps: {
|
||||
href: `${base}/flows/add?template=${flow.path}`,
|
||||
href: `${$wsBase}/flows/add?template=${flow.path}`,
|
||||
variant: 'subtle',
|
||||
unifiedSize: 'md',
|
||||
disabled: !showEditButtons,
|
||||
@@ -275,7 +275,7 @@
|
||||
buttons.push({
|
||||
label: `Runs`,
|
||||
buttonProps: {
|
||||
href: `${base}/runs/${flow.path}`,
|
||||
href: `${$wsBase}/runs/${flow.path}`,
|
||||
unifiedSize: 'md',
|
||||
variant: 'subtle',
|
||||
startIcon: Play
|
||||
@@ -315,7 +315,7 @@
|
||||
buttons.push({
|
||||
label: 'Edit',
|
||||
buttonProps: {
|
||||
href: `${base}/flows/edit/${path}?nodraft=true`,
|
||||
href: `${$wsBase}/flows/edit/${path}?nodraft=true`,
|
||||
variant: 'accent',
|
||||
unifiedSize: 'md',
|
||||
disabled: !can_write || !showEditButtons,
|
||||
@@ -474,7 +474,7 @@
|
||||
<MoveDrawer
|
||||
bind:this={moveDrawer}
|
||||
on:update={async (e) => {
|
||||
await goto('/flows/get/' + e.detail + `?workspace=${$workspaceStore}`)
|
||||
await goto('/flows/get/' + e.detail)
|
||||
loadFlow()
|
||||
}}
|
||||
/>
|
||||
@@ -515,7 +515,7 @@
|
||||
onSaved={can_write
|
||||
? async (newPath) => {
|
||||
if (newPath !== flow?.path) {
|
||||
await goto(`/flows/get/${newPath}?workspace=${$workspaceStore}`)
|
||||
await goto(`/flows/get/${newPath}`)
|
||||
} else {
|
||||
loadFlow()
|
||||
}
|
||||
@@ -593,7 +593,7 @@
|
||||
Deployment in progress
|
||||
{#if deploymentJobId}
|
||||
<a
|
||||
href="/run/{deploymentJobId}?workspace={$workspaceStore}"
|
||||
href="/run/{deploymentJobId}"
|
||||
class="underline"
|
||||
target="_blank">view job</a
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import {
|
||||
JobService,
|
||||
type Job,
|
||||
@@ -363,7 +363,7 @@
|
||||
})
|
||||
}
|
||||
|
||||
await goto('/run/' + id + '?workspace=' + $workspaceStore)
|
||||
await goto('/run/' + id)
|
||||
} else {
|
||||
sendUserToast('Cannot run this job immediately', true)
|
||||
}
|
||||
@@ -464,7 +464,7 @@
|
||||
</div>
|
||||
{/each}
|
||||
<div>
|
||||
<Button href="{base}/runs" unifiedSize="md" variant="accent">Go to runs page</Button>
|
||||
<Button href="{$wsBase}/runs" unifiedSize="md" variant="accent">Go to runs page</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -624,7 +624,7 @@
|
||||
{selectedJobStepType}
|
||||
{restartBranchNames}
|
||||
onRestartComplete={(newJobId) => {
|
||||
goto('/run/' + newJobId + '?workspace=' + $workspaceStore)
|
||||
goto('/run/' + newJobId)
|
||||
}}
|
||||
flowPath={job.script_path}
|
||||
flowVersionId={job.script_hash ? parseInt(job.script_hash, 16) : undefined}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
WorkspaceService
|
||||
} from '$lib/gen'
|
||||
import { canWrite, displayDate, getLocalSetting, storeLocalSetting } from '$lib/utils'
|
||||
import { base } from '$app/paths'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import { Badge, Button, Skeleton } from '$lib/components/common'
|
||||
import Dropdown from '$lib/components/DropdownV2.svelte'
|
||||
@@ -362,7 +362,7 @@
|
||||
/>
|
||||
<div class="flex gap-2 items-center justify-end">
|
||||
<Button
|
||||
href={`${base}/runs/?schedule_path=${path}&show_schedules=true&show_future_jobs=true`}
|
||||
href={`${$wsBase}/runs/?schedule_path=${path}&show_schedules=true&show_future_jobs=true`}
|
||||
unifiedSize="md"
|
||||
startIcon={{ icon: List }}
|
||||
variant="subtle"
|
||||
@@ -433,7 +433,7 @@
|
||||
displayName: 'View runs',
|
||||
icon: List,
|
||||
href:
|
||||
base +
|
||||
$wsBase +
|
||||
'/runs/?schedule_path=' +
|
||||
path +
|
||||
'&show_schedules=true&show_future_jobs=true'
|
||||
@@ -441,7 +441,7 @@
|
||||
{
|
||||
displayName: 'Audit logs',
|
||||
icon: Eye,
|
||||
href: `${base}/audit_logs?resource=${path}`
|
||||
href: `${$wsBase}/audit_logs?resource=${path}`
|
||||
},
|
||||
{
|
||||
displayName: 'Run now',
|
||||
@@ -476,7 +476,7 @@
|
||||
{/if}
|
||||
{#each jobs ?? [] as job}
|
||||
{@const h = (avg_s ? job.duration_ms / avg_s : 1) * 7 + 3}
|
||||
<a href="{base}/run/{job.id}?workspace={$workspaceStore}">
|
||||
<a href="{$wsBase}/run/{job.id}">
|
||||
<JobPreview id={job.id} class="p-4">
|
||||
<div>
|
||||
<div
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import {
|
||||
JobService,
|
||||
ScriptService,
|
||||
@@ -309,7 +309,7 @@
|
||||
skipPreprocessor: true
|
||||
})
|
||||
}
|
||||
await goto('/run/' + run + '?workspace=' + $workspaceStore)
|
||||
await goto('/run/' + run)
|
||||
} catch (err) {
|
||||
runLoading = false
|
||||
sendUserToast(`Could not create job: ${err.body}`, true)
|
||||
@@ -348,7 +348,7 @@
|
||||
buttons.push({
|
||||
label: 'Fork',
|
||||
buttonProps: {
|
||||
href: `${base}/scripts/add?template=${script.path}`,
|
||||
href: `${$wsBase}/scripts/add?template=${script.path}`,
|
||||
unifiedSize: 'md',
|
||||
variant: 'subtle',
|
||||
disabled: !showEditButtons,
|
||||
@@ -381,7 +381,7 @@
|
||||
buttons.push({
|
||||
label: `Runs`,
|
||||
buttonProps: {
|
||||
href: `${base}/runs/${script.path}`,
|
||||
href: `${$wsBase}/runs/${script.path}`,
|
||||
unifiedSize: 'md',
|
||||
variant: 'subtle',
|
||||
startIcon: Play
|
||||
@@ -441,7 +441,7 @@
|
||||
buttons.push({
|
||||
label: 'Edit',
|
||||
buttonProps: {
|
||||
href: `${base}/scripts/edit/${script.path}?${
|
||||
href: `${$wsBase}/scripts/edit/${script.path}?${
|
||||
topHash ? `&hash=${script.hash}&topHash=` + topHash : ''
|
||||
}`,
|
||||
unifiedSize: 'md',
|
||||
@@ -613,7 +613,7 @@
|
||||
<MoveDrawer
|
||||
bind:this={moveDrawer}
|
||||
on:update={async (e) => {
|
||||
await goto('/scripts/get/' + e.detail + `?workspace=${$workspaceStore}`)
|
||||
await goto('/scripts/get/' + e.detail)
|
||||
loadScript(page.params.hash ?? '')
|
||||
}}
|
||||
/>
|
||||
@@ -632,7 +632,7 @@
|
||||
openDetails
|
||||
on:openDetails={(e) => {
|
||||
if (script) {
|
||||
goto(`/scripts/get/${e.detail.version}?workspace=${$workspaceStore}`)
|
||||
goto(`/scripts/get/${e.detail.version}`)
|
||||
}
|
||||
versionsDrawerOpen = false
|
||||
}}
|
||||
@@ -663,7 +663,7 @@
|
||||
onSaved={can_write
|
||||
? async (newPath) => {
|
||||
if (newPath !== script?.path) {
|
||||
await goto(`/scripts/get/${newPath}?workspace=${$workspaceStore}`)
|
||||
await goto(`/scripts/get/${newPath}`)
|
||||
} else {
|
||||
loadScript(page.params.hash ?? '')
|
||||
}
|
||||
@@ -750,7 +750,7 @@
|
||||
<div class="mt-2"></div>
|
||||
<Alert type="warning" title="Not HEAD">
|
||||
This hash is not HEAD (latest non-archived version at this path) :
|
||||
<a href="{base}/scripts/get/{topHash}?workspace={$workspaceStore}"
|
||||
<a href="{$wsBase}/scripts/get/{topHash}"
|
||||
>Go to the HEAD of this path</a
|
||||
>
|
||||
</Alert>
|
||||
@@ -784,7 +784,7 @@
|
||||
Deployment in progress
|
||||
{#if deploymentJobId}
|
||||
<a
|
||||
href="/run/{deploymentJobId}?workspace={$workspaceStore}"
|
||||
href="/run/{deploymentJobId}"
|
||||
class="underline"
|
||||
target="_blank">view job</a
|
||||
>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
whitelabelNameStore
|
||||
} from '$lib/stores'
|
||||
import { classNames, emptyString, parseQueryParams } from '$lib/utils'
|
||||
import { extractWorkspaceFromPath } from '$lib/workspaceUrl'
|
||||
import { getUserExt } from '$lib/user'
|
||||
import { WindmillIcon } from '$lib/components/icons'
|
||||
import LoginPageHeader from '$lib/components/LoginPageHeader.svelte'
|
||||
@@ -69,7 +70,10 @@
|
||||
if ($workspaceStore) {
|
||||
goto(rd ?? '/')
|
||||
} else {
|
||||
let workspaceTarget = parseQueryParams(rd ?? undefined)['workspace']
|
||||
// Extract workspace from rd path (/w/<ws>/...) or query param (?workspace=X)
|
||||
let workspaceTarget =
|
||||
extractWorkspaceFromPath(rd ?? '') ??
|
||||
parseQueryParams(rd ?? undefined)['workspace']
|
||||
if (rd && workspaceTarget) {
|
||||
$workspaceStore = workspaceTarget
|
||||
goto(rd)
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
type S3ResourceSettings
|
||||
} from '$lib/workspace_settings'
|
||||
import { base } from '$lib/base'
|
||||
import { wsBase } from '$lib/workspaceUrl'
|
||||
import ConnectionSection from '$lib/components/ConnectionSection.svelte'
|
||||
import AISettings from '$lib/components/workspaceSettings/AISettings.svelte'
|
||||
import StorageSettings from '$lib/components/workspaceSettings/StorageSettings.svelte'
|
||||
@@ -1315,8 +1316,8 @@
|
||||
}}
|
||||
onSelect={editSlackCommand}
|
||||
connectHref="{base}/api/oauth/connect_slack"
|
||||
createScriptHref="{base}/scripts/add?hub=hub%2F28071%2Fslack%2Fexample_of_responding_to_a_slack_command_slack"
|
||||
createFlowHref="{base}/flows/add?hub=28"
|
||||
createScriptHref="{$wsBase}/scripts/add?hub=hub%2F28071%2Fslack%2Fexample_of_responding_to_a_slack_command_slack"
|
||||
createFlowHref="{$wsBase}/flows/add?hub=28"
|
||||
documentationLink="https://www.windmill.dev/docs/integrations/slack"
|
||||
onLoadSettings={loadSettings}
|
||||
display_name={slack_team_name}
|
||||
@@ -1451,8 +1452,8 @@
|
||||
}}
|
||||
onSelect={editTeamsCommand}
|
||||
connectHref={undefined}
|
||||
createScriptHref="{base}/scripts/add?hub=hub%2F11591%2Fteams%2FExample%20of%20responding%20to%20a%20Microsoft%20Teams%20command"
|
||||
createFlowHref="{base}/flows/add?hub=58"
|
||||
createScriptHref="{$wsBase}/scripts/add?hub=hub%2F11591%2Fteams%2FExample%20of%20responding%20to%20a%20Microsoft%20Teams%20command"
|
||||
createFlowHref="{$wsBase}/flows/add?hub=58"
|
||||
documentationLink="https://www.windmill.dev/docs/integrations/teams"
|
||||
onLoadSettings={loadSettings}
|
||||
display_name={teams_team_name}
|
||||
@@ -1684,7 +1685,7 @@
|
||||
/>
|
||||
<Button
|
||||
variant="default"
|
||||
href={`${base}/scripts/add?lang=bun#` +
|
||||
href={`${$wsBase}/scripts/add?lang=bun#` +
|
||||
encodeState({
|
||||
path: 'f/success_handler',
|
||||
summary: 'Workspace Success Handler',
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { onDestroy, onMount } from 'svelte'
|
||||
|
||||
import { refreshSuperadmin } from '$lib/refreshUser'
|
||||
import { extractWorkspaceFromPath, stripWsPrefix } from '$lib/workspaceUrl'
|
||||
// import EditorTheme from '$lib/components/EditorTheme.svelte'
|
||||
import { computeDrift } from '$lib/forLater'
|
||||
import { setLicense } from '$lib/enterpriseUtils'
|
||||
@@ -40,6 +41,14 @@
|
||||
try {
|
||||
await refreshSuperadmin()
|
||||
|
||||
// Extract workspace from URL path if present
|
||||
if (!$workspaceStore) {
|
||||
const wsFromUrl = extractWorkspaceFromPath(page.url.pathname)
|
||||
if (wsFromUrl) {
|
||||
$workspaceStore = wsFromUrl
|
||||
}
|
||||
}
|
||||
|
||||
if ($workspaceStore) {
|
||||
if ($userStore) {
|
||||
console.log(`Welcome back ${$userStore.username} to ${$workspaceStore}`)
|
||||
@@ -50,9 +59,10 @@
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const strippedPath = stripWsPrefix(page.url.pathname)
|
||||
if (
|
||||
(!page.url.pathname.startsWith('/user/') || page.url.pathname.startsWith('/user/cli')) &&
|
||||
!page.url.pathname.startsWith('/oauth/mcp_authorize')
|
||||
(!strippedPath.startsWith('/user/') || strippedPath.startsWith('/user/cli')) &&
|
||||
!strippedPath.startsWith('/oauth/mcp_authorize')
|
||||
) {
|
||||
goto(
|
||||
`/user/workspaces?rd=${encodeURIComponent(page.url.href.replace(page.url.origin, ''))}`
|
||||
@@ -63,7 +73,8 @@
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
if (page.url.pathname != '/user/login' && page.url.pathname != '/user/logout') {
|
||||
const strippedPath = stripWsPrefix(page.url.pathname)
|
||||
if (strippedPath != '/user/login' && strippedPath != '/user/logout') {
|
||||
const url = page.url
|
||||
console.log('logout 5', url.href.replace(url.origin, ''))
|
||||
await logoutWithRedirect(url.href.replace(url.origin, ''))
|
||||
|
||||
Reference in New Issue
Block a user