From 16c615e038ecdf23b72d12052e00636ffe464eb6 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Tue, 12 Mar 2024 21:50:24 +0100 Subject: [PATCH] feat: configurable languages and orders --- backend/windmill-api/openapi.yaml | 55 ++++ backend/windmill-api/src/workspaces.rs | 67 +++- .../src/lib/components/DefaultScripts.svelte | 28 ++ .../lib/components/DefaultScriptsInner.svelte | 75 +++++ .../src/lib/components/FieldHeader.svelte | 14 +- .../src/lib/components/ScriptBuilder.svelte | 103 +++--- frontend/src/lib/components/TimeAgo.svelte | 2 +- .../EmptyInlineScript.svelte | 30 +- .../flows/content/FlowInputs.svelte | 294 +++++------------- .../flows/pickers/FlowScriptPicker.svelte | 10 +- .../src/lib/components/runs/RunRow.svelte | 25 +- .../src/lib/components/runs/RunsTable.svelte | 2 +- frontend/src/lib/consts.ts | 4 - frontend/src/lib/script_helpers.ts | 1 + frontend/src/lib/scripts.ts | 17 + frontend/src/lib/stores.ts | 3 +- frontend/src/lib/utils.ts | 8 +- .../src/routes/(root)/(logged)/+layout.svelte | 39 ++- 18 files changed, 413 insertions(+), 364 deletions(-) create mode 100644 frontend/src/lib/components/DefaultScripts.svelte create mode 100644 frontend/src/lib/components/DefaultScriptsInner.svelte diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index b02ffb05ce..44c6a7cf5b 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1698,6 +1698,43 @@ paths: schema: type: string + /w/{workspace}/workspaces/default_scripts: + post: + summary: edit default scripts for workspace + operationId: editDefaultScripts + tags: + - workspace + parameters: + - $ref: "#/components/parameters/WorkspaceId" + requestBody: + description: Workspace default app + content: + application/json: + schema: + $ref: "#/components/schemas/WorkspaceDefaultScripts" + + responses: + "200": + description: status + content: + text/plain: + schema: + type: string + get: + summary: get default scripts for workspace + operationId: get default scripts + tags: + - workspace + parameters: + - $ref: "#/components/parameters/WorkspaceId" + responses: + "200": + description: status + content: + application/json: + schema: + $ref: "#/components/schemas/WorkspaceDefaultScripts" + /w/{workspace}/workspaces/encryption_key: get: summary: retrieves the encryption key for this workspace @@ -9834,6 +9871,24 @@ components: items: $ref: "#/components/schemas/GitRepositorySettings" + WorkspaceDefaultScripts: + type: object + properties: + order: + type: array + items: + type: string + hidden: + type: array + items: + type: string + default_script_content: + additionalProperties: + type: string + + + + GitRepositorySettings: type: object properties: diff --git a/backend/windmill-api/src/workspaces.rs b/backend/windmill-api/src/workspaces.rs index b11f43e052..b9ea884c66 100644 --- a/backend/windmill-api/src/workspaces.rs +++ b/backend/windmill-api/src/workspaces.rs @@ -100,6 +100,10 @@ pub fn workspaced_service() -> Router { .route("/edit_git_sync_config", post(edit_git_sync_config)) .route("/edit_default_app", post(edit_default_app)) .route("/default_app", get(get_default_app)) + .route( + "/default_scripts", + post(edit_default_scripts).get(get_default_scripts), + ) .route( "/encryption_key", get(get_encryption_key).post(set_encryption_key), @@ -164,6 +168,7 @@ pub struct WorkspaceSettings { pub git_sync: Option, // effectively: WorkspaceGitSyncSettings pub default_app: Option, pub automatic_billing: bool, + pub default_scripts: Option, } #[derive(FromRow, Serialize, Debug)] @@ -984,6 +989,66 @@ async fn edit_default_app( )); } +async fn edit_default_scripts( + authed: ApiAuthed, + Extension(db): Extension, + Path(w_id): Path, + ApiAuthed { is_admin, username, .. }: ApiAuthed, + Json(new_config): Json>, +) -> Result { + require_admin(is_admin, &username)?; + + let mut tx = db.begin().await?; + + audit_log( + &mut *tx, + &authed.username, + "workspaces.edit_default_scripts", + ActionKind::Update, + &w_id, + Some(&authed.email), + None, + ) + .await?; + + if let Some(config) = new_config { + sqlx::query!( + "UPDATE workspace_settings SET default_scripts = $1 WHERE workspace_id = $2", + config, + &w_id + ) + .execute(&mut *tx) + .await?; + } else { + sqlx::query!( + "UPDATE workspace_settings SET default_scripts = NULL WHERE workspace_id = $1", + &w_id, + ) + .execute(&mut *tx) + .await?; + } + tx.commit().await?; + + Ok(format!("Edit default scripts for workspace {}", &w_id)) +} + +async fn get_default_scripts( + Extension(db): Extension, + Path(w_id): Path, +) -> JsonResult> { + let mut tx = db.begin().await?; + let default_scripts = sqlx::query_scalar!( + "SELECT default_scripts FROM workspace_settings WHERE workspace_id = $1", + &w_id + ) + .fetch_optional(&mut *tx) + .await + .map_err(|err| Error::InternalErr(format!("getting default_app: {err}")))?; + tx.commit().await?; + + Ok(Json(default_scripts.flatten())) +} + #[cfg(feature = "enterprise")] async fn edit_default_app( authed: ApiAuthed, @@ -1012,7 +1077,7 @@ async fn edit_default_app( ActionKind::Update, &w_id, Some(&authed.email), - Some([("args_for_audit", args_for_audit.as_str())].into()), + Some([("default_app", args_for_audit.as_str())].into()), ) .await?; diff --git a/frontend/src/lib/components/DefaultScripts.svelte b/frontend/src/lib/components/DefaultScripts.svelte new file mode 100644 index 0000000000..1f0055d7e2 --- /dev/null +++ b/frontend/src/lib/components/DefaultScripts.svelte @@ -0,0 +1,28 @@ + + +{#if $userStore?.is_admin || $userStore?.is_super_admin} + + + + + + + + +{/if} diff --git a/frontend/src/lib/components/DefaultScriptsInner.svelte b/frontend/src/lib/components/DefaultScriptsInner.svelte new file mode 100644 index 0000000000..fa76183827 --- /dev/null +++ b/frontend/src/lib/components/DefaultScriptsInner.svelte @@ -0,0 +1,75 @@ + + + + This setting is only available to admins and will affect all users in the workspace. + +
+ {#each langs as lang, i (lang)} +

{lang}

+
+ {#if i > 0} + + {/if} + {#if i < langs.length - 1} + + {/if}
+ +
+ { + let toggled = e.detail + if (toggled) { + defaultScripts.update((s) => ({ ...(s ?? {}), hidden: [...(s?.hidden ?? []), lang] })) + } else { + defaultScripts.update((s) => ({ + ...(s ?? {}), + hidden: (s?.hidden ?? []).filter((h) => h != lang) + })) + } + }} + /> +
+
+ {/each} +
diff --git a/frontend/src/lib/components/FieldHeader.svelte b/frontend/src/lib/components/FieldHeader.svelte index 92bb41b72d..0dea7e0a14 100644 --- a/frontend/src/lib/components/FieldHeader.svelte +++ b/frontend/src/lib/components/FieldHeader.svelte @@ -16,7 +16,7 @@ export let simpleTooltip: string | undefined = undefined -
+
{#if prettify} {label.replace(/_/g, ' ').split(' ').map(capitalize).join(' ')} @@ -43,10 +43,10 @@ {/if} {#if !emptyString(simpleTooltip)} - - - {simpleTooltip} - - -{/if} + + + {simpleTooltip} + + + {/if}
diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index a3f73cd3fd..0fed12b79b 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -11,7 +11,7 @@ import { page } from '$app/stores' import { inferArgs } from '$lib/infer' import { initialCode } from '$lib/script_helpers' - import { enterpriseLicense, userStore, workspaceStore } from '$lib/stores' + import { defaultScripts, enterpriseLicense, userStore, workspaceStore } from '$lib/stores' import { cleanValueProperties, emptySchema, @@ -43,7 +43,6 @@ Settings, X } from 'lucide-svelte' - import { SCRIPT_SHOW_BASH, SCRIPT_SHOW_GO } from '$lib/consts' import UnsavedConfirmationModal from './common/confirmationModal/UnsavedConfirmationModal.svelte' import { sendUserToast } from '$lib/toast' import { isCloudHosted } from '$lib/cloud' @@ -61,11 +60,12 @@ import MetadataGen from './copilot/MetadataGen.svelte' import ScriptSchedules from './ScriptSchedules.svelte' import { writable } from 'svelte/store' - import { type ScriptSchedule, loadScriptSchedule } from '$lib/scripts' + import { type ScriptSchedule, loadScriptSchedule, defaultScriptLanguages } from '$lib/scripts' + import DefaultScripts from './DefaultScripts.svelte' export let script: NewScript export let initialPath: string = '' - export let template: 'pgsql' | 'mysql' | 'script' | 'docker' | 'powershell' = 'script' + export let template: 'docker' | 'script' = 'script' export let initialArgs: Record = {} export let lockedLanguage = false export let showMeta: boolean = false @@ -107,25 +107,11 @@ editor?.setCode(code) } - const langs: [string, SupportedLanguage][] = [ - ['TypeScript (Bun)', Script.language.BUN], - ['Python', Script.language.PYTHON3], - ['TypeScript (Deno)', Script.language.DENO] - ] - if (SCRIPT_SHOW_BASH) { - langs.push(['Bash', Script.language.BASH]) - } - if (SCRIPT_SHOW_GO) { - langs.push(['Go', Script.language.GO]) - } - langs.push(['REST', Script.language.NATIVETS]) - langs.push(['PostgreSQL', Script.language.POSTGRESQL]) - langs.push(['MySQL', Script.language.MYSQL]) - langs.push(['BigQuery', Script.language.BIGQUERY]) - langs.push(['Snowflake', Script.language.SNOWFLAKE]) - langs.push(['MS SQL Server', Script.language.MSSQL]) - langs.push(['GraphQL', Script.language.GRAPHQL]) - langs.push(['PowerShell', Script.language.POWERSHELL]) + $: langs = ($defaultScripts?.order ?? Object.keys(defaultScriptLanguages)) + .map((l) => [defaultScriptLanguages[l], l]) + .filter( + (x) => $defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1]) + ) as [string, SupportedLanguage | 'docker'][] const scriptKindOptions: { value: Script.kind @@ -551,14 +537,17 @@
+ {#if lockedLanguage}
As a forked script, the language '{script.language}' cannot be modified.
{/if}
- {#each langs as [label, lang]} - {@const isPicked = script.language == lang && template == 'script'} + {#each langs as [label, lang] (lang)} + {@const isPicked = + (lang == script.language && template == 'script') || + (template == 'docker' && lang == 'docker')} @@ -570,9 +559,33 @@ ? '!border-2 !bg-blue-50/75 dark:!bg-frost-900/75' : 'm-[1px]'} on:click={() => { - template = 'script' - initContent(lang, script.kind, template) - script.language = lang + if (lang == 'docker') { + if (isCloudHosted()) { + sendUserToast( + 'You cannot use Docker scripts on the multi-tenant platform. Use a dedicated instance or self-host windmill instead.', + true, + [ + { + label: 'Learn more', + callback: () => { + window.open( + 'https://www.windmill.dev/docs/advanced/docker', + '_blank' + ) + } + } + ] + ) + return + } + template = 'docker' + } else { + template = 'script' + } + let language = lang == 'docker' ? Script.language.BASH : lang + // + initContent(language, script.kind, template) + script.language = language }} disabled={lockedLanguage || (enterpriseLangs.includes(lang) && !$enterpriseLicense)} @@ -585,40 +598,6 @@ > {/each} -
diff --git a/frontend/src/lib/components/TimeAgo.svelte b/frontend/src/lib/components/TimeAgo.svelte index 657261068c..e4dfdc5c83 100644 --- a/frontend/src/lib/components/TimeAgo.svelte +++ b/frontend/src/lib/components/TimeAgo.svelte @@ -69,7 +69,7 @@ minute: '2-digit' })}` } else { - return !withDate ? displayDate(dateString) : '' + return !withDate ? displayDate(dateString, false, withDate) : '' } } } diff --git a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte index ef0adcc48e..017821d590 100644 --- a/frontend/src/lib/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte +++ b/frontend/src/lib/components/apps/editor/inlineScriptsPanel/EmptyInlineScript.svelte @@ -8,7 +8,7 @@ import { inferArgs } from '$lib/infer' import { initialCode } from '$lib/script_helpers' import { emptySchema } from '$lib/utils' - import { getScriptByPath } from '$lib/scripts' + import { defaultScriptLanguages, getScriptByPath } from '$lib/scripts' import { Building, GitFork, Globe2 } from 'lucide-svelte' import { createEventDispatcher, getContext } from 'svelte' @@ -18,6 +18,8 @@ import InlineScriptList from '../settingsPanel/mainInput/InlineScriptList.svelte' import WorkspaceScriptList from '../settingsPanel/mainInput/WorkspaceScriptList.svelte' import RunnableSelector from '../settingsPanel/mainInput/RunnableSelector.svelte' + import { defaultScripts } from '$lib/stores' + import DefaultScripts from '$lib/components/DefaultScripts.svelte' export let name: string export let componentType: string | undefined = undefined @@ -92,21 +94,13 @@ dispatch('new', unusedInlineScript.inlineScript) } - const langs = [ - ['bun', 'TypeScript (Bun)'], - ['python3', 'Python'], - ['deno', 'TypeScript (Deno)'], - ['go', 'Go'], - ['bash', 'Bash'], - ['powershell', 'PowerShell'], - ['nativets', 'REST'], - ['postgresql', 'PostgreSQL'], - ['mysql', 'MySQL'], - ['bigquery', 'BigQuery'], - ['snowflake', 'Snowflake'], - ['mssql', 'MS SQL Server'], - ['graphql', 'GraphQL'] - ] as [Script.language, string][] + $: langs = ($defaultScripts?.order ?? Object.keys(defaultScriptLanguages)) + .map((l) => [defaultScriptLanguages[l], l]) + .filter( + (x) => + x[1] != 'docker' && + ($defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1])) + ) as [string, Preview.language][] @@ -192,10 +186,10 @@
-
Backend
+
Backend
- {#each langs as [lang, label]} + {#each langs as [label, lang] (lang)} [defaultScriptLanguages[l], l]) + .filter( + (x) => $defaultScripts?.hidden == undefined || !$defaultScripts.hidden.includes(x[1]) + ) as [string, SupportedLanguage | 'docker'][] + + function displayLang(lang: SupportedLanguage | 'docker', kind: string) { + if ( + lang == Script.language.BUN || + lang == Script.language.PYTHON3 || + lang == Script.language.DENO + ) { + return true + } + if (lang == Script.language.GO) { + return kind == 'script' || kind == 'trigger' || failureModule + } + + if (lang == Script.language.BASH || lang == Script.language.NATIVETS) { + return kind == 'script' + } + return kind == 'script' && !failureModule + }
@@ -136,21 +164,24 @@ > {/if} {/if} -

- Inline new {kind == 'script' ? 'action' : kind} script - - Embed {kind == 'script' ? 'action' : kind} script directly inside a flow instead - of saving the script into your workspace for reuse. You can always save an inline script to your - workspace later. - +

+
+ Inline new {kind == 'script' ? 'action' : kind} script + + Embed {kind == 'script' ? 'action' : kind} script directly inside a flow instead + of saving the script into your workspace for reuse. You can always save an inline script to + your workspace later. + +
+

{#if noEditor}
- { - dispatch('new', { - language: RawScript.language.BUN, - kind, - subkind: 'flow', - summary - }) - }} - /> - - { - dispatch('new', { - language: RawScript.language.PYTHON3, - kind, - subkind: 'flow', - summary - }) - }} - /> - - { - dispatch('new', { - language: RawScript.language.DENO, - kind, - subkind: 'flow', - summary - }) - }} - /> - - {#if kind != 'approval'} - { - dispatch('new', { - language: RawScript.language.GO, - kind, - subkind: 'flow', - summary - }) - }} - /> - {/if} - - {#if kind == 'script'} - { - dispatch('new', { - language: RawScript.language.BASH, - kind, - subkind: 'flow', - summary - }) - }} - /> - - { - dispatch('new', { - language: RawScript.language.NATIVETS, - kind, - subkind: 'flow', - summary - }) - }} - /> - - {#if !failureModule} + {#each langs as [label, lang] (lang)} + {#if displayLang(lang, kind)} { - dispatch('new', { - language: RawScript.language.POSTGRESQL, - kind, - subkind: 'flow', - summary - }) - }} - /> - { - dispatch('new', { - language: RawScript.language.MYSQL, - kind, - subkind: 'flow', - summary - }) - }} - /> - { - dispatch('new', { - language: RawScript.language.BIGQUERY, - kind, - subkind: 'flow', - summary - }) - }} - /> - { - dispatch('new', { - language: RawScript.language.SNOWFLAKE, - kind, - subkind: 'flow', - summary - }) - }} - /> - - { - dispatch('new', { - language: RawScript.language.MSSQL, - kind, - subkind: 'flow', - summary - }) - }} - /> - - { - dispatch('new', { - language: RawScript.language.GRAPHQL, - kind, - subkind: 'flow', - summary - }) - }} - /> - - { - if (isCloudHosted()) { - sendUserToast( - 'You cannot use Docker scripts on the multi-tenant platform. Use a dedicated instance or self-host windmill instead.', - true, - [ - { - label: 'Learn more', - callback: () => { - window.open('https://www.windmill.dev/docs/advanced/docker', '_blank') + if (lang == 'docker') { + if (isCloudHosted()) { + sendUserToast( + 'You cannot use Docker scripts on the multi-tenant platform. Use a dedicated instance or self-host windmill instead.', + true, + [ + { + label: 'Learn more', + callback: () => { + window.open('https://www.windmill.dev/docs/advanced/docker', '_blank') + } } - } - ] - ) - return + ] + ) + return + } } + console.log(lang, kind) dispatch('new', { - language: RawScript.language.BASH, + language: lang == 'docker' ? Script.language.BASH : lang, kind, - subkind: 'docker', + subkind: lang == 'docker' ? 'docker' : 'flow', summary }) }} /> - - { - dispatch('new', { - language: RawScript.language.POWERSHELL, - kind, - subkind: 'flow', - summary - }) - }} - /> - - {/if} - {/if} + {/each}
diff --git a/frontend/src/lib/components/flows/pickers/FlowScriptPicker.svelte b/frontend/src/lib/components/flows/pickers/FlowScriptPicker.svelte index f5de2d67fd..78ccb80e83 100644 --- a/frontend/src/lib/components/flows/pickers/FlowScriptPicker.svelte +++ b/frontend/src/lib/components/flows/pickers/FlowScriptPicker.svelte @@ -7,15 +7,7 @@ export let disabled: boolean = false export let label: string - export let lang: - | SupportedLanguage - | 'pgsql' - | 'mysql' - | 'javascript' - | 'fetch' - | 'docker' - | 'powershell' - | undefined = undefined + export let lang: SupportedLanguage | 'docker' | 'javascript' | undefined = undefined export let id: string | undefined = undefined diff --git a/frontend/src/lib/components/runs/RunRow.svelte b/frontend/src/lib/components/runs/RunRow.svelte index 89f454d553..2d2f43ea40 100644 --- a/frontend/src/lib/components/runs/RunRow.svelte +++ b/frontend/src/lib/components/runs/RunRow.svelte @@ -30,16 +30,6 @@ export let containerWidth: number = 0 let scheduleEditor: ScheduleEditor - - function endedDate(started_at: string, duration_ms: number): string { - const started = new Date(started_at) - started.setMilliseconds(started.getMilliseconds() + duration_ms) - return `${started.toLocaleTimeString([], { - hour: '2-digit', - minute: '2-digit', - second: '2-digit' - })}` - } @@ -93,16 +83,11 @@
{#if job} {#if 'started_at' in job && job.started_at} - {#if job?.['duration_ms']} - Ended {endedDate(job.started_at, job?.['duration_ms'])} - {#if job && 'duration_ms' in job && job.duration_ms != undefined} - (Ran in {msToSec(job.duration_ms)}s) - {/if} - {:else} -
- Started - -
+ Started + {#if job && 'duration_ms' in job && job.duration_ms != undefined} + (Ran in {msToSec( + job.duration_ms + )}s{#if job.job_kind == 'flow' || job.job_kind == 'flowpreview'} total{/if}) {/if} {:else if `scheduled_for` in job && job.scheduled_for && forLater(job.scheduled_for)} Scheduled for {displayDate(job.scheduled_for)} diff --git a/frontend/src/lib/components/runs/RunsTable.svelte b/frontend/src/lib/components/runs/RunsTable.svelte index d9ad1c1ff1..168003e886 100644 --- a/frontend/src/lib/components/runs/RunsTable.svelte +++ b/frontend/src/lib/components/runs/RunsTable.svelte @@ -23,7 +23,7 @@ const field: string | undefined = getTime(job) if (field) { const date = new Date(field) - date.setMilliseconds(date.getMilliseconds() + (job['duration_ms'] ?? 0)) + date.setMilliseconds(date.getMilliseconds()) const day = date.toLocaleDateString('en-US', { year: 'numeric', diff --git a/frontend/src/lib/consts.ts b/frontend/src/lib/consts.ts index 586ab2b48b..c45e8f9a7a 100644 --- a/frontend/src/lib/consts.ts +++ b/frontend/src/lib/consts.ts @@ -11,10 +11,6 @@ export const HOME_SEARCH_PLACEHOLDER = 'Search Scripts, Flows & Apps' export const SIDEBAR_SHOW_SCHEDULES = true -export const SCRIPT_SHOW_PSQL = true -export const SCRIPT_SHOW_GO = true -export const SCRIPT_SHOW_BASH = true - export const WORKSPACE_SHOW_SLACK_CMD = true export const WORKSPACE_SHOW_WEBHOOK_CLI_SYNC = true diff --git a/frontend/src/lib/script_helpers.ts b/frontend/src/lib/script_helpers.ts index 7da38b83d3..b3dc19bdd4 100644 --- a/frontend/src/lib/script_helpers.ts +++ b/frontend/src/lib/script_helpers.ts @@ -340,6 +340,7 @@ export function initialCode( kind: Script.kind | undefined, subkind: 'pgsql' | 'mysql' | 'flow' | 'script' | 'fetch' | 'docker' | 'powershell' | undefined ): string { + console.log(language, kind, subkind) if (!kind) { kind = Script.kind.SCRIPT } diff --git a/frontend/src/lib/scripts.ts b/frontend/src/lib/scripts.ts index 64f8be7f4f..89639ca60c 100644 --- a/frontend/src/lib/scripts.ts +++ b/frontend/src/lib/scripts.ts @@ -87,6 +87,23 @@ export function scriptPathToHref(path: string): string { } } +export const defaultScriptLanguages = Object.fromEntries([ + [Script.language.BUN, 'TypeScript (Bun)'], + [Script.language.PYTHON3, 'Python'], + [Script.language.DENO, 'TypeScript (Deno)'], + [Script.language.BASH, 'Bash'], + [Script.language.GO, 'Go'], + [Script.language.NATIVETS, 'REST'], + [Script.language.POSTGRESQL, 'PostgreSQL'], + [Script.language.MYSQL, 'MySQL'], + [Script.language.BIGQUERY, 'BigQuery'], + [Script.language.SNOWFLAKE, 'Snowflake'], + [Script.language.MSSQL, 'MS SQL Server'], + [Script.language.GRAPHQL, 'GraphQL'], + [Script.language.POWERSHELL, 'PowerShell'], + ['docker', 'Docker'] +]) + export async function getScriptByPath(path: string): Promise<{ content: string language: SupportedLanguage diff --git a/frontend/src/lib/stores.ts b/frontend/src/lib/stores.ts index c9a6b5cb59..aae4e4a519 100644 --- a/frontend/src/lib/stores.ts +++ b/frontend/src/lib/stores.ts @@ -1,7 +1,7 @@ import { BROWSER } from 'esm-env' import { derived, type Readable, writable } from 'svelte/store' import type { UserWorkspaceList } from '$lib/gen/models/UserWorkspaceList.js' -import type { TokenResponse } from './gen' +import { type WorkspaceDefaultScripts, type TokenResponse } from './gen' import type { IntrospectionQuery } from 'graphql' export interface UserExt { @@ -39,6 +39,7 @@ export const userStore = writable(undefined) export const workspaceStore = writable( persistedWorkspace ? String(persistedWorkspace) : undefined ) +export const defaultScripts = writable(undefined) export const dbClockDrift = writable(undefined) export const isPremiumStore = writable(false) export const starStore = writable(1) diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 314ad94256..c12772cc29 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -36,7 +36,11 @@ export function parseQueryParams(url: string | undefined) { return params } -export function displayDate(dateString: string | Date | undefined, displaySecond = false): string { +export function displayDate( + dateString: string | Date | undefined, + displaySecond = false, + displayDate = true +): string { const date = new Date(dateString ?? '') if (date.toString() === 'Invalid Date') { return '' @@ -45,7 +49,7 @@ export function displayDate(dateString: string | Date | undefined, displaySecond hour: '2-digit', minute: '2-digit', second: displaySecond ? '2-digit' : undefined - })} ${date.getDate()}/${date.getMonth() + 1}` + })}${displayDate ? ` ${date.getDate()}/${date.getMonth() + 1}` : ''}` } } diff --git a/frontend/src/routes/(root)/(logged)/+layout.svelte b/frontend/src/routes/(root)/(logged)/+layout.svelte index 132c9d250c..b895ee72d4 100644 --- a/frontend/src/routes/(root)/(logged)/+layout.svelte +++ b/frontend/src/routes/(root)/(logged)/+layout.svelte @@ -21,7 +21,8 @@ usageStore, userStore, workspaceStore, - type UserExt + type UserExt, + defaultScripts } from '$lib/stores' import CenteredModal from '$lib/components/CenteredModal.svelte' import { afterNavigate, beforeNavigate, goto } from '$app/navigation' @@ -186,22 +187,32 @@ let devOnly = $page.url.pathname.startsWith('/scripts/dev') - workspaceStore.subscribe(async (value) => { - if (value) { - workspacedOpenai.init(value) - try { - copilotInfo.set(await WorkspaceService.getCopilotInfo({ workspace: value })) - } catch (err) { - copilotInfo.set({ - exists_openai_resource_path: false, - code_completion_enabled: false - }) - console.error('Could not get copilot info') - } + async function loadCopilot(workspace: string) { + workspacedOpenai.init(workspace) + try { + copilotInfo.set(await WorkspaceService.getCopilotInfo({ workspace })) + } catch (err) { + copilotInfo.set({ + exists_openai_resource_path: false, + code_completion_enabled: false + }) + console.error('Could not get copilot info') + } + } + + workspaceStore.subscribe(async (workspace) => { + if (workspace) { + loadCopilot(workspace) } }) - $: onUserStore($userStore) + $: onUserStore($userStore) + $: $workspaceStore && $userStore && loadDefaultScripts($workspaceStore, $userStore) + async function loadDefaultScripts(workspace: string, user: UserExt | undefined) { + if (!user?.operator) { + $defaultScripts = await WorkspaceService.getDefaultScripts({ workspace }) + } + } let timeout: NodeJS.Timeout | undefined async function onUserStore(u: UserExt | undefined) { if (u && timeout) {