Skip to content

Instantly share code, notes, and snippets.

@mkarajohn
Last active April 3, 2020 02:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkarajohn/055f79a01af232ffd2a29d1af59d236b to your computer and use it in GitHub Desktop.
Save mkarajohn/055f79a01af232ffd2a29d1af59d236b to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
const fileMachine = Machine(
{
id: 'file',
initial: 'idle',
context: null,
states: {
idle: {
on: {
START: 'pending',
},
},
pending: {
invoke: {
id: 'upload',
src: 'upload',
},
on: {
RESOLVED: 'success',
REJECTED: 'failed',
CANCEL: 'cancelled',
},
},
success: {
type: 'final',
entry: [
() => {
console.log('%centering file success state', 'color: green');
},
sendParent('FILE.UPLOADED'),
],
},
failed: {
type: 'final',
entry: [
() => {
console.log('%centering file failed state', 'color: red');
},
sendParent('FILE.FAILED'),
],
},
cancelled: {
type: 'final',
entry: [
() => {
console.log('%centering file cancelled state', 'color: orange');
},
sendParent('FILE.CANCELLED'),
],
},
},
},
{
services: {
upload: (__context, event) => {
return callback => {
let cancelRequest;
let settled;
const req = new Promise((resolve, reject) => {
cancelRequest = reject;
console.log('Started uploading', event);
return setTimeout(() => {
const cond = Math.random() > 0.5;
if (cond) {
resolve();
} else {
reject();
}
}, Math.random() * 5000);
});
req
.then(() => {
settled = true;
console.log('%cFile uploaded successfully', 'color: green');
callback('RESOLVED');
})
.catch(() => {
settled = true;
console.log('%cFile failed to upload', 'color: red');
callback('REJECTED');
});
return () => {
if (!settled) {
console.log('canceling request');
cancelRequest();
}
};
};
},
},
}
);
const uploadSystemMachine = Machine(
{
id: 'upload-system',
initial: 'idle',
context: {
files: [],
successes: 0,
failures: 0,
cancellations: 0,
},
states: {
idle: {
entry: ['clearSpawnedActors', 'resetContext'],
on: {
OPEN: 'active',
},
},
active: {
initial: 'waitingForFiles',
states: {
waitingForFiles: {
on: {
CLOSE: {
target: '#upload-system.idle',
},
ADD: {
actions: 'addFile',
},
UPLOAD: {
target: 'pending',
cond: 'hasFiles',
},
},
},
pending: {
entry: 'startFileUploads',
on: {
'FILE.UPLOADED': {
actions: 'incrementSuccesses',
},
'FILE.FAILED': {
actions: 'incrementFailures',
},
'FILE.CANCELLED': {
actions: 'incrementCancellations',
},
CANCEL: {
actions: 'cancelFileUpload',
},
'': {
target: 'completed',
cond: 'allSettled',
},
},
},
completed: {
type: 'final',
on: {
CLOSE: '#upload-system.idle',
},
},
},
},
},
on: {
KILL: '.idle',
},
},
{
guards: {
hasFiles: context => {
return context.files.length > 0;
},
hasNoFiles: context => {
return context.files.length === 0;
},
allSettled: context => {
return (
context.files.length === context.successes + context.failures + context.cancellations
);
},
},
actions: {
startFileUploads: context => {
context.files.forEach(actor => {
actor.send('START');
});
},
addFile: assign({
files: (context, event) => {
const newValue = spawn(
fileMachine.withContext(event.target ? event.target.data : {}),
context.files.length
);
return [...context.files, newValue];
},
}),
removeFile: assign({
files: (context, event) => {
return context.files.filter(file => {
if (file.id === event.target.id) {
file.stop();
return false;
}
return true;
});
},
}),
resetContext: assign({
files: context => {
context.files.forEach(actor => {
console.log(actor);
actor.stop();
});
return [];
},
successes: 0,
failures: 0,
cancellations: 0,
}),
cancelFileUpload: (context, event) => {
const fileID = event.data.id;
for (let i = 0; i < context.files.length; i++) {
if (context.files[i].id === fileID) {
context.files[i].send('CANCEL');
break;
}
}
},
incrementSuccesses: assign({
successes: context => {
return context.successes + 1;
},
}),
incrementFailures: assign({
failures: context => {
return context.failures + 1;
},
}),
incrementCancellations: assign({
cancellations: context => {
return context.cancellations + 1;
},
}),
},
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment