Create the example workspace in the browser build

This commit is contained in:
Gregory Schier
2026-09-15 16:32:20 -07:00
parent f827aae46d
commit 2c51fc92d6
12 changed files with 117 additions and 91 deletions
+16 -1
View File
@@ -21,6 +21,9 @@ import { Button } from "./core/Button";
/** Shown instead of a workspace when there are none. */ /** Shown instead of a workspace when there are none. */
export function Onboarding() { export function Onboarding() {
const settings = useAtomValue(settingsAtom); const settings = useAtomValue(settingsAtom);
const { capabilities } = platform;
const canImport = capabilities.plugins;
const showAlreadyUsing = capabilities.localFiles || capabilities.git || canImport;
const [busy, setBusy] = useState<OnboardingChoice | null>(null); const [busy, setBusy] = useState<OnboardingChoice | null>(null);
const choose = (choice: OnboardingChoice, run: () => Promise<void> | void) => async () => { const choose = (choice: OnboardingChoice, run: () => Promise<void> | void) => async () => {
@@ -55,11 +58,14 @@ export function Onboarding() {
<div className="flex flex-col gap-1.5"> <div className="flex flex-col gap-1.5">
<Heading>How would you like to get started?</Heading> <Heading>How would you like to get started?</Heading>
<p className="text-text-subtle"> <p className="text-text-subtle">
Bring over existing work, try a real API, or start fresh. {canImport
? "Bring over existing work, try a real API, or start fresh."
: "Try a real API, or start fresh."}
</p> </p>
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{canImport && (
<StartOption <StartOption
color="primary" color="primary"
icon="folder_input" icon="folder_input"
@@ -69,6 +75,7 @@ export function Onboarding() {
disabled={busy != null} disabled={busy != null}
onClick={choose("import", () => importData.mutateAsync())} onClick={choose("import", () => importData.mutateAsync())}
/> />
)}
<StartOption <StartOption
color="info" color="info"
icon="flask" icon="flask"
@@ -89,9 +96,11 @@ export function Onboarding() {
/> />
</div> </div>
{showAlreadyUsing && (
<div className="pt-5 border-t border-dashed border-border-subtle flex flex-col items-start gap-2.5"> <div className="pt-5 border-t border-dashed border-border-subtle flex flex-col items-start gap-2.5">
<span className="text-sm text-text-subtle">Already using Yaak?</span> <span className="text-sm text-text-subtle">Already using Yaak?</span>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{capabilities.localFiles && (
<Button <Button
size="xs" size="xs"
variant="border" variant="border"
@@ -110,6 +119,8 @@ export function Onboarding() {
> >
Open folder Open folder
</Button> </Button>
)}
{capabilities.git && (
<Button <Button
size="xs" size="xs"
variant="border" variant="border"
@@ -127,6 +138,8 @@ export function Onboarding() {
> >
Clone repository Clone repository
</Button> </Button>
)}
{canImport && (
<Button <Button
size="xs" size="xs"
variant="border" variant="border"
@@ -137,8 +150,10 @@ export function Onboarding() {
> >
Import Import
</Button> </Button>
)}
</div> </div>
</div> </div>
)}
</div> </div>
</div> </div>
</div> </div>
@@ -31,6 +31,10 @@ export function RedirectToLatestWorkspace() {
request_id: requestId, request_id: requestId,
}; };
// Whatever created the first workspace may have already navigated into it
const currentId = router.history.location.pathname.match(/^\/workspaces\/([^/]+)/)?.[1];
if (workspaces.some((w) => w.id === currentId)) return;
console.log("Redirecting to workspace", params, search); console.log("Redirecting to workspace", params, search);
await router.navigate({ to: "/workspaces/$workspaceId", params, search }); await router.navigate({ to: "/workspaces/$workspaceId", params, search });
})(), })(),
+1 -1
View File
@@ -2,7 +2,7 @@
use crate::error::Result; use crate::error::Result;
use crate::host::Host; use crate::host::Host;
use yaak::example::create_example_workspace; use yaak_models::example::create_example_workspace;
use yaak_models::export::{self, ExportDataParams}; use yaak_models::export::{self, ExportDataParams};
use yaak_models::util::BatchUpsertResult; use yaak_models::util::BatchUpsertResult;
use yaak_rpc_schema::*; use yaak_rpc_schema::*;
@@ -4,10 +4,10 @@
//! other (the chaining example names another request by id). Every placeholder //! other (the chaining example names another request by id). Every placeholder
//! gets a fresh id per creation, so the example can be created more than once. //! gets a fresh id per creation, so the example can be created more than once.
use crate::Result; use crate::error::Result;
use yaak_models::models::{Environment, Folder, HttpRequest, UpsertModelInfo, Workspace}; use crate::models::{Environment, Folder, HttpRequest, UpsertModelInfo, Workspace};
use yaak_models::query_manager::QueryManager; use crate::query_manager::QueryManager;
use yaak_models::util::{BatchUpsertResult, UpdateSource}; use crate::util::{BatchUpsertResult, UpdateSource};
const EXAMPLE_JSON: &str = include_str!("example_workspace.json"); const EXAMPLE_JSON: &str = include_str!("example_workspace.json");
@@ -67,7 +67,7 @@ fn example_resources() -> Result<BatchUpsertResult> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use yaak_models::init_in_memory; use crate::init_in_memory;
#[test] #[test]
fn every_placeholder_is_mapped() { fn every_placeholder_is_mapped() {
+1
View File
@@ -13,6 +13,7 @@ pub mod client_db;
mod connection_or_tx; mod connection_or_tx;
pub mod cookies; pub mod cookies;
pub mod error; pub mod error;
pub mod example;
pub mod export; pub mod export;
pub mod migrate; pub mod migrate;
pub mod models; pub mod models;
+19 -19
View File
@@ -512,7 +512,7 @@ export function __wbg_new_typed_c072c4ce9a2a0cdf(arg0, arg1) {
const a = state0.a; const a = state0.a;
state0.a = 0; state0.a = 0;
try { try {
return wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___js_sys_434c4d6d72aa7d1b___Function_fn_wasm_bindgen_9b5275515258a0f8___JsValue_____wasm_bindgen_9b5275515258a0f8___sys__Undefined___js_sys_434c4d6d72aa7d1b___Function_fn_wasm_bindgen_9b5275515258a0f8___JsValue_____wasm_bindgen_9b5275515258a0f8___sys__Undefined_______true_(a, state0.b, arg0, arg1); return wasm_bindgen__convert__closures_____invoke__h7cced28f7815df81(a, state0.b, arg0, arg1);
} finally { } finally {
state0.a = a; state0.a = a;
} }
@@ -697,23 +697,23 @@ export function __wbg_warn_b6f36cac66fc96a4(arg0, arg1) {
console.warn(arg0, arg1); console.warn(arg0, arg1);
} }
export function __wbindgen_cast_0000000000000001(arg0, arg1) { export function __wbindgen_cast_0000000000000001(arg0, arg1) {
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1116, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1131, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
const ret = makeMutClosure(arg0, arg1, wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___wasm_bindgen_9b5275515258a0f8___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_9b5275515258a0f8___JsError___true_); const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2c4f0a20127a8a23);
return ret; return ret;
} }
export function __wbindgen_cast_0000000000000002(arg0, arg1) { export function __wbindgen_cast_0000000000000002(arg0, arg1) {
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 206, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 214, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
const ret = makeMutClosure(arg0, arg1, wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___web_sys_e1a11cd1518a8b4d___features__gen_Event__Event______true_); const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h54297d6cc284a2e5);
return ret; return ret;
} }
export function __wbindgen_cast_0000000000000003(arg0, arg1) { export function __wbindgen_cast_0000000000000003(arg0, arg1) {
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("IDBVersionChangeEvent")], shim_idx: 113, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("IDBVersionChangeEvent")], shim_idx: 177, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
const ret = makeMutClosure(arg0, arg1, wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___web_sys_e1a11cd1518a8b4d___features__gen_IdbVersionChangeEvent__IdbVersionChangeEvent__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_9b5275515258a0f8___JsValue___true_); const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h804afe9d352bd562);
return ret; return ret;
} }
export function __wbindgen_cast_0000000000000004(arg0, arg1) { export function __wbindgen_cast_0000000000000004(arg0, arg1) {
// Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 208, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 216, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
const ret = makeMutClosure(arg0, arg1, wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke_______true_); const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h5977a2970909c8b8);
return ret; return ret;
} }
export function __wbindgen_cast_0000000000000005(arg0) { export function __wbindgen_cast_0000000000000005(arg0) {
@@ -750,30 +750,30 @@ export function __wbindgen_init_externref_table() {
table.set(offset + 2, true); table.set(offset + 2, true);
table.set(offset + 3, false); table.set(offset + 3, false);
} }
function wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke_______true_(arg0, arg1) { function wasm_bindgen__convert__closures_____invoke__h5977a2970909c8b8(arg0, arg1) {
wasm.wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke_______true_(arg0, arg1); wasm.wasm_bindgen__convert__closures_____invoke__h5977a2970909c8b8(arg0, arg1);
} }
function wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___web_sys_e1a11cd1518a8b4d___features__gen_Event__Event______true_(arg0, arg1, arg2) { function wasm_bindgen__convert__closures_____invoke__h54297d6cc284a2e5(arg0, arg1, arg2) {
wasm.wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___web_sys_e1a11cd1518a8b4d___features__gen_Event__Event______true_(arg0, arg1, arg2); wasm.wasm_bindgen__convert__closures_____invoke__h54297d6cc284a2e5(arg0, arg1, arg2);
} }
function wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___wasm_bindgen_9b5275515258a0f8___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_9b5275515258a0f8___JsError___true_(arg0, arg1, arg2) { function wasm_bindgen__convert__closures_____invoke__h2c4f0a20127a8a23(arg0, arg1, arg2) {
const ret = wasm.wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___wasm_bindgen_9b5275515258a0f8___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_9b5275515258a0f8___JsError___true_(arg0, arg1, arg2); const ret = wasm.wasm_bindgen__convert__closures_____invoke__h2c4f0a20127a8a23(arg0, arg1, arg2);
if (ret[1]) { if (ret[1]) {
throw takeFromExternrefTable0(ret[0]); throw takeFromExternrefTable0(ret[0]);
} }
} }
function wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___web_sys_e1a11cd1518a8b4d___features__gen_IdbVersionChangeEvent__IdbVersionChangeEvent__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_9b5275515258a0f8___JsValue___true_(arg0, arg1, arg2) { function wasm_bindgen__convert__closures_____invoke__h804afe9d352bd562(arg0, arg1, arg2) {
const ret = wasm.wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___web_sys_e1a11cd1518a8b4d___features__gen_IdbVersionChangeEvent__IdbVersionChangeEvent__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_9b5275515258a0f8___JsValue___true_(arg0, arg1, arg2); const ret = wasm.wasm_bindgen__convert__closures_____invoke__h804afe9d352bd562(arg0, arg1, arg2);
if (ret[1]) { if (ret[1]) {
throw takeFromExternrefTable0(ret[0]); throw takeFromExternrefTable0(ret[0]);
} }
} }
function wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___js_sys_434c4d6d72aa7d1b___Function_fn_wasm_bindgen_9b5275515258a0f8___JsValue_____wasm_bindgen_9b5275515258a0f8___sys__Undefined___js_sys_434c4d6d72aa7d1b___Function_fn_wasm_bindgen_9b5275515258a0f8___JsValue_____wasm_bindgen_9b5275515258a0f8___sys__Undefined_______true_(arg0, arg1, arg2, arg3) { function wasm_bindgen__convert__closures_____invoke__h7cced28f7815df81(arg0, arg1, arg2, arg3) {
wasm.wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___js_sys_434c4d6d72aa7d1b___Function_fn_wasm_bindgen_9b5275515258a0f8___JsValue_____wasm_bindgen_9b5275515258a0f8___sys__Undefined___js_sys_434c4d6d72aa7d1b___Function_fn_wasm_bindgen_9b5275515258a0f8___JsValue_____wasm_bindgen_9b5275515258a0f8___sys__Undefined_______true_(arg0, arg1, arg2, arg3); wasm.wasm_bindgen__convert__closures_____invoke__h7cced28f7815df81(arg0, arg1, arg2, arg3);
} }
Binary file not shown.
+5 -5
View File
@@ -17,11 +17,11 @@ export const rust_sqlite_wasm_malloc: (a: number) => number;
export const rust_sqlite_wasm_realloc: (a: number, b: number) => number; export const rust_sqlite_wasm_realloc: (a: number, b: number) => number;
export const sqlite3_os_end: () => number; export const sqlite3_os_end: () => number;
export const sqlite3_os_init: () => number; export const sqlite3_os_init: () => number;
export const wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___wasm_bindgen_9b5275515258a0f8___JsValue__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_9b5275515258a0f8___JsError___true_: (a: number, b: number, c: any) => [number, number]; export const wasm_bindgen__convert__closures_____invoke__h2c4f0a20127a8a23: (a: number, b: number, c: any) => [number, number];
export const wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___web_sys_e1a11cd1518a8b4d___features__gen_IdbVersionChangeEvent__IdbVersionChangeEvent__core_f0fd674eaa06beef___result__Result_____wasm_bindgen_9b5275515258a0f8___JsValue___true_: (a: number, b: number, c: any) => [number, number]; export const wasm_bindgen__convert__closures_____invoke__h804afe9d352bd562: (a: number, b: number, c: any) => [number, number];
export const wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___js_sys_434c4d6d72aa7d1b___Function_fn_wasm_bindgen_9b5275515258a0f8___JsValue_____wasm_bindgen_9b5275515258a0f8___sys__Undefined___js_sys_434c4d6d72aa7d1b___Function_fn_wasm_bindgen_9b5275515258a0f8___JsValue_____wasm_bindgen_9b5275515258a0f8___sys__Undefined_______true_: (a: number, b: number, c: any, d: any) => void; export const wasm_bindgen__convert__closures_____invoke__h7cced28f7815df81: (a: number, b: number, c: any, d: any) => void;
export const wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke___web_sys_e1a11cd1518a8b4d___features__gen_Event__Event______true_: (a: number, b: number, c: any) => void; export const wasm_bindgen__convert__closures_____invoke__h54297d6cc284a2e5: (a: number, b: number, c: any) => void;
export const wasm_bindgen_9b5275515258a0f8___convert__closures_____invoke_______true_: (a: number, b: number) => void; export const wasm_bindgen__convert__closures_____invoke__h5977a2970909c8b8: (a: number, b: number) => void;
export const __wbindgen_malloc: (a: number, b: number) => number; export const __wbindgen_malloc: (a: number, b: number) => number;
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
export const __wbindgen_exn_store: (a: number) => void; export const __wbindgen_exn_store: (a: number) => void;
+5
View File
@@ -432,6 +432,11 @@ fn dispatch(
) )
} }
"cmd_create_example_workspace" => to_json(
yaak_models::example::create_example_workspace(&host.queries, source)
.map_err(js_error)?,
),
"cmd_get_workspace_meta" => { "cmd_get_workspace_meta" => {
let req: WorkspaceIdReq = from_js(payload)?; let req: WorkspaceIdReq = from_js(payload)?;
let workspace = let workspace =
-1
View File
@@ -1,5 +1,4 @@
pub mod error; pub mod error;
pub mod example;
pub mod import; pub mod import;
pub mod plugin_events; pub mod plugin_events;
pub mod response_body; pub mod response_body;
+3 -1
View File
@@ -231,6 +231,9 @@ const HANDLERS: Partial<Record<AppCmd, Handler>> = {
// which is the one thing each host answers differently. // which is the one thing each host answers differently.
cmd_export_data: (payload, db) => db.rpc("cmd_export_data", payload), cmd_export_data: (payload, db) => db.rpc("cmd_export_data", payload),
// The same example the desktop creates, built by the model layer in the worker.
cmd_create_example_workspace: (payload, db) => db.rpc("cmd_create_example_workspace", payload),
async cmd_get_sse_events() { async cmd_get_sse_events() {
return []; return [];
}, },
@@ -289,7 +292,6 @@ const DECLINED: Partial<Record<AppCmd, [reason: string, capability: CapabilityNa
cmd_commit_import: ["Importing needs a plugin, which this host doesn't run", null], cmd_commit_import: ["Importing needs a plugin, which this host doesn't run", null],
cmd_list_import_sources: ["Importing isn't available in the browser yet", null], cmd_list_import_sources: ["Importing isn't available in the browser yet", null],
cmd_import_sources_for_origin: ["Importing isn't available in the browser yet", null], cmd_import_sources_for_origin: ["Importing isn't available in the browser yet", null],
cmd_create_example_workspace: ["The example workspace isn't available in the browser yet", null],
cmd_save_response: ["Saving a response to disk isn't available in the browser", "localFiles"], cmd_save_response: ["Saving a response to disk isn't available in the browser", "localFiles"],
cmd_save_base64_to_binary: ["Saving to disk isn't available in the browser", "localFiles"], cmd_save_base64_to_binary: ["Saving to disk isn't available in the browser", "localFiles"],
cmd_format_graphql: ["Formatting GraphQL needs a plugin, which this host doesn't run", null], cmd_format_graphql: ["Formatting GraphQL needs a plugin, which this host doesn't run", null],