mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-21 00:02:30 +00:00
fix: share the hub integration list cache, backfill admins only
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
414e8bfd54
commit
a4c5de5a2b
@@ -2,8 +2,8 @@
|
||||
-- "Google Sheets". Null where nobody named the type; readers derive a label from the name.
|
||||
ALTER TABLE resource_type ADD COLUMN display_name VARCHAR(100);
|
||||
|
||||
-- The names the hub carries today, so existing instances show them before any sync. Not
|
||||
-- limited to admins: a workspace that copied a hub type keeps the type's name.
|
||||
-- The names the hub carries today, so existing instances show them before any sync. Only in
|
||||
-- admins, where hub resource types live and every workspace reads them from.
|
||||
UPDATE resource_type SET display_name = v.display_name
|
||||
FROM (VALUES
|
||||
('bamboo_hr', 'BambooHR'),
|
||||
@@ -19,4 +19,6 @@ FROM (VALUES
|
||||
('snowflake_oauth', 'Snowflake (OAuth)'),
|
||||
('their_stack', 'TheirStack')
|
||||
) AS v(name, display_name)
|
||||
WHERE resource_type.name = v.name AND resource_type.display_name IS NULL;
|
||||
WHERE resource_type.workspace_id = 'admins'
|
||||
AND resource_type.name = v.name
|
||||
AND resource_type.display_name IS NULL;
|
||||
|
||||
@@ -5,10 +5,10 @@ import { createCache } from '$lib/utils'
|
||||
import { setHubIntegrationDisplayNames, setResourceTypeDisplayNames } from './resourceTypeDisplay'
|
||||
|
||||
/**
|
||||
* Loads the names `resourceTypeDisplayName` and `integrationDisplayName` read, for a surface that
|
||||
* shows a label without already fetching the rows it comes from. Apart from `resourceTypeDisplay`,
|
||||
* which makes no API calls so it can be unit-tested alone. Cached briefly: drawers and pickers
|
||||
* reopen often, and a name rarely changes.
|
||||
* Loads what `resourceTypeDisplayName` and `integrationDisplayName` read: a type's stored name for a
|
||||
* surface that holds no row for it, and the hub's integration list, which every picker that needs
|
||||
* it shares. Apart from `resourceTypeDisplay`, which makes no API calls so it can be unit-tested
|
||||
* alone. Cached briefly: drawers and pickers reopen often, and a name rarely changes.
|
||||
*/
|
||||
const CACHE_MS = 60_000
|
||||
|
||||
@@ -29,12 +29,24 @@ export function loadResourceTypeDisplayName(workspace: string, name: string): Pr
|
||||
return resourceTypeRowCached({ workspace, name })
|
||||
}
|
||||
|
||||
const hubIntegrationNamesCached = createCache(
|
||||
(_: Record<string, never>) =>
|
||||
IntegrationService.listHubIntegrations().then(setHubIntegrationDisplayNames, () => {}),
|
||||
const hubIntegrationsCached = createCache(
|
||||
({ kind }: { kind?: string }) =>
|
||||
IntegrationService.listHubIntegrations({ kind }).then((integrations) => {
|
||||
setHubIntegrationDisplayNames(integrations)
|
||||
return integrations
|
||||
}),
|
||||
{ invalidateMs: CACHE_MS }
|
||||
)
|
||||
|
||||
/**
|
||||
* The hub's integration list, read once a minute per `kind` however many pickers ask, recording
|
||||
* each integration's name on the way. A failed read is kept for that minute too, and rejects, so
|
||||
* a picker can say the hub is unavailable.
|
||||
*/
|
||||
export function listHubIntegrationsShared(kind?: string) {
|
||||
return hubIntegrationsCached({ kind })
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill `integrationDisplayName` for a picker whose integrations come from its own items rather
|
||||
* than the hub's integration list, as the hub app and flow pickers do. Unfiltered: `kind`
|
||||
@@ -42,5 +54,8 @@ const hubIntegrationNamesCached = createCache(
|
||||
*/
|
||||
export function loadHubIntegrationDisplayNames(): Promise<void> {
|
||||
if (get(disableHubStore)) return Promise.resolve()
|
||||
return hubIntegrationNamesCached({})
|
||||
return listHubIntegrationsShared().then(
|
||||
() => {},
|
||||
() => {}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
import { capitalize } from '$lib/utils'
|
||||
import NoItemFound from '$lib/components/home/NoItemFound.svelte'
|
||||
import { APP_TO_ICON_COMPONENT } from '$lib/components/icons'
|
||||
import { setHubIntegrationDisplayNames } from '$lib/components/resourceTypeDisplay'
|
||||
import { listHubIntegrationsShared } from '$lib/components/displayNameLoaders'
|
||||
import ListFilters from '$lib/components/home/ListFilters.svelte'
|
||||
import { IntegrationService, ScriptService, type HubScriptKind } from '$lib/gen'
|
||||
import { ScriptService, type HubScriptKind } from '$lib/gen'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import TextInput from '$lib/components/text_input/TextInput.svelte'
|
||||
import { disableHubStore, workspaceStore } from '$lib/stores'
|
||||
@@ -65,10 +65,9 @@
|
||||
hubNotAvailable = false
|
||||
// Independent reads, so they share one round trip before first paint.
|
||||
const [integrations, local] = await Promise.all([
|
||||
IntegrationService.listHubIntegrations({ kind: filterKind }),
|
||||
listHubIntegrationsShared(filterKind),
|
||||
$workspaceStore ? localCountsByIntegration($workspaceStore) : {}
|
||||
])
|
||||
setHubIntegrationDisplayNames(integrations)
|
||||
const hubPicks = Object.fromEntries(integrations.map((x) => [x.name, x.picks ?? 0]))
|
||||
popularity = byPopularity(hubPicks, local)
|
||||
allApps = integrations.map((x) => x.name).sort(popularity)
|
||||
|
||||
@@ -5,12 +5,10 @@
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import MultiSelect from '$lib/components/select/MultiSelect.svelte'
|
||||
import { safeSelectItems } from '$lib/components/select/utils.svelte'
|
||||
import {
|
||||
integrationDisplayName,
|
||||
setHubIntegrationDisplayNames
|
||||
} from '$lib/components/resourceTypeDisplay'
|
||||
import { integrationDisplayName } from '$lib/components/resourceTypeDisplay'
|
||||
import { listHubIntegrationsShared } from '$lib/components/displayNameLoaders'
|
||||
import TextInput from '$lib/components/text_input/TextInput.svelte'
|
||||
import { FlowService, FolderService, IntegrationService, ScriptService } from '$lib/gen'
|
||||
import { FlowService, FolderService, ScriptService } from '$lib/gen'
|
||||
import { mcpEndpointTools } from '$lib/mcpEndpointTools'
|
||||
import {
|
||||
endpointPathPolicy,
|
||||
@@ -272,8 +270,7 @@
|
||||
if (allApps.length > 0) return
|
||||
try {
|
||||
loadingApps = true
|
||||
const integrations = await IntegrationService.listHubIntegrations({ kind: 'script' })
|
||||
setHubIntegrationDisplayNames(integrations)
|
||||
const integrations = await listHubIntegrationsShared('script')
|
||||
allApps = integrations.map((x) => x.name)
|
||||
} catch (err) {
|
||||
console.error('Hub is not available')
|
||||
|
||||
Reference in New Issue
Block a user