- Replaced rigid TIERs with continuous COMPLEXITY 1-5 scale in semantics.md - Updated generate_semantic_map.py to parse and score based on Complexity - Added backward compatibility mapping for legacy TIERs - Migrated all .ai/shots examples to use @COMPLEXITY and updated relation syntax - Added trivial_utility.py shot to demonstrate implicit Complexity 1 token savings
92 lines
3.3 KiB
Svelte
92 lines
3.3 KiB
Svelte
<!-- [DEF:FrontendComponentShot:Component] -->
|
|
<!--
|
|
/**
|
|
* @COMPLEXITY: 5
|
|
* @SEMANTICS: Task, Button, Action, UX
|
|
* @PURPOSE: Action button to spawn a new task with full UX feedback cycle.
|
|
* @LAYER: UI (Presentation)
|
|
* @RELATION: [CALLS] ->[postApi]
|
|
*
|
|
* @INVARIANT: Must prevent double-submission while loading.
|
|
* @INVARIANT: Loading state must always terminate (no infinite spinner).
|
|
* @INVARIANT: User must receive feedback on both success and failure.
|
|
*
|
|
* @SIDE_EFFECT: Sends network request and emits toast notifications.
|
|
* @DATA_CONTRACT: Input -> { plugin_id: string, params: object }, Output -> { task_id?: string }
|
|
*
|
|
* @UX_REACTIVITY: Props -> $props(), LocalState -> $state(isLoading).
|
|
* @UX_STATE: Idle -> Button enabled, primary color, no spinner.
|
|
* @UX_STATE: Loading -> Button disabled, spinner visible, aria-busy=true.
|
|
* @UX_STATE: Success -> Toast success displayed.
|
|
* @UX_STATE: Error -> Toast error displayed.
|
|
* @UX_FEEDBACK: toast.success, toast.error
|
|
* @UX_RECOVERY: Error -> Keep form interactive and allow retry after failure.
|
|
*
|
|
* @TEST_CONTRACT: ComponentState ->
|
|
* {
|
|
* required_fields: { isLoading: bool },
|
|
* invariants:[
|
|
* "isLoading=true implies button.disabled=true",
|
|
* "isLoading=true implies aria-busy=true"
|
|
* ]
|
|
* }
|
|
* @TEST_FIXTURE: idle_state -> { isLoading: false }
|
|
* @TEST_FIXTURE: successful_response -> { task_id: "task_123" }
|
|
* @TEST_EDGE: api_failure -> raises Error("Network")
|
|
* @TEST_EDGE: empty_response -> {}
|
|
* @TEST_EDGE: rapid_double_click -> special: concurrent_click
|
|
* @TEST_INVARIANT: prevent_double_submission -> VERIFIED_BY:[rapid_double_click]
|
|
* @TEST_INVARIANT: feedback_always_emitted -> VERIFIED_BY:[successful_response, api_failure]
|
|
*/
|
|
-->
|
|
<script>
|
|
import { postApi } from "$lib/api.js";
|
|
import { t } from "$lib/i18n";
|
|
import { toast } from "$lib/stores/toast";
|
|
|
|
// GRACE Svelte 5 Runes
|
|
let { plugin_id = "", params = {} } = $props();
|
|
let isLoading = $state(false);
|
|
|
|
// [DEF:spawnTask:Function]
|
|
/**
|
|
* @PURPOSE: Execute task creation request and emit user feedback.
|
|
* @PRE: plugin_id is resolved and request params are serializable.
|
|
* @POST: isLoading is reset and user receives success/error feedback.
|
|
*/
|
|
async function spawnTask() {
|
|
isLoading = true;
|
|
console.info("[spawnTask][REASON] Spawning task...", { plugin_id });
|
|
|
|
try {
|
|
// 1. Action: API Call
|
|
const response = await postApi("/api/tasks", { plugin_id, params });
|
|
|
|
// 2. Feedback: Success validation
|
|
if (response.task_id) {
|
|
console.info("[spawnTask][REFLECT] Task created.", { task_id: response.task_id });
|
|
toast.success($t.tasks.spawned_success);
|
|
}
|
|
} catch (error) {
|
|
// 3. Recovery: Error handling & fallback logic
|
|
console.error("[spawnTask][EXPLORE] Failed to spawn task. Notifying user.", { error });
|
|
toast.error(`${$t.errors.task_failed}: ${error.message}`);
|
|
} finally {
|
|
isLoading = false;
|
|
}
|
|
}
|
|
// [/DEF:spawnTask:Function]
|
|
</script>
|
|
|
|
<button
|
|
onclick={spawnTask}
|
|
disabled={isLoading}
|
|
class="btn-primary flex items-center gap-2"
|
|
aria-busy={isLoading}
|
|
>
|
|
{#if isLoading}
|
|
<span class="animate-spin" aria-label="Loading">🌀</span>
|
|
{/if}
|
|
<span>{$t.actions.start_task}</span>
|
|
</button>
|
|
<!-- [/DEF:FrontendComponentShot:Component] --> |