feat: add visible to runner only default value (#3472)

This commit is contained in:
HugoCasa
2024-03-26 19:07:21 +01:00
committed by GitHub
parent fbc82b9940
commit 0e0d964fc8
25 changed files with 146 additions and 48 deletions
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27)",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28)",
"describe": {
"columns": [],
"parameters": {
@@ -65,10 +65,11 @@
"Bool",
"Bool",
"Int4",
"Varchar"
"Varchar",
"Bool"
]
},
"nullable": []
},
"hash": "260feb784bb0b223bd9276d6a82bd26be90efb17a4323b9673e93ff88513942a"
"hash": "020d33ed5d47350b456783fd548422ea8dcf2d786d0e9fa849754db82c9fa378"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow (workspace_id, path, summary, description, value, edited_by, edited_at, schema, dependency_job, draft_only, tag, dedicated_worker) VALUES ($1, $2, $3, $4, $5, $6, now(), $7::text::json, NULL, $8, $9, $10)",
"query": "INSERT INTO flow (workspace_id, path, summary, description, value, edited_by, edited_at, schema, dependency_job, draft_only, tag, dedicated_worker, visible_to_runner_only) VALUES ($1, $2, $3, $4, $5, $6, now(), $7::text::json, NULL, $8, $9, $10, $11)",
"describe": {
"columns": [],
"parameters": {
@@ -14,10 +14,11 @@
"Text",
"Bool",
"Varchar",
"Bool",
"Bool"
]
},
"nullable": []
},
"hash": "c3da506f47dfb42434debf6e005319147c7513193e853c38cfb7c071d61a3d2e"
"hash": "35e6af0b203e3e4fac9020b037a3c41af92537c0fd5683227767f6a1bd17339f"
}
@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow SET path = $1, summary = $2, description = $3, value = $4, edited_by = $5, edited_at = now(), schema = $6::text::json, dependency_job = NULL, draft_only = NULL, tag = $9, dedicated_worker = $10\n WHERE path = $7 AND workspace_id = $8",
"query": "UPDATE flow SET path = $1, summary = $2, description = $3, value = $4, edited_by = $5, edited_at = now(), schema = $6::text::json, dependency_job = NULL, draft_only = NULL, tag = $9, dedicated_worker = $10, visible_to_runner_only = $11\n WHERE path = $7 AND workspace_id = $8",
"describe": {
"columns": [],
"parameters": {
@@ -14,10 +14,11 @@
"Text",
"Text",
"Varchar",
"Bool",
"Bool"
]
},
"nullable": []
},
"hash": "de06474de29c6c2cadb99787f5d627678a5285011d7b1a516d4e240a5810ddba"
"hash": "f6fd65fbe36502923ab4ccf1a22f748cb854e23049d0cf73a42229eccc88c4e6"
}
@@ -0,0 +1 @@
-- Add down migration script here
@@ -0,0 +1,3 @@
-- Add up migration script here
ALTER TABLE script ADD COLUMN visible_to_runner_only BOOLEAN;
ALTER TABLE flow ADD COLUMN visible_to_runner_only BOOLEAN;
+2
View File
@@ -2582,6 +2582,7 @@ async fn test_flow_lock_all(db: Pool<Postgres>) {
priority: None,
dedicated_worker: None,
timeout: None,
visible_to_runner_only: None,
},
draft_only: None,
deployment_message: None,
@@ -3153,6 +3154,7 @@ async fn run_deployed_relative_imports(db: &Pool<Postgres>, script_content: Stri
restart_unless_cancelled: None,
deployment_message: None,
concurrency_key: None,
visible_to_runner_only: None,
},
).await.unwrap();
+8 -2
View File
@@ -718,7 +718,6 @@ paths:
schema:
type: string
# pub use_ssl: Option<bool>,
# #[serde(rename = "accountName")]
# pub account_name: String,
@@ -1229,7 +1228,6 @@ paths:
schema:
type: string
/w/{workspace}/workspaces/change_workspace_id:
post:
summary: change workspace id
@@ -8303,6 +8301,8 @@ components:
type: integer
delete_after_use:
type: boolean
visible_to_runner_only:
type: boolean
required:
- hash
- path
@@ -8389,6 +8389,8 @@ components:
type: string
concurrency_key:
type: string
visible_to_runner_only:
type: boolean
required:
- path
- summary
@@ -9717,6 +9719,8 @@ components:
type: boolean
timeout:
type: number
visible_to_runner_only:
type: boolean
required:
- path
- edited_by
@@ -9741,6 +9745,8 @@ components:
type: boolean
timeout:
type: number
visible_to_runner_only:
type: boolean
required:
- path
+9 -5
View File
@@ -319,7 +319,7 @@ async fn create_flow(
sqlx::query!(
"INSERT INTO flow (workspace_id, path, summary, description, value, edited_by, edited_at, \
schema, dependency_job, draft_only, tag, dedicated_worker) VALUES ($1, $2, $3, $4, $5, $6, now(), $7::text::json, NULL, $8, $9, $10)",
schema, dependency_job, draft_only, tag, dedicated_worker, visible_to_runner_only) VALUES ($1, $2, $3, $4, $5, $6, now(), $7::text::json, NULL, $8, $9, $10, $11)",
w_id,
nf.path,
nf.summary,
@@ -329,7 +329,8 @@ async fn create_flow(
nf.schema.and_then(|x| serde_json::to_string(&x.0).ok()),
nf.draft_only,
nf.tag,
nf.dedicated_worker
nf.dedicated_worker,
nf.visible_to_runner_only.unwrap_or(false),
)
.execute(&mut tx)
.await?;
@@ -485,7 +486,7 @@ async fn update_flow(
let old_dep_job = not_found_if_none(old_dep_job, "Flow", flow_path)?;
sqlx::query!(
"UPDATE flow SET path = $1, summary = $2, description = $3, value = $4, edited_by = $5, \
edited_at = now(), schema = $6::text::json, dependency_job = NULL, draft_only = NULL, tag = $9, dedicated_worker = $10
edited_at = now(), schema = $6::text::json, dependency_job = NULL, draft_only = NULL, tag = $9, dedicated_worker = $10, visible_to_runner_only = $11
WHERE path = $7 AND workspace_id = $8",
nf.path,
nf.summary,
@@ -496,7 +497,8 @@ async fn update_flow(
flow_path,
w_id,
nf.tag,
nf.dedicated_worker
nf.dedicated_worker,
nf.visible_to_runner_only.unwrap_or(false),
)
.execute(&mut tx)
.await?;
@@ -669,6 +671,8 @@ pub struct FlowWDraft {
pub ws_error_handler_muted: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dedicated_worker: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visible_to_runner_only: Option<bool>,
}
async fn get_flow_by_path_w_draft(
@@ -680,7 +684,7 @@ async fn get_flow_by_path_w_draft(
let mut tx = user_db.begin(&authed).await?;
let flow_o = sqlx::query_as::<_, FlowWDraft>(
"SELECT flow.path, flow.summary, flow,description, flow.schema, flow.value, flow.extra_perms, flow.draft_only, flow.ws_error_handler_muted, flow.dedicated_worker, draft.value as draft, flow.tag
"SELECT flow.path, flow.summary, flow,description, flow.schema, flow.value, flow.extra_perms, flow.draft_only, flow.ws_error_handler_muted, flow.dedicated_worker, draft.value as draft, flow.tag, flow.visible_to_runner_only
FROM flow
LEFT JOIN draft ON
flow.path = draft.path AND draft.workspace_id = $2 AND draft.typ = 'flow'
+6 -3
View File
@@ -88,6 +88,8 @@ pub struct ScriptWDraft {
pub timeout: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub concurrency_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visible_to_runner_only: Option<bool>,
}
pub fn global_service() -> Router {
@@ -472,8 +474,8 @@ async fn create_script(
content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, \
draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, \
dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, \
delete_after_use, timeout, concurrency_key) \
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27)",
delete_after_use, timeout, concurrency_key, visible_to_runner_only) \
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28)",
&w_id,
&hash.0,
ns.path,
@@ -501,6 +503,7 @@ async fn create_script(
ns.delete_after_use,
ns.timeout,
ns.concurrency_key,
ns.visible_to_runner_only,
)
.execute(&mut tx)
.await?;
@@ -720,7 +723,7 @@ async fn get_script_by_path_w_draft(
let mut tx = user_db.begin(&authed).await?;
let script_o = sqlx::query_as::<_, ScriptWDraft>(
"SELECT hash, script.path, summary, description, content, language, kind, tag, schema, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, ws_error_handler_muted, draft.value as draft, dedicated_worker, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key FROM script LEFT JOIN draft ON
"SELECT hash, script.path, summary, description, content, language, kind, tag, schema, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, ws_error_handler_muted, draft.value as draft, dedicated_worker, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only FROM script LEFT JOIN draft ON
script.path = draft.path AND script.workspace_id = draft.workspace_id AND draft.typ = 'script'
WHERE script.path = $1 AND script.workspace_id = $2 \
AND script.created_at = (SELECT max(created_at) FROM script WHERE path = $1 AND \
+3
View File
@@ -2157,6 +2157,8 @@ struct ScriptMetadata {
pub delete_after_use: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub restart_unless_cancelled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visible_to_runner_only: Option<bool>,
}
pub fn is_none_or_false(val: &Option<bool>) -> bool {
@@ -2432,6 +2434,7 @@ async fn tarball_workspace(
timeout: script.timeout,
delete_after_use: script.delete_after_use,
restart_unless_cancelled: script.restart_unless_cancelled,
visible_to_runner_only: script.visible_to_runner_only,
};
let metadata_str = serde_json::to_string_pretty(&metadata).unwrap();
archive
+3
View File
@@ -44,6 +44,8 @@ pub struct Flow {
pub ws_error_handler_muted: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visible_to_runner_only: Option<bool>,
}
#[derive(Serialize, sqlx::FromRow)]
@@ -77,6 +79,7 @@ pub struct NewFlow {
pub dedicated_worker: Option<bool>,
pub timeout: Option<i32>,
pub deployment_message: Option<String>,
pub visible_to_runner_only: Option<bool>,
}
#[derive(Deserialize, Serialize, Debug, Clone, Default)]
+10 -14
View File
@@ -22,8 +22,7 @@ use serde_json::to_string_pretty;
use crate::utils::StripPath;
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Hash, Eq)]
#[derive(sqlx::Type)]
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Hash, Eq, sqlx::Type)]
#[sqlx(type_name = "SCRIPT_LANG", rename_all = "lowercase")]
#[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))]
pub enum ScriptLang {
@@ -62,13 +61,11 @@ impl ScriptLang {
}
}
#[derive(PartialEq, Debug, Hash, Clone, Copy)]
#[derive(sqlx::Type)]
#[derive(PartialEq, Debug, Hash, Clone, Copy, sqlx::Type)]
#[sqlx(transparent)]
pub struct ScriptHash(pub i64);
#[derive(PartialEq)]
#[derive(sqlx::Type)]
#[derive(PartialEq, sqlx::Type)]
#[sqlx(transparent, no_pg_array)]
pub struct ScriptHashes(pub Vec<i64>);
@@ -109,8 +106,7 @@ impl Serialize for ScriptHashes {
}
}
#[derive(Serialize, Deserialize, Debug, Hash)]
#[derive(sqlx::Type)]
#[derive(Serialize, Deserialize, Debug, Hash, sqlx::Type)]
#[sqlx(type_name = "SCRIPT_KIND", rename_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum ScriptKind {
@@ -132,8 +128,7 @@ impl Display for ScriptKind {
}
}
#[derive(Serialize)]
#[derive(sqlx::FromRow)]
#[derive(Serialize, sqlx::FromRow)]
pub struct Script {
pub workspace_id: String,
pub hash: ScriptHash,
@@ -178,10 +173,11 @@ pub struct Script {
pub restart_unless_cancelled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub concurrency_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub visible_to_runner_only: Option<bool>,
}
#[derive(Serialize)]
#[derive(sqlx::FromRow)]
#[derive(Serialize, sqlx::FromRow)]
pub struct ListableScript {
pub hash: ScriptHash,
pub path: String,
@@ -212,8 +208,7 @@ pub struct ScriptHistoryUpdate {
pub deployment_msg: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(sqlx::Type)]
#[derive(Serialize, Deserialize, Debug, sqlx::Type)]
#[sqlx(transparent)]
#[serde(transparent)]
pub struct Schema(pub serde_json::Value);
@@ -255,6 +250,7 @@ pub struct NewScript {
pub deployment_message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub concurrency_key: Option<String>,
pub visible_to_runner_only: Option<bool>,
}
fn lock_deserialize<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
+5 -1
View File
@@ -164,7 +164,9 @@ export async function handleFile(
remote.concurrency_time_window_s &&
typed.concurrent_limit == remote.concurrent_limit &&
Boolean(typed.restart_unless_cancelled) ==
Boolean(remote.restart_unless_cancelled))
Boolean(remote.restart_unless_cancelled) &&
Boolean(typed.visible_to_runner_only) ==
Boolean(remote.visible_to_runner_only))
) {
log.info(colors.green(`Script ${remotePath} is up to date`));
return true;
@@ -194,6 +196,7 @@ export async function handleFile(
concurrent_limit: typed?.concurrent_limit,
deployment_message: message,
restart_unless_cancelled: typed?.restart_unless_cancelled,
visible_to_runner_only: typed?.visible_to_runner_only,
},
});
} else {
@@ -221,6 +224,7 @@ export async function handleFile(
concurrent_limit: typed?.concurrent_limit,
deployment_message: message,
restart_unless_cancelled: typed?.restart_unless_cancelled,
visible_to_runner_only: typed?.visible_to_runner_only,
},
});
}
@@ -157,7 +157,8 @@
schema: flow.schema,
tag: flow.tag,
draft_only: true,
ws_error_handler_muted: flow.ws_error_handler_muted
ws_error_handler_muted: flow.ws_error_handler_muted,
visible_to_runner_only: flow.visible_to_runner_only
}
})
}
@@ -235,7 +236,8 @@
schema: flow.schema,
ws_error_handler_muted: flow.ws_error_handler_muted,
tag: flow.tag,
dedicated_worker: flow.dedicated_worker
dedicated_worker: flow.dedicated_worker,
visible_to_runner_only: flow.visible_to_runner_only
}
})
if (enabled) {
@@ -297,7 +299,8 @@
schema: flow.schema,
tag: flow.tag,
dedicated_worker: flow.dedicated_worker,
ws_error_handler_muted: flow.ws_error_handler_muted
ws_error_handler_muted: flow.ws_error_handler_muted,
visible_to_runner_only: flow.visible_to_runner_only
}
})
}
@@ -53,7 +53,8 @@
schema: flow.schema,
tag: flow.tag,
dedicated_worker: flow.dedicated_worker,
ws_error_handler_muted: flow.ws_error_handler_muted
ws_error_handler_muted: flow.ws_error_handler_muted,
visible_to_runner_only: flow.visible_to_runner_only
}
})
} else if (kind == 'script') {
+1 -1
View File
@@ -49,7 +49,7 @@
export let viewKeybinding = false
export let scheduledForStr: string | undefined
export let invisible_to_owner: false | undefined
export let invisible_to_owner: boolean | undefined
export let overrideTag: string | undefined
export let args: Record<string, any> = {}
@@ -25,7 +25,7 @@
| undefined
export let scheduledForStr: string | undefined
export let invisible_to_owner: false | undefined
export let invisible_to_owner: boolean | undefined
export let overrideTag: string | undefined
loadWorkerGroups()
@@ -241,7 +241,8 @@
restart_unless_cancelled: script.restart_unless_cancelled,
delete_after_use: script.delete_after_use,
timeout: script.timeout,
concurrency_key: emptyString(script.concurrency_key) ? undefined : script.concurrency_key
concurrency_key: emptyString(script.concurrency_key) ? undefined : script.concurrency_key,
visible_to_runner_only: script.visible_to_runner_only
}
})
@@ -365,7 +366,8 @@
timeout: script.timeout,
concurrency_key: emptyString(script.concurrency_key)
? undefined
: script.concurrency_key
: script.concurrency_key,
visible_to_runner_only: script.visible_to_runner_only
}
})
}
@@ -875,6 +877,31 @@
</svelte:fragment>
</Section>
{/if}
<Section label="Runs visibility">
<svelte:fragment slot="header">
<Tooltip>
When this option is enabled, manual executions of this script are invisible to
users other than the user running it, including the owner(s). This setting can
be overridden when this script is run manually from the advanced menu.
</Tooltip>
</svelte:fragment>
<div class="flex gap-2 shrink flex-col">
<Toggle
size="sm"
checked={Boolean(script.visible_to_runner_only)}
on:change={() => {
if (script.visible_to_runner_only) {
script.visible_to_runner_only = undefined
} else {
script.visible_to_runner_only = true
}
}}
options={{
right: 'Make runs invisible to others'
}}
/>
</div>
</Section>
{#if !isCloudHosted()}
<Section label="Custom env variables">
<svelte:fragment slot="header">
@@ -161,6 +161,23 @@
</svelte:fragment>
</Toggle>
<Toggle
size="sm"
checked={Boolean($flowStore.visible_to_runner_only)}
on:change={() => {
if ($flowStore.visible_to_runner_only) {
$flowStore.visible_to_runner_only = undefined
} else {
$flowStore.visible_to_runner_only = true
}
}}
options={{
right: 'Make runs invisible to others',
rightTooltip:
'When this option is enabled, manual executions of this script are invisible to users other than the user running it, including the owner(s). This setting can be overridden when this script is run manually from the advanced menu.'
}}
/>
<div class="flex flex-row items-center gap-1">
<ErrorHandlerToggleButton
kind="flow"
@@ -46,6 +46,7 @@
envs?: string[]
ws_error_handler_muted?: boolean
dedicated_worker?: boolean
visible_to_runner_only?: boolean
}
| undefined = undefined
@@ -61,6 +62,8 @@
kind: 'script' | 'failure' | 'trigger' | 'command' | 'approval' | undefined
envs?: string[]
ws_error_handler_muted?: boolean
dedicated_worker?: boolean
visible_to_runner_only?: boolean
}
| undefined = undefined
+6 -1
View File
@@ -14,7 +14,12 @@ export type FlowEditorContext = {
history: History<OpenFlow>
pathStore: Writable<string>
flowStore: Writable<
OpenFlow & { tag?: string; ws_error_handler_muted?: boolean; dedicated_worker?: boolean }
OpenFlow & {
tag?: string
ws_error_handler_muted?: boolean
dedicated_worker?: boolean
visible_to_runner_only?: boolean
}
>
flowStateStore: Writable<FlowState>
testStepStore: Writable<Record<string, any>>
+6 -1
View File
@@ -70,7 +70,12 @@ export function evalValue(
export function cleanInputs(
flow: OpenFlow | any
): OpenFlow & { tag?: string; ws_error_handler_muted?: boolean; dedicated_worker?: boolean } {
): OpenFlow & {
tag?: string
ws_error_handler_muted?: boolean
dedicated_worker?: boolean
visible_to_runner_only?: boolean
} {
const newFlow: Flow = JSON.parse(JSON.stringify(flow))
newFlow.value.modules.forEach((mod) => {
if (mod.value.type == 'rawscript' || mod.value.type == 'script') {
@@ -52,7 +52,7 @@
let deploymentInProgress = false
let scheduledForStr: string | undefined = undefined
let invisible_to_owner: false | undefined = undefined
let invisible_to_owner: boolean | undefined = undefined
let overrideTag: string | undefined = undefined
$: cliCommand = `wmill flow run ${flow?.path} -d '${JSON.stringify(args)}'`
@@ -81,6 +81,9 @@
let schedule: Schedule | undefined = undefined
async function loadFlow(): Promise<void> {
flow = await FlowService.getFlowByPath({ workspace: $workspaceStore!, path })
if (!flow.path.startsWith(`u/${$userStore?.username}`) && flow.path.split('/').length > 2) {
invisible_to_owner = flow.visible_to_runner_only
}
can_write = canWrite(flow.path, flow.extra_perms!, $userStore)
try {
schedule = await loadFlowSchedule(path, $workspaceStore!)
@@ -571,10 +571,13 @@
<Badge color="indigo">Tag: {job.tag}</Badge>
</div>
{/if}
{#if !job.visible_to_owner}<Badge color="red"
>only visible to you <Tooltip
>The option to hide this run from the owner of this script or flow was activated</Tooltip
></Badge
{#if !job.visible_to_owner}
<div
><Badge color="red"
>only visible to you <Tooltip
>The option to hide this run from the owner of this script or flow was activated</Tooltip
>
</Badge></div
>
{/if}
</div>
@@ -77,7 +77,7 @@
let runForm: RunForm
let scheduledForStr: string | undefined = undefined
let invisible_to_owner: false | undefined = undefined
let invisible_to_owner: boolean | undefined = undefined
let overrideTag: string | undefined = undefined
$: cliCommand = `wmill script run ${script?.path} -d '${JSON.stringify(args)}'`
@@ -172,6 +172,9 @@
if (deploymentInProgress) {
intervalId = setInterval(syncer, 500)
}
if (!script.path.startsWith(`u/${$userStore?.username}`) && script.path.split('/').length > 2) {
invisible_to_owner = script.visible_to_runner_only
}
}
onDestroy(() => {