mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-04 16:03:06 +00:00
9c28bbfd69
* stash
* ui nits
* Fix contenteditable feedback look (duplicate typing)
* fix right icon wrong position with placeholder
* user editor in Path editor takes correct width
* nits
* nit
* chore: remove assets-operator changes (moved to separate PR)
These files were mistakenly included in this PR and belong in a dedicated PR
("Allow assets page to operators").
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: remove sidebar assets-operator change (moved to separate PR)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix disabled
* border nit
* Fix disabled styling
* Apply suggestion from @cubic-dev-ai[bot]
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* nit
* Update frontend/src/lib/components/text_input/TextInput.svelte
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
* Fix disabled tabindex and aria-disabled on contenteditable Select
The useContentEditable branch had an unconditional tabindex="0", keeping
a disabled Select in the tab order, and was missing aria-disabled.
Mirror the TextInput div branch.
Co-authored-by: Diego Imbert <diegoimbert@users.noreply.github.com>
* fix: drop obsolete hideFullPath prop from EditorHeader Path usage
* invalidate autocomplete paths on deploy
* nit pixel
* use Badge in auto complete
* nit prevent default
* fix(autocomplete): don't let stale fetch clobber forced refresh
A non-forced fetchWorkspacePaths() that started before invalidateWorkspacePaths()
could still resolve afterward, overwrite the cache, and clear forceNextFetch —
making the post-deploy refresh a no-op. Only write back from the promise that
is still the current pending one, and only clear the force flag when the
completing fetch was itself forced.
* refactor(path): drop unreachable 'group' branch in owner-kind setter
The Select only offers user/folder, so the 'group' branch was dead. Leave a
short note pointing at validateName which still accepts 'group' for
forward-compat.
* fix(path): respect disableEditing on owner-kind selector
Other path-editor controls disable on (disabled || disableEditing); the
owner-kind Select only checked `disabled`, so read-only users (trigger
editors with !can_write) could still toggle User/Folder and mutate the
bound path. Reuse the existing nameDisabled flag.
* Revert "fix(autocomplete): don't let stale fetch clobber forced refresh"
This reverts commit 6649975714.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Diego Imbert <diegoimbert@users.noreply.github.com>
99 lines
3.1 KiB
Rust
99 lines
3.1 KiB
Rust
/*
|
|
* Author: Ruben Fiszel
|
|
* Copyright: Windmill Labs, Inc 2026
|
|
* This file and its contents are licensed under the AGPLv3 License.
|
|
* Please see the included NOTICE for copyright information and
|
|
* LICENSE-AGPL for a copy of the license.
|
|
*/
|
|
|
|
use std::{
|
|
sync::{Arc, LazyLock},
|
|
time::{Duration, Instant},
|
|
};
|
|
|
|
use axum::{
|
|
extract::{Extension, Path, Query},
|
|
routing::get,
|
|
Json, Router,
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
use windmill_common::error::JsonResult;
|
|
|
|
use crate::db::{ApiAuthed, DB};
|
|
|
|
// Per-table row cap is inlined into the SQL as `LIMIT 5000`.
|
|
// With 6 tables, the absolute ceiling is ~30k paths pre-dedup.
|
|
/// Final cap applied after dedup/sort.
|
|
const MAX_PATHS: usize = 20_000;
|
|
/// TTL for the per-workspace path list cache.
|
|
const CACHE_TTL: Duration = Duration::from_secs(60);
|
|
|
|
/// Workspace-wide path list cache keyed by workspace_id only.
|
|
/// One entry per workspace shared across all users — autocomplete is a
|
|
/// navigation hint, not an access gate. Saves memory and warms faster.
|
|
static PATHS_CACHE: LazyLock<quick_cache::sync::Cache<String, (Arc<Vec<String>>, Instant)>> =
|
|
LazyLock::new(|| quick_cache::sync::Cache::new(500));
|
|
|
|
pub fn workspaced_service() -> Router {
|
|
Router::new().route("/list_paths", get(list_paths))
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
struct ListPathsResponse {
|
|
paths: Arc<Vec<String>>,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct ListPathsQuery {
|
|
/// When true, bypass the cached entry and re-query the DB, refreshing the
|
|
/// cache. Used by clients that just mutated the workspace (e.g. a deploy)
|
|
/// and need the new path reflected immediately.
|
|
#[serde(default)]
|
|
force: bool,
|
|
}
|
|
|
|
async fn list_paths(
|
|
_authed: ApiAuthed,
|
|
Extension(db): Extension<DB>,
|
|
Path(w_id): Path<String>,
|
|
Query(ListPathsQuery { force }): Query<ListPathsQuery>,
|
|
) -> JsonResult<ListPathsResponse> {
|
|
if !force {
|
|
if let Some((cached, cached_at)) = PATHS_CACHE.get(&w_id) {
|
|
if cached_at.elapsed() < CACHE_TTL {
|
|
return Ok(Json(ListPathsResponse { paths: cached }));
|
|
}
|
|
PATHS_CACHE.remove(&w_id);
|
|
}
|
|
}
|
|
|
|
let mut paths: Vec<String> = sqlx::query_scalar!(
|
|
r#"
|
|
SELECT path AS "path!" FROM (
|
|
(SELECT DISTINCT path FROM script WHERE workspace_id = $1 AND archived = false AND deleted = false AND draft_only IS NOT true LIMIT 5000)
|
|
UNION
|
|
(SELECT path FROM flow WHERE workspace_id = $1 AND archived = false AND draft_only IS NOT true LIMIT 5000)
|
|
UNION
|
|
(SELECT path FROM app WHERE workspace_id = $1 LIMIT 5000)
|
|
UNION
|
|
(SELECT path FROM raw_app WHERE workspace_id = $1 LIMIT 5000)
|
|
UNION
|
|
(SELECT path FROM variable WHERE workspace_id = $1 LIMIT 5000)
|
|
UNION
|
|
(SELECT path FROM resource WHERE workspace_id = $1 LIMIT 5000)
|
|
) t
|
|
"#,
|
|
&w_id,
|
|
)
|
|
.fetch_all(&db)
|
|
.await?;
|
|
|
|
paths.sort_unstable();
|
|
paths.truncate(MAX_PATHS);
|
|
let paths = Arc::new(paths);
|
|
|
|
PATHS_CACHE.insert(w_id, (paths.clone(), Instant::now()));
|
|
|
|
Ok(Json(ListPathsResponse { paths }))
|
|
}
|