Last active
July 20, 2022 19:49
-
-
Save hnordt/aa62a863e07ae050806ddc6372379f17 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Machine({ | |
id: "widget", | |
context: { | |
id: null, | |
settings: { | |
name: null, | |
refreshInterval: 30, | |
waitDelay: 5, // TODO: make editable | |
dataSource: null, | |
series: null, | |
timeframe: null, | |
interval: null, | |
visualizationType: null, | |
legendPosition: null, | |
defaultName: "Untitled", | |
defaultRefreshInterval: 30, | |
defaultSeries: {}, | |
defaultTimeframe: "today", | |
defaultIntervalByTimeframe: { | |
today: "15m", | |
yesterday: "15m", | |
thisWeek: "1d", | |
thisMonth: "1d", | |
last7Days: "1d", | |
last30Days: "1d", | |
last60Days: "1d" | |
}, | |
defaultVisualizationType: "barChart", | |
defaultLegendPosition: "bottom", | |
enableIntervalFor: ["thisWeek"], | |
enableLegendFor: ["pieChart"] | |
}, | |
data: [], | |
error: null, | |
nextRefresh: 0 | |
}, | |
initial: "initializing", | |
states: { | |
initializing: { | |
entry: "initializeSettings", | |
on: { | |
"": "ready" | |
} | |
}, | |
ready: { | |
type: "parallel", | |
states: { | |
settings: { | |
type: "parallel", | |
states: { | |
general: { | |
entry: ["resetName", "resetRefreshInterval"], | |
on: { | |
CHANGE_NAME: { | |
actions: "updateName" | |
}, | |
CHANGE_REFRESH_INTERVAL: { | |
actions: "updateRefreshInterval" | |
}, | |
BLUR_NAME: { | |
actions: "resetName" | |
} | |
} | |
}, | |
dataSource: { | |
initial: "empty", | |
states: { | |
empty: { | |
on: { | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// CHANGE_DATA_SOURCE: "selected" | |
CHANGE_DATA_SOURCE: { | |
target: "selected", | |
actions: "updateDataSource" | |
} | |
} | |
}, | |
selected: { | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// entry: "updateDataSource", | |
exit: "cleanupDataSource", | |
type: "parallel", | |
states: { | |
series: { | |
exit: "cleanupSeries", | |
initial: "pristine", | |
states: { | |
pristine: { | |
entry: "resetSeries" | |
}, | |
dirty: { | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// entry: "toggleSerie" | |
} | |
}, | |
on: { | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// TOGGLE_SERIE: "series.dirty" | |
TOGGLE_SERIE: { | |
target: ".dirty", | |
actions: "toggleSerie" | |
} | |
} | |
}, | |
timeframe: { | |
exit: "cleanupTimeframe", | |
initial: "pristine", | |
states: { | |
pristine: { | |
entry: "resetTimeframe" | |
}, | |
dirty: { | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// entry: "updateTimeframe" | |
} | |
}, | |
on: { | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// CHANGE_TIMEFRAME: "timeframe.dirty" | |
CHANGE_TIMEFRAME: { | |
target: ".dirty", | |
actions: "updateTimeframe" | |
} | |
} | |
}, | |
interval: { | |
exit: "cleanupInterval", | |
initial: "init", | |
states: { | |
init: { | |
on: { | |
"": [ | |
{ | |
target: "pristine", | |
cond: "canChangeInterval" | |
}, | |
{ | |
target: "disabled" | |
} | |
] | |
} | |
}, | |
disabled: { | |
entry: "resetInterval" | |
}, | |
pristine: { | |
entry: "resetInterval" | |
}, | |
dirty: { | |
// entry: "updateInterval" | |
} | |
}, | |
on: { | |
CHANGE_TIMEFRAME: ".init", | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// CHANGE_INTERVAL: "interval.dirty" | |
CHANGE_INTERVAL: { | |
target: ".dirty", | |
actions: "updateInterval" | |
} | |
} | |
}, | |
visualizationType: { | |
exit: "cleanupVisualizationType", | |
initial: "pristine", | |
states: { | |
pristine: { | |
entry: "resetVisualizationType" | |
}, | |
dirty: { | |
// entry: "updateVisualizationType" | |
} | |
}, | |
on: { | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// CHANGE_VISUALIZATION_TYPE: "visualizationType.dirty" | |
CHANGE_VISUALIZATION_TYPE: { | |
target: ".dirty", | |
actions: "updateVisualizationType" | |
} | |
} | |
}, | |
legendPosition: { | |
exit: "cleanupLegendPosition", | |
initial: "init", | |
states: { | |
init: { | |
on: { | |
"": [ | |
{ | |
target: "pristine", | |
cond: "canChangeLegendPosition" | |
}, | |
{ | |
target: "hidden" | |
} | |
] | |
} | |
}, | |
hidden: { | |
entry: "cleanupLegendPosition" | |
}, | |
pristine: { | |
entry: "resetLegendPosition" | |
}, | |
dirty: { | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// entry: "updateLegendPosition" | |
} | |
}, | |
on: { | |
CHANGE_VISUALIZATION_TYPE: ".init", | |
// FIXME: https://github.com/davidkpiano/xstate/issues/673 | |
// CHANGE_LEGEND_POSITION: "legendPosition.dirty" | |
CHANGE_LEGEND_POSITION: { | |
target: ".dirty", | |
actions: "updateLegendPosition" | |
} | |
} | |
} | |
}, | |
on: { | |
CHANGE_DATA_SOURCE: { | |
actions: "updateDataSource" | |
}, | |
CLEANUP_DATA_SOURCE: "empty" | |
} | |
} | |
} | |
} | |
} | |
}, | |
data: { | |
initial: "loading", | |
states: { | |
loading: { | |
invoke: { | |
src: "getData", | |
onDone: "success", | |
onError: "failure" | |
} | |
}, | |
success: { | |
invoke: { | |
src: "tick" | |
}, | |
initial: "wait", | |
states: { | |
wait: { | |
entry: ["setData", "resetNextRefresh"], | |
after: { | |
WAIT_DELAY: "idle" | |
}, | |
initial: "waiting", | |
states: { | |
waiting: { | |
on: { | |
REFRESH: "blocked" | |
} | |
}, | |
blocked: { | |
after: { | |
2000: "waiting" | |
}, | |
on: { | |
REFRESH: "blocked" | |
} | |
} | |
} | |
}, | |
idle: { | |
after: { | |
REFRESH_DELAY: "refreshing" | |
}, | |
on: { | |
REFRESH: "refreshing" | |
} | |
}, | |
refreshing: { | |
invoke: { | |
src: "getData", | |
onDone: "wait", | |
onError: "failure" | |
} | |
}, | |
failure: { | |
on: { | |
RETRY: "refreshing" | |
} | |
} | |
}, | |
on: { | |
TICK: { | |
actions: "updateNextRefresh" | |
} | |
} | |
}, | |
failure: { | |
entry: "setError", | |
exit: "resetError", | |
on: { | |
RETRY: "loading" | |
} | |
} | |
} | |
} | |
} | |
} | |
}, | |
on: { | |
UPDATE_SETTINGS: { | |
target: "ready.data.loading", | |
actions: ["updateSettings", "storeSettings"] | |
}, | |
REMOVE: { | |
actions: "cleanupSettings" | |
} | |
} | |
}, | |
{ | |
guards: { | |
canChangeInterval: ctx => { | |
return ctx.settings.enableIntervalFor.includes(ctx.settings.timeframe) | |
}, | |
canChangeLegendPosition: ctx => { | |
return ctx.settings.enableLegendFor.includes( | |
ctx.settings.visualizationType | |
) | |
} | |
}, | |
delays: { | |
REFRESH_DELAY: ctx => { | |
return (ctx.settings.refreshInterval - ctx.settings.waitDelay) * 1000 | |
}, | |
WAIT_DELAY: ctx => { | |
return ctx.settings.waitDelay * 1000 | |
} | |
}, | |
actions: { | |
initializeSettings: assign({ | |
settings: ctx => { | |
try { | |
return ( | |
JSON.parse(localStorage.getItem(`widget-${ctx.id}`)) || | |
ctx.settings | |
) | |
} catch { | |
return ctx.settings | |
} | |
} | |
}), | |
updateSettings: assign({ | |
settings: (_, e) => e.payload.settings | |
}), | |
storeSettings: ctx => { | |
localStorage.setItem(`widget-${ctx.id}`, JSON.stringify(ctx.settings)) | |
}, | |
cleanupSettings: ctx => { | |
localStorage.removeItem(`widget-${ctx.id}`) | |
}, | |
updateName: assign({ | |
settings: (ctx, e) => ({ | |
...ctx.settings, | |
name: e.payload | |
}) | |
}), | |
updateRefreshInterval: assign({ | |
settings: (ctx, e) => ({ | |
...ctx.settings, | |
refreshInterval: e.payload | |
}) | |
}), | |
updateDataSource: assign({ | |
settings: (ctx, e) => ({ | |
...ctx.settings, | |
dataSource: e.payload | |
}) | |
}), | |
toggleSerie: assign({ | |
settings: (ctx, e) => ({ | |
...ctx.settings, | |
series: { | |
...ctx.series, | |
[e.payload]: !ctx.series[e.payload] | |
} | |
}) | |
}), | |
updateTimeframe: assign({ | |
settings: (ctx, e) => ({ | |
...ctx.settings, | |
timeframe: e.payload | |
}) | |
}), | |
updateInterval: assign({ | |
settings: (ctx, e) => ({ | |
...ctx.settings, | |
interval: e.payload | |
}) | |
}), | |
updateVisualizationType: assign({ | |
settings: (ctx, e) => ({ | |
...ctx.settings, | |
visualizationType: e.payload | |
}) | |
}), | |
updateLegendPosition: assign({ | |
settings: (ctx, e) => ({ | |
...ctx.settings, | |
legendPosition: e.payload | |
}) | |
}), | |
// TODO: rename to ensureName? | |
resetName: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
name: ctx.name || ctx.defaultName | |
}) | |
}), | |
// TODO: rename to ensureRefreshInterval? | |
resetRefreshInterval: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
refreshInterval: ctx.refreshInterval || ctx.defaultRefreshInterval | |
}) | |
}), | |
resetSeries: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
series: ctx.defaultSeries | |
}) | |
}), | |
resetTimeframe: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
timeframe: ctx.defaultTimeframe | |
}) | |
}), | |
resetInterval: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
interval: ctx.defaultIntervalByTimeframe[ctx.timeframe] | |
}) | |
}), | |
resetVisualizationType: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
visualizationType: ctx.defaultVisualizationType | |
}) | |
}), | |
resetLegendPosition: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
legendPosition: ctx.defaultLegendPosition | |
}) | |
}), | |
cleanupDataSource: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
dataSource: null | |
}) | |
}), | |
cleanupSeries: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
series: null | |
}) | |
}), | |
cleanupTimeframe: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
timeframe: null | |
}) | |
}), | |
cleanupInterval: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
interval: null | |
}) | |
}), | |
cleanupVisualizationType: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
visualizationType: null | |
}) | |
}), | |
cleanupLegendPosition: assign({ | |
settings: ctx => ({ | |
...ctx.settings, | |
legendPosition: null | |
}) | |
}), | |
setData: assign({ | |
data: (_, e) => e.data | |
}), | |
setError: assign({ | |
error: (_, e) => e.data | |
}), | |
resetError: assign({ | |
error: null | |
}), | |
updateNextRefresh: assign({ | |
nextRefresh: ctx => ctx.nextRefresh - 1 | |
}), | |
resetNextRefresh: assign({ | |
nextRefresh: ctx => ctx.settings.refreshInterval | |
}) | |
}, | |
services: { | |
tick: () => callback => { | |
let id = setInterval(() => callback("TICK"), 1000) | |
return () => clearInterval(id) | |
}, | |
getData: ctx => new Promise(r => setTimeout(r, 4000)) | |
} | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment