mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-23 16:00:38 +00:00
fix: isolate SvelteKit-specific imports for library usage
Split SvelteKit-specific code into separate files to allow windmill-components to be used as a library in non-SvelteKit contexts (e.g., windmill-react-sdk): - Split logout.ts into logout.ts and logoutKit.ts - Split svelte5Utils.svelte.ts into svelte5Utils.svelte.ts and svelte5UtilsKit.svelte.ts (for runed/kit useSearchParams) - Fix triggers/utils.ts type-only import resolution - Update FlowRestartButton to use callback instead of direct navigation - Update all route files to import from logoutKit Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
import { FlowService, JobService, type FlowVersion } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { emptyString, sendUserToast } from '$lib/utils'
|
||||
import { goto } from '$lib/navigation'
|
||||
|
||||
interface Props {
|
||||
jobId: string
|
||||
@@ -17,7 +16,10 @@
|
||||
enterpriseOnly?: boolean
|
||||
variant?: 'default' | 'accent'
|
||||
unifiedSize?: 'xs' | 'sm' | 'md' | 'lg'
|
||||
/** Called when flow is restarted. If not provided, will navigate to the new run using goto (requires SvelteKit) */
|
||||
onRestart?: (stepId: string, branchOrIterationN: number, flowVersion?: number) => void
|
||||
/** Called when flow restart completes with the new job ID. Used for navigation in non-SvelteKit contexts */
|
||||
onRestartComplete?: (newJobId: string) => void
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -30,7 +32,8 @@
|
||||
enterpriseOnly = false,
|
||||
variant = 'default',
|
||||
unifiedSize = 'md',
|
||||
onRestart
|
||||
onRestart,
|
||||
onRestartComplete
|
||||
}: Props = $props()
|
||||
|
||||
let branchOrIterationN = $state(0)
|
||||
@@ -49,7 +52,7 @@
|
||||
flow_version: flowVersion
|
||||
}
|
||||
})
|
||||
await goto('/run/' + run + '?workspace=' + $workspaceStore)
|
||||
onRestartComplete?.(run)
|
||||
}
|
||||
|
||||
async function loadFlowVersions() {
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
import ToggleButton from '$lib/components/common/toggleButton-v2/ToggleButton.svelte'
|
||||
import Select from '$lib/components/select/Select.svelte'
|
||||
import AnimatedPane from '$lib/components/splitPanes/AnimatedPane.svelte'
|
||||
import { useSearchParams, StaleWhileLoading } from '$lib/svelte5Utils.svelte'
|
||||
import { useSearchParams } from '$lib/svelte5UtilsKit.svelte'
|
||||
import { StaleWhileLoading } from '$lib/svelte5Utils.svelte'
|
||||
|
||||
interface Props {
|
||||
/** Initial path from route params (e.g., /runs/u/user/script) */
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
} from '$lib/stores'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { USER_SETTINGS_HASH } from './settings'
|
||||
import { logout } from '$lib/logout'
|
||||
import { logout } from '$lib/logoutKit'
|
||||
import DarkModeObserver from '../DarkModeObserver.svelte'
|
||||
import BarsStaggered from '../icons/BarsStaggered.svelte'
|
||||
import { Menu, Menubar, MenuItem } from '$lib/components/meltComponents'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$lib/navigation'
|
||||
import { logout } from '$lib/logout'
|
||||
import { logout } from '$lib/logoutKit'
|
||||
import {
|
||||
userStore,
|
||||
usageStore,
|
||||
|
||||
@@ -14,7 +14,7 @@ import type {
|
||||
} from '$lib/gen/types.gen'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import SchedulePollIcon from '../icons/SchedulePollIcon.svelte'
|
||||
import { type TriggerKind } from '$lib/components/triggers'
|
||||
import type { TriggerKind } from '../triggers'
|
||||
import { saveScheduleFromCfg } from '$lib/components/flows/scheduleUtils'
|
||||
import { saveHttpRouteFromCfg } from './http/utils'
|
||||
import { saveWebsocketTriggerFromCfg } from './websocket/utils'
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
type CompletedJob
|
||||
} from '$lib/gen'
|
||||
import { validateUsername } from '$lib/utils'
|
||||
import { logoutWithRedirect } from '$lib/logout'
|
||||
import { logoutWithRedirect } from '$lib/logoutKit'
|
||||
import { page } from '$app/stores'
|
||||
import { usersWorkspaceStore, workspaceStore } from '$lib/stores'
|
||||
import CenteredModal from '$lib/components/CenteredModal.svelte'
|
||||
|
||||
@@ -1,33 +1,12 @@
|
||||
import { goto } from '$lib/navigation'
|
||||
import { UserService } from '$lib/gen'
|
||||
import { clearStores } from './storeUtils'
|
||||
import { sendUserToast } from './toast'
|
||||
|
||||
export async function logoutWithRedirect(rd?: string): Promise<void> {
|
||||
console.log('logoutWithRedirect', rd)
|
||||
await clearUser()
|
||||
const splitted = rd?.split('?')[0]
|
||||
if (rd && rd != '/' && splitted != '/user/login' && splitted != '/user/logout') {
|
||||
const error = document.cookie.includes('token')
|
||||
? `error=${encodeURIComponent('You have been logged out because your session has expired.')}&`
|
||||
: ''
|
||||
console.log('login redirect with error', error, rd)
|
||||
goto(`/user/login?${error}${rd ? 'rd=' + encodeURIComponent(rd) : ''}`, { replaceState: true })
|
||||
} else {
|
||||
console.log('login redirect vanilla')
|
||||
goto('/user/login', { replaceState: true })
|
||||
}
|
||||
}
|
||||
|
||||
export async function logout(): Promise<void> {
|
||||
await clearUser()
|
||||
goto(`/user/login`)
|
||||
sendUserToast('you have been logged out')
|
||||
}
|
||||
// Note: logout and logoutWithRedirect have been moved to logoutKit.ts
|
||||
// as they depend on SvelteKit navigation
|
||||
|
||||
export async function clearUser() {
|
||||
try {
|
||||
clearStores()
|
||||
await UserService.logout()
|
||||
} catch (error) { }
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// SvelteKit-specific logout utilities
|
||||
// These functions depend on $lib/navigation which requires SvelteKit
|
||||
|
||||
import { goto } from '$lib/navigation'
|
||||
import { clearUser } from './logout'
|
||||
import { sendUserToast } from './toast'
|
||||
|
||||
export async function logoutWithRedirect(rd?: string): Promise<void> {
|
||||
console.log('logoutWithRedirect', rd)
|
||||
await clearUser()
|
||||
const splitted = rd?.split('?')[0]
|
||||
if (rd && rd != '/' && splitted != '/user/login' && splitted != '/user/logout') {
|
||||
const error = document.cookie.includes('token')
|
||||
? `error=${encodeURIComponent('You have been logged out because your session has expired.')}&`
|
||||
: ''
|
||||
console.log('login redirect with error', error, rd)
|
||||
goto(`/user/login?${error}${rd ? 'rd=' + encodeURIComponent(rd) : ''}`, { replaceState: true })
|
||||
} else {
|
||||
console.log('login redirect vanilla')
|
||||
goto('/user/login', { replaceState: true })
|
||||
}
|
||||
}
|
||||
|
||||
export async function logout(): Promise<void> {
|
||||
await clearUser()
|
||||
goto(`/user/login`)
|
||||
sendUserToast('you have been logged out')
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { goto as svelteGoto } from '$app/navigation'
|
||||
import { base as svelteBase } from '$app/paths'
|
||||
|
||||
export function goto(path, options = {}) {
|
||||
export function goto(path: string, options = {}) {
|
||||
if (svelteBase == '' || path.startsWith('?')) {
|
||||
return svelteGoto(path, options)
|
||||
} else {
|
||||
|
||||
@@ -2,10 +2,8 @@
|
||||
|
||||
import { untrack } from 'svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { type StateStore } from './utils'
|
||||
import type { StateStore } from './utils'
|
||||
import { resource, watch, type ResourceReturn } from 'runed'
|
||||
import * as runed from 'runed/kit'
|
||||
import type z from 'zod'
|
||||
|
||||
export function withProps<Component, Props>(component: Component, props: Props) {
|
||||
const ret = $state({
|
||||
@@ -190,36 +188,6 @@ export class ChangeOnDeepInequality<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// The original from runed has a weird behavior with dedup reads causing duplicate effect runs
|
||||
// (Every field has to be derived to avoid it : https://runed.dev/docs/utilities/use-search-params)
|
||||
export function useSearchParams<S extends z.ZodType>(
|
||||
schema: S,
|
||||
options?: runed.SearchParamsOptions
|
||||
): runed.ReturnUseSearchParams<S> {
|
||||
let params = runed.useSearchParams(schema, options)
|
||||
let keys = Object.keys((schema as any).shape ?? {})
|
||||
let obj = { ...params }
|
||||
for (const key of keys) {
|
||||
// Somehow using $derived does not trigger reactivity sometimes ...
|
||||
// (e.g: filters.arg in RunsPage.svelte updates in the URL but does not trigger reactivity)
|
||||
let derivedVal = $state(params[key])
|
||||
Object.defineProperty(obj, key, {
|
||||
get: () => {
|
||||
if (typeof derivedVal === 'string') return decodeURIComponent(derivedVal)
|
||||
return derivedVal
|
||||
},
|
||||
set: (v) => {
|
||||
const val = typeof v === 'string' ? encodeURIComponent(v) : v
|
||||
params[key] = val
|
||||
derivedVal = val
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
})
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
// Prevents flickering when data is unloaded (undefined) then reloaded quickly
|
||||
// But still becomes undefined if data is not reloaded within the timeout
|
||||
// so the user has feedback that the data is not available anymore.
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// SvelteKit-specific utilities
|
||||
// This file should only be imported in SvelteKit apps as it depends on $app/environment
|
||||
|
||||
import * as runed from 'runed/kit'
|
||||
import type z from 'zod'
|
||||
|
||||
// The original from runed has a weird behavior with dedup reads causing duplicate effect runs
|
||||
// (Every field has to be derived to avoid it : https://runed.dev/docs/utilities/use-search-params)
|
||||
export function useSearchParams<S extends z.ZodType>(
|
||||
schema: S,
|
||||
options?: runed.SearchParamsOptions
|
||||
): runed.ReturnUseSearchParams<S> {
|
||||
let params = runed.useSearchParams(schema, options)
|
||||
let keys = Object.keys((schema as any).shape ?? {})
|
||||
let obj = { ...params }
|
||||
for (const key of keys) {
|
||||
// Somehow using $derived does not trigger reactivity sometimes ...
|
||||
// (e.g: filters.arg in RunsPage.svelte updates in the URL but does not trigger reactivity)
|
||||
let derivedVal = $state(params[key])
|
||||
Object.defineProperty(obj, key, {
|
||||
get: () => {
|
||||
if (typeof derivedVal === 'string') return decodeURIComponent(derivedVal)
|
||||
return derivedVal
|
||||
},
|
||||
set: (v) => {
|
||||
const val = typeof v === 'string' ? encodeURIComponent(v) : v
|
||||
params[key] = val
|
||||
derivedVal = val
|
||||
},
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
})
|
||||
}
|
||||
return obj
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
import { base } from '$app/paths'
|
||||
import { page } from '$app/stores'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import { logout, logoutWithRedirect } from '$lib/logout'
|
||||
import { logout, logoutWithRedirect } from '$lib/logoutKit'
|
||||
import { UserService, type WorkspaceInvite, WorkspaceService } from '$lib/gen'
|
||||
import {
|
||||
superadmin,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { goto } from '$lib/navigation'
|
||||
import { page } from '$app/stores'
|
||||
import { UserService, WorkspaceService } from '$lib/gen'
|
||||
import { logoutWithRedirect } from '$lib/logout'
|
||||
import { logoutWithRedirect } from '$lib/logoutKit'
|
||||
import { userStore, usersWorkspaceStore, workspaceStore } from '$lib/stores'
|
||||
import { getUserExt } from '$lib/user'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
import { userStore, usersWorkspaceStore, workspaceStore } from '$lib/stores'
|
||||
import { getUserExt } from '$lib/user'
|
||||
import { logoutWithRedirect } from '$lib/logout'
|
||||
import { logoutWithRedirect } from '$lib/logoutKit'
|
||||
import { parseQueryParams } from '$lib/utils'
|
||||
import { page } from '$app/state'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
|
||||
Reference in New Issue
Block a user