mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-13 00:03:00 +00:00
feat: private hub user accessible url setting (#4617)
* feat: private hub user accessible url setting * improve UI
This commit is contained in:
@@ -31,7 +31,7 @@ use windmill_common::{
|
||||
error::{self, JsonResult, Result},
|
||||
global_settings::{
|
||||
AUTOMATE_USERNAME_CREATION_SETTING, EMAIL_DOMAIN_SETTING, ENV_SETTINGS,
|
||||
HUB_BASE_URL_SETTING,
|
||||
HUB_ACCESSIBLE_URL_SETTING, HUB_BASE_URL_SETTING,
|
||||
},
|
||||
server::Smtp,
|
||||
utils::send_email,
|
||||
@@ -262,6 +262,7 @@ pub async fn get_global_setting(
|
||||
&& !key.starts_with("default_success_handler_")
|
||||
&& key != AUTOMATE_USERNAME_CREATION_SETTING
|
||||
&& key != HUB_BASE_URL_SETTING
|
||||
&& key != HUB_ACCESSIBLE_URL_SETTING
|
||||
&& key != EMAIL_DOMAIN_SETTING
|
||||
{
|
||||
require_super_admin(&db, &authed.email).await?;
|
||||
|
||||
@@ -27,6 +27,7 @@ pub const OBJECT_STORE_CACHE_CONFIG_SETTING: &str = "object_store_cache_config";
|
||||
|
||||
pub const AUTOMATE_USERNAME_CREATION_SETTING: &str = "automate_username_creation";
|
||||
pub const HUB_BASE_URL_SETTING: &str = "hub_base_url";
|
||||
pub const HUB_ACCESSIBLE_URL_SETTING: &str = "hub_accessible_url";
|
||||
pub const CRITICAL_ERROR_CHANNELS_SETTING: &str = "critical_error_channels";
|
||||
pub const DEV_INSTANCE_SETTING: &str = "dev_instance";
|
||||
pub const JWT_SECRET_SETTING: &str = "jwt_secret";
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
import KeycloakSetting from './KeycloakSetting.svelte'
|
||||
import Alert from './common/alert/Alert.svelte'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import { capitalize, classNames } from '$lib/utils'
|
||||
import { capitalize, classNames, sleep } from '$lib/utils'
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import CustomOauth from './CustomOauth.svelte'
|
||||
import {
|
||||
@@ -111,6 +111,7 @@
|
||||
}
|
||||
|
||||
export async function saveSettings() {
|
||||
let shouldReloadPage = false
|
||||
if (values) {
|
||||
const allSettings = Object.values(settings).flatMap((x) => Object.entries(x))
|
||||
let licenseKeySet = false
|
||||
@@ -129,6 +130,9 @@
|
||||
if (x.key == 'license_key') {
|
||||
licenseKeySet = true
|
||||
}
|
||||
if (x.requiresReloadOnChange) {
|
||||
shouldReloadPage = true
|
||||
}
|
||||
return await SettingService.setGlobal({
|
||||
key: x.key,
|
||||
requestBody: { value: values?.[x.key] }
|
||||
@@ -158,8 +162,14 @@
|
||||
} else {
|
||||
console.error('Values not loaded')
|
||||
}
|
||||
sendUserToast('Settings updated')
|
||||
dispatch('saved')
|
||||
if (shouldReloadPage) {
|
||||
sendUserToast('Settings updated, reloading page...')
|
||||
await sleep(1000)
|
||||
window.location.reload()
|
||||
} else {
|
||||
sendUserToast('Settings updated')
|
||||
dispatch('saved')
|
||||
}
|
||||
}
|
||||
|
||||
let oauths: Record<string, any> = {}
|
||||
@@ -548,7 +558,7 @@
|
||||
<div>
|
||||
<div class="flex-col flex gap-2 pb-4">
|
||||
{#each settings[category] as setting}
|
||||
{#if (!setting.cloudonly || isCloudHosted()) && showSetting(setting.key, values)}
|
||||
{#if (!setting.cloudonly || isCloudHosted()) && showSetting(setting.key, values) && !(setting.hiddenIfNull && values[setting.key] == null)}
|
||||
{#if setting.ee_only != undefined && !$enterpriseLicense}
|
||||
<div class="flex text-xs items-center gap-1 text-yellow-500 whitespace-nowrap">
|
||||
<AlertTriangle size={16} />
|
||||
@@ -579,6 +589,20 @@
|
||||
: ''}
|
||||
bind:value={values[setting.key]}
|
||||
/>
|
||||
{#if setting.advancedToggle}
|
||||
<div class="mt-1">
|
||||
<Toggle
|
||||
size="xs"
|
||||
options={{ right: setting.advancedToggle.label }}
|
||||
checked={setting.advancedToggle.checked(values)}
|
||||
on:change={() => {
|
||||
if (setting.advancedToggle) {
|
||||
values = setting.advancedToggle.onChange(values)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{:else if setting.fieldType == 'textarea'}
|
||||
<textarea
|
||||
rows="2"
|
||||
|
||||
@@ -21,18 +21,26 @@ export interface Setting {
|
||||
| 'slack_connect'
|
||||
| 'smtp_connect'
|
||||
storage: SettingStorage
|
||||
advancedToggle?: {
|
||||
label: string
|
||||
onChange: (values: Record<string, any>) => Record<string, any>
|
||||
checked: (values: Record<string, any>) => boolean
|
||||
}
|
||||
hiddenIfNull?: boolean
|
||||
requiresReloadOnChange?: boolean
|
||||
isValid?: (value: any) => boolean
|
||||
error?: string
|
||||
defaultValue?: () => any
|
||||
}
|
||||
|
||||
export type SettingStorage = 'setting'
|
||||
export type SettingStorage = 'setting'
|
||||
|
||||
export const settings: Record<string, Setting[]> = {
|
||||
Core: [
|
||||
{
|
||||
label: 'Base url',
|
||||
description: 'Public base url of the instance. <a href="https://www.windmill.dev/docs/advanced/instance_settings#global-users">Learn more</a>',
|
||||
description:
|
||||
'Public base url of the instance. <a href="https://www.windmill.dev/docs/advanced/instance_settings#global-users">Learn more</a>',
|
||||
key: 'base_url',
|
||||
fieldType: 'text',
|
||||
placeholder: 'https://windmill.com',
|
||||
@@ -67,14 +75,16 @@ export const settings: Record<string, Setting[]> = {
|
||||
{
|
||||
label: 'Default timeout',
|
||||
key: 'job_default_timeout',
|
||||
description: 'Default timeout for individual jobs. <a href="https://www.windmill.dev/docs/core_concepts/jobs#retention-policy">Learn more</a>',
|
||||
description:
|
||||
'Default timeout for individual jobs. <a href="https://www.windmill.dev/docs/core_concepts/jobs#retention-policy">Learn more</a>',
|
||||
fieldType: 'seconds',
|
||||
storage: 'setting',
|
||||
cloudonly: false
|
||||
},
|
||||
{
|
||||
label: 'Max timeout for sync endpoints',
|
||||
description: 'Maximum amount of time (measured in seconds) that a <a href="https://www.windmill.dev/docs/core_concepts/webhooks">sync endpoint</a> is allowed to run before it is forcibly stopped or timed out.',
|
||||
description:
|
||||
'Maximum amount of time (measured in seconds) that a <a href="https://www.windmill.dev/docs/core_concepts/webhooks">sync endpoint</a> is allowed to run before it is forcibly stopped or timed out.',
|
||||
key: 'timeout_wait_result',
|
||||
cloudonly: true,
|
||||
fieldType: 'seconds',
|
||||
@@ -83,7 +93,8 @@ export const settings: Record<string, Setting[]> = {
|
||||
},
|
||||
{
|
||||
label: 'License key',
|
||||
description: 'License key required to use the EE (switch image for windmill-ee). <a href="https://www.windmill.dev/docs/advanced/instance_settings#license-key">Learn more</a>',
|
||||
description:
|
||||
'License key required to use the EE (switch image for windmill-ee). <a href="https://www.windmill.dev/docs/advanced/instance_settings#license-key">Learn more</a>',
|
||||
key: 'license_key',
|
||||
fieldType: 'license_key',
|
||||
placeholder: 'only needed to prepare upgrade to EE',
|
||||
@@ -91,7 +102,8 @@ export const settings: Record<string, Setting[]> = {
|
||||
},
|
||||
{
|
||||
label: 'Non-prod instance',
|
||||
description: 'Whether we should consider the reported usage of this instance as non-prod. <a href="https://www.windmill.dev/docs/advanced/instance_settings#non-prod-instance">Learn more</a>',
|
||||
description:
|
||||
'Whether we should consider the reported usage of this instance as non-prod. <a href="https://www.windmill.dev/docs/advanced/instance_settings#non-prod-instance">Learn more</a>',
|
||||
key: 'dev_instance',
|
||||
fieldType: 'boolean',
|
||||
storage: 'setting'
|
||||
@@ -99,7 +111,8 @@ export const settings: Record<string, Setting[]> = {
|
||||
{
|
||||
label: 'Retention period in secs',
|
||||
key: 'retention_period_secs',
|
||||
description: 'How long to keep the jobs data in the database (max 30 days on CE). <a href="https://www.windmill.dev/docs/advanced/instance_settings#retention-period-in-secs">Learn more</a>',
|
||||
description:
|
||||
'How long to keep the jobs data in the database (max 30 days on CE). <a href="https://www.windmill.dev/docs/advanced/instance_settings#retention-period-in-secs">Learn more</a>',
|
||||
fieldType: 'seconds',
|
||||
placeholder: '30',
|
||||
storage: 'setting',
|
||||
@@ -108,7 +121,8 @@ export const settings: Record<string, Setting[]> = {
|
||||
},
|
||||
{
|
||||
label: 'Expose metrics',
|
||||
description: 'Expose Prometheus metrics for workers and servers on port 8001 at /metrics. <a href="https://www.windmill.dev/docs/advanced/instance_settings#expose-metrics">Learn more</a>',
|
||||
description:
|
||||
'Expose Prometheus metrics for workers and servers on port 8001 at /metrics. <a href="https://www.windmill.dev/docs/advanced/instance_settings#expose-metrics">Learn more</a>',
|
||||
key: 'expose_metrics',
|
||||
fieldType: 'boolean',
|
||||
storage: 'setting',
|
||||
@@ -116,7 +130,8 @@ export const settings: Record<string, Setting[]> = {
|
||||
},
|
||||
{
|
||||
label: 'Instance object storage',
|
||||
description: ' S3/Azure bucket to store large logs and global cache for Python and Go. <a href="https://www.windmill.dev/docs/core_concepts/object_storage_in_windmill#instance-object-storage">Learn more</a>',
|
||||
description:
|
||||
' S3/Azure bucket to store large logs and global cache for Python and Go. <a href="https://www.windmill.dev/docs/core_concepts/object_storage_in_windmill#instance-object-storage">Learn more</a>',
|
||||
key: 'object_store_cache_config',
|
||||
fieldType: 'object_store_config',
|
||||
storage: 'setting',
|
||||
@@ -124,7 +139,8 @@ export const settings: Record<string, Setting[]> = {
|
||||
},
|
||||
{
|
||||
label: 'Critical alert channels',
|
||||
description: 'Channels to send critical alerts to. SMTP must be configured for the email channel. A Slack workspace must be connected to the instance for the Slack channel. <a href="https://www.windmill.dev/docs/core_concepts/critical_alert_channels">Learn more</a>',
|
||||
description:
|
||||
'Channels to send critical alerts to. SMTP must be configured for the email channel. A Slack workspace must be connected to the instance for the Slack channel. <a href="https://www.windmill.dev/docs/core_concepts/critical_alert_channels">Learn more</a>',
|
||||
key: 'critical_error_channels',
|
||||
fieldType: 'critical_error_channels',
|
||||
storage: 'setting',
|
||||
@@ -132,7 +148,8 @@ export const settings: Record<string, Setting[]> = {
|
||||
},
|
||||
{
|
||||
label: 'Azure OpenAI base path',
|
||||
description: 'All Windmill AI features will run on the specified deployed model. Format: https://{your-resource-name}.openai.azure.com/openai/deployments/{deployment-id}. <a href="https://www.windmill.dev/docs/core_concepts/ai_generation#azure-openai-advanced-models">Learn more</a>',
|
||||
description:
|
||||
'All Windmill AI features will run on the specified deployed model. Format: https://{your-resource-name}.openai.azure.com/openai/deployments/{deployment-id}. <a href="https://www.windmill.dev/docs/core_concepts/ai_generation#azure-openai-advanced-models">Learn more</a>',
|
||||
key: 'openai_azure_base_path',
|
||||
fieldType: 'text',
|
||||
storage: 'setting',
|
||||
@@ -140,12 +157,38 @@ export const settings: Record<string, Setting[]> = {
|
||||
},
|
||||
{
|
||||
label: 'Private Hub base url',
|
||||
description: 'Base url of your private Hub instance, without trailing slash. <a href="https://www.windmill.dev/docs/core_concepts/private_hub">Learn more</a>',
|
||||
description:
|
||||
'Base URL of your private Hub instance, without trailing slash. <a href="https://www.windmill.dev/docs/core_concepts/private_hub">Learn more</a>',
|
||||
placeholder: 'https://hub.company.com',
|
||||
key: 'hub_base_url',
|
||||
fieldType: 'text',
|
||||
storage: 'setting',
|
||||
ee_only: ''
|
||||
ee_only: '',
|
||||
advancedToggle: {
|
||||
label: 'I have a different URL for Hub access from end-user browsers',
|
||||
onChange(values) {
|
||||
if (values['hub_accessible_url']) {
|
||||
values['hub_accessible_url'] = null
|
||||
} else {
|
||||
values['hub_accessible_url'] = values['hub_base_url'] || 'https://hub.company.com'
|
||||
}
|
||||
return values
|
||||
},
|
||||
checked: (values) => values['hub_accessible_url'] != null
|
||||
},
|
||||
requiresReloadOnChange: true
|
||||
},
|
||||
{
|
||||
label: 'Private Hub accessible url',
|
||||
description:
|
||||
'Base URL accessible from end-user browsers, without trailing slash. <a href="https://www.windmill.dev/docs/core_concepts/private_hub">Learn more</a>',
|
||||
key: 'hub_accessible_url',
|
||||
fieldType: 'text',
|
||||
hiddenIfNull: true,
|
||||
|
||||
storage: 'setting',
|
||||
ee_only: '',
|
||||
requiresReloadOnChange: true
|
||||
}
|
||||
],
|
||||
'SSO/OAuth': [],
|
||||
@@ -189,12 +232,12 @@ export const settings: Record<string, Setting[]> = {
|
||||
}
|
||||
],
|
||||
SMTP: [
|
||||
{
|
||||
label: 'SMTP',
|
||||
key: 'smtp_settings',
|
||||
fieldType: 'smtp_connect',
|
||||
storage: 'setting',
|
||||
ee_only: '',
|
||||
{
|
||||
label: 'SMTP',
|
||||
key: 'smtp_settings',
|
||||
fieldType: 'smtp_connect',
|
||||
storage: 'setting',
|
||||
ee_only: ''
|
||||
}
|
||||
],
|
||||
Slack: [
|
||||
|
||||
@@ -139,7 +139,8 @@
|
||||
|
||||
async function loadHubBaseUrl() {
|
||||
$hubBaseUrlStore =
|
||||
((await SettingService.getGlobal({ key: 'hub_base_url' })) as string) ??
|
||||
((await SettingService.getGlobal({ key: 'hub_accessible_url' })) as string) ||
|
||||
((await SettingService.getGlobal({ key: 'hub_base_url' })) as string) ||
|
||||
'https://hub.windmill.dev'
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user