feat(state-machine): let blueprints define init, caption, and kinds
RememberMe is the first blueprint whose lifecycle is not the composed LoadState: it starts at NotPersisted (not `loading`), has its own panel caption, and its own transition kinds. Make the init node, the panel caption/field, and the SmKind palette data-driven, with defaults that leave List/Grid/Calendar unchanged.
This commit is contained in:
@@ -161,7 +161,8 @@ const funcCount = computed(() => props.blueprint.functions.length)
|
|||||||
<h2 class="section">Lifecycle — state machine</h2>
|
<h2 class="section">Lifecycle — state machine</h2>
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<div class="cap">
|
<div class="cap">
|
||||||
<span>Composed lifecycle</span><span class="id">loadState : LoadState</span>
|
<span>{{ blueprint.stateMachine?.caption ?? "Composed lifecycle" }}</span
|
||||||
|
><span class="id">{{ blueprint.stateMachine?.field ?? "loadState : LoadState" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="body svg-wrap"><StateMachine :machine="blueprint.stateMachine" /></div>
|
<div class="body svg-wrap"><StateMachine :machine="blueprint.stateMachine" /></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ const markers = (Object.keys(SM_COLORS) as (keyof typeof SM_COLORS)[]).map((k) =
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const init = computed(() => {
|
const init = computed(() => {
|
||||||
const loading = byId.value.loading
|
const start = byId.value[props.machine.initId ?? "loading"]
|
||||||
const cy = loading.y + loading.h / 2
|
const cy = start.y + start.h / 2
|
||||||
const e = edgePoint(loading, 26, cy)
|
const e = edgePoint(start, 26, cy)
|
||||||
return { cy, path: `M31 ${cy} L ${e[0]} ${e[1]}` }
|
return { cy, path: `M31 ${cy} L ${e[0]} ${e[1]}` }
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -81,8 +81,27 @@ const KIND_LABELS: Record<SmKind, string> = {
|
|||||||
loadMore: "loadMore()",
|
loadMore: "loadMore()",
|
||||||
navigate: "navigate(δ)",
|
navigate: "navigate(δ)",
|
||||||
changeScope: "changeScope(s)",
|
changeScope: "changeScope(s)",
|
||||||
|
persist: "startPersist()",
|
||||||
|
store: "tokenStored(t)",
|
||||||
|
storeFail: "storeFailed()",
|
||||||
|
revoke: "revoke()",
|
||||||
|
expire: "expired()",
|
||||||
|
clear: "clear()",
|
||||||
}
|
}
|
||||||
const KIND_ORDER: SmKind[] = ["succeed", "fail", "refresh", "loadMore", "navigate", "changeScope"]
|
const KIND_ORDER: SmKind[] = [
|
||||||
|
"succeed",
|
||||||
|
"fail",
|
||||||
|
"refresh",
|
||||||
|
"loadMore",
|
||||||
|
"navigate",
|
||||||
|
"changeScope",
|
||||||
|
"persist",
|
||||||
|
"store",
|
||||||
|
"storeFail",
|
||||||
|
"revoke",
|
||||||
|
"expire",
|
||||||
|
"clear",
|
||||||
|
]
|
||||||
|
|
||||||
const legendItems = computed(() => {
|
const legendItems = computed(() => {
|
||||||
const present = new Set(props.machine.edges.map((e) => e.kind))
|
const present = new Set(props.machine.edges.map((e) => e.kind))
|
||||||
|
|||||||
@@ -58,7 +58,20 @@ export interface SmNode {
|
|||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SmKind = "succeed" | "fail" | "refresh" | "loadMore" | "navigate" | "changeScope"
|
export type SmKind =
|
||||||
|
| "succeed"
|
||||||
|
| "fail"
|
||||||
|
| "refresh"
|
||||||
|
| "loadMore"
|
||||||
|
| "navigate"
|
||||||
|
| "changeScope"
|
||||||
|
// RememberMe persistence lifecycle
|
||||||
|
| "persist"
|
||||||
|
| "store"
|
||||||
|
| "storeFail"
|
||||||
|
| "revoke"
|
||||||
|
| "expire"
|
||||||
|
| "clear"
|
||||||
|
|
||||||
export interface SmEdge {
|
export interface SmEdge {
|
||||||
from: string
|
from: string
|
||||||
@@ -71,6 +84,13 @@ export interface SmEdge {
|
|||||||
export interface StateMachine {
|
export interface StateMachine {
|
||||||
nodes: SmNode[]
|
nodes: SmNode[]
|
||||||
edges: SmEdge[]
|
edges: SmEdge[]
|
||||||
|
// id of the initial state (the [*] arrow points here). Defaults to "loading"
|
||||||
|
// for the LoadState-based machines; RememberMe starts at "notpersisted".
|
||||||
|
initId?: string
|
||||||
|
// Panel caption + field label shown above the diagram. Default to the
|
||||||
|
// composed-LoadState wording; capabilities with their own lifecycle override.
|
||||||
|
caption?: string
|
||||||
|
field?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SM_COLORS: Record<SmKind | "init", string> = {
|
export const SM_COLORS: Record<SmKind | "init", string> = {
|
||||||
@@ -80,6 +100,13 @@ export const SM_COLORS: Record<SmKind | "init", string> = {
|
|||||||
loadMore: "#8fd0ff",
|
loadMore: "#8fd0ff",
|
||||||
navigate: "#b79cff",
|
navigate: "#b79cff",
|
||||||
changeScope: "#67d0c0",
|
changeScope: "#67d0c0",
|
||||||
|
// RememberMe: green mint / red store-fail / magenta revoke / amber expiry / purple reset
|
||||||
|
persist: "#8fd0ff",
|
||||||
|
store: "#7fdca0",
|
||||||
|
storeFail: "#ff8f8f",
|
||||||
|
revoke: "#ff5c8a",
|
||||||
|
expire: "#ffb84d",
|
||||||
|
clear: "#b79cff",
|
||||||
init: "#4f7099",
|
init: "#4f7099",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user