few shots update
This commit is contained in:
@@ -11,45 +11,27 @@
|
||||
* @INVARIANT: Loading state must always terminate (no infinite spinner).
|
||||
* @INVARIANT: User must receive feedback on both success and failure.
|
||||
*
|
||||
* @UX_REACTIVITY: Props -> $props(), LocalState -> $state(isLoading).
|
||||
*
|
||||
* @TEST_CONTRACT: ComponentState ->
|
||||
* {
|
||||
* required_fields: {
|
||||
* isLoading: bool
|
||||
* },
|
||||
* invariants: [
|
||||
* required_fields: { isLoading: bool },
|
||||
* invariants:[
|
||||
* "isLoading=true implies button.disabled=true",
|
||||
* "isLoading=true implies aria-busy=true",
|
||||
* "isLoading=true implies spinner visible"
|
||||
* "isLoading=true implies aria-busy=true"
|
||||
* ]
|
||||
* }
|
||||
*
|
||||
* @TEST_CONTRACT: ApiResponse ->
|
||||
* {
|
||||
* required_fields: {},
|
||||
* optional_fields: {
|
||||
* task_id: str
|
||||
* }
|
||||
* }
|
||||
|
||||
* @TEST_FIXTURE: idle_state ->
|
||||
* {
|
||||
* isLoading: false
|
||||
* }
|
||||
*
|
||||
* @TEST_FIXTURE: successful_response ->
|
||||
* {
|
||||
* task_id: "task_123"
|
||||
* }
|
||||
|
||||
* @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_EDGE: unresolved_promise -> special: pending_state
|
||||
|
||||
* @TEST_INVARIANT: prevent_double_submission -> verifies: [rapid_double_click]
|
||||
* @TEST_INVARIANT: loading_state_consistency -> verifies: [idle_state, pending_state]
|
||||
* @TEST_INVARIANT: feedback_always_emitted -> verifies: [successful_response, api_failure]
|
||||
|
||||
*
|
||||
* @TEST_INVARIANT: prevent_double_submission -> VERIFIED_BY:[rapid_double_click]
|
||||
* @TEST_INVARIANT: feedback_always_emitted -> VERIFIED_BY:[successful_response, api_failure]
|
||||
*
|
||||
* @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.
|
||||
@@ -59,44 +41,39 @@
|
||||
*
|
||||
* @UX_TEST: Idle -> {click: spawnTask, expected: isLoading=true}
|
||||
* @UX_TEST: Loading -> {double_click: ignored, expected: single_api_call}
|
||||
* @UX_TEST: Success -> {api_resolve: task_id, expected: toast.success called}
|
||||
* @UX_TEST: Error -> {api_reject: error, expected: toast.error called}
|
||||
*/
|
||||
-->
|
||||
<script>
|
||||
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;
|
||||
// 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.
|
||||
* @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.log("[FrontendComponentShot][Loading] Spawning task...");
|
||||
console.info("[spawnTask][REASON] Spawning task...", { plugin_id });
|
||||
|
||||
try {
|
||||
// 1. Action: API Call
|
||||
const response = await postApi("/api/tasks", {
|
||||
plugin_id,
|
||||
params
|
||||
});
|
||||
const response = await postApi("/api/tasks", { plugin_id, params });
|
||||
|
||||
// 2. Feedback: Success
|
||||
// 2. Feedback: Success validation
|
||||
if (response.task_id) {
|
||||
console.log("[FrontendComponentShot][Success] Task created.");
|
||||
console.info("[spawnTask][REFLECT] Task created.", { task_id: response.task_id });
|
||||
toast.success($t.tasks.spawned_success);
|
||||
}
|
||||
} catch (error) {
|
||||
// 3. Recovery: User notification
|
||||
console.log("[FrontendComponentShot][Error] Failed:", 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;
|
||||
@@ -106,7 +83,7 @@
|
||||
</script>
|
||||
|
||||
<button
|
||||
on:click={spawnTask}
|
||||
onclick={spawnTask}
|
||||
disabled={isLoading}
|
||||
class="btn-primary flex items-center gap-2"
|
||||
aria-busy={isLoading}
|
||||
|
||||
Reference in New Issue
Block a user