64 lines
1.8 KiB
Svelte
64 lines
1.8 KiB
Svelte
<!-- [DEF:Shot:Svelte_Component:Example] -->
|
|
# @PURPOSE: Reference implementation of a task-spawning component using Constitution rules.
|
|
# @RELATION: IMPLEMENTS -> [DEF:Std:UI_Svelte]
|
|
|
|
<script>
|
|
/**
|
|
* @TIER: STANDARD
|
|
* @PURPOSE: Action button to spawn a new task.
|
|
* @LAYER: UI
|
|
* @SEMANTICS: Task, Creation, Button
|
|
* @RELATION: CALLS -> postApi
|
|
*
|
|
* @UX_STATE: Idle -> Button enabled with primary color.
|
|
* @UX_STATE: Loading -> Button disabled with spinner while postApi resolves.
|
|
* @UX_FEEDBACK: toast.success on completion; toast.error on failure.
|
|
* @UX_TEST: Idle -> {click: spawnTask, expected: loading state then success}
|
|
*/
|
|
import { postApi } from "$lib/api.js";
|
|
import { t } from "$lib/i18n";
|
|
import { toast } from "$lib/stores/toast";
|
|
|
|
export let plugin_id = "";
|
|
export let params = {};
|
|
|
|
let isLoading = false;
|
|
|
|
async def spawnTask() {
|
|
isLoading = true;
|
|
try {
|
|
// 1. Action: Constitution Rule - MUST use postApi wrapper
|
|
const response = await postApi("/api/tasks", {
|
|
plugin_id,
|
|
params
|
|
});
|
|
|
|
// 2. Feedback: UX state management
|
|
if (response.task_id) {
|
|
toast.success($t.tasks.spawned_success);
|
|
}
|
|
} catch (error) {
|
|
// 3. Recovery: Evaluation & UI reporting
|
|
toast.error(`${$t.errors.task_failed}: ${error.message}`);
|
|
} finally {
|
|
isLoading = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<button
|
|
on:click={spawnTask}
|
|
disabled={isLoading}
|
|
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center gap-2"
|
|
>
|
|
{#if isLoading}
|
|
<span class="animate-spin text-sm">🌀</span>
|
|
{/if}
|
|
<span>{$t.actions.start_task}</span>
|
|
</button>
|
|
|
|
<style>
|
|
/* Local styles minimized as per Constitution Rule III */
|
|
</style>
|
|
<!-- [/DEF:Shot:Svelte_Component] -->
|