factory_burgers 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/assets/asset-manifest.json +3 -3
- data/lib/assets/index.html +1 -1
- data/lib/assets/static/js/main.056013c5.chunk.js +2 -0
- data/lib/assets/static/js/main.056013c5.chunk.js.map +1 -0
- data/lib/assets/static/js/main.317bde1c.chunk.js +2 -0
- data/lib/assets/static/js/main.317bde1c.chunk.js.map +1 -0
- data/lib/factory_burgers.rb +2 -1
- data/lib/factory_burgers/app.rb +2 -1
- data/lib/factory_burgers/builder.rb +1 -0
- data/lib/factory_burgers/cheating.rb +38 -5
- data/lib/factory_burgers/factory_bot_adapter.rb +4 -2
- data/lib/factory_burgers/introspection.rb +2 -0
- data/lib/factory_burgers/middleware/build.rb +39 -17
- data/lib/factory_burgers/middleware/data.rb +2 -1
- data/lib/factory_burgers/middleware/static.rb +2 -1
- data/lib/factory_burgers/models/factory.rb +3 -0
- data/lib/factory_burgers/models/factory_output.rb +1 -0
- data/lib/factory_burgers/presenter_builder.rb +4 -6
- data/lib/factory_burgers/presenters.rb +6 -2
- data/lib/factory_burgers/presenters/base.rb +4 -0
- data/lib/factory_burgers/sequence_cheater.rb +17 -2
- data/lib/factory_burgers/sequence_injector.rb +15 -2
- data/lib/factory_burgers/version.rb +3 -0
- metadata +35 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 58af4b9f7e01058ecbcc53a746ae65250a933230b9522926f94d84e19e586fc2
|
|
4
|
+
data.tar.gz: bd22e7febdb4674ba7de8b83c3079ab8b9ce7d560dcc98fc966a4785fe969fd8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8073d998380b45bb0cc83ff15f9d5cdab8ae2052dc62ad9b811fcdfa80db03ef368b511c60869c30ca2d5beaae2c876124fbd37357c512495b474171e49860f1
|
|
7
|
+
data.tar.gz: be0fc1eee12919e6ae580da4faba1a4ad7a3fec9ae239919654c5937eb9df86d365a6a6eb9986ab8db8503bb887b2f3098d51522c7a5cc925a46290280ab80fd
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
3
|
"main.css": "./static/css/main.510d0fb6.chunk.css",
|
|
4
|
-
"main.js": "./static/js/main.
|
|
5
|
-
"main.js.map": "./static/js/main.
|
|
4
|
+
"main.js": "./static/js/main.317bde1c.chunk.js",
|
|
5
|
+
"main.js.map": "./static/js/main.317bde1c.chunk.js.map",
|
|
6
6
|
"runtime-main.js": "./static/js/runtime-main.38f920d2.js",
|
|
7
7
|
"runtime-main.js.map": "./static/js/runtime-main.38f920d2.js.map",
|
|
8
8
|
"static/js/2.3ff1dc5f.chunk.js": "./static/js/2.3ff1dc5f.chunk.js",
|
|
@@ -18,6 +18,6 @@
|
|
|
18
18
|
"static/js/runtime-main.38f920d2.js",
|
|
19
19
|
"static/js/2.3ff1dc5f.chunk.js",
|
|
20
20
|
"static/css/main.510d0fb6.chunk.css",
|
|
21
|
-
"static/js/main.
|
|
21
|
+
"static/js/main.317bde1c.chunk.js"
|
|
22
22
|
]
|
|
23
23
|
}
|
data/lib/assets/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="stylesheet" href="./bootstrap.4.0.0.min.css"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><title>React App</title><link href="./static/css/main.510d0fb6.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var c=t[a];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"996d9368"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="./",i.oe=function(e){throw console.error(e),e};var a=this["webpackJsonpfactory_burgers-ui"]=this["webpackJsonpfactory_burgers-ui"]||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([])</script><script src="./static/js/2.3ff1dc5f.chunk.js"></script><script src="./static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="stylesheet" href="./bootstrap.4.0.0.min.css"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><title>React App</title><link href="./static/css/main.510d0fb6.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,i,a=r[0],c=r[1],l=r[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(r);p.length;)p.shift()();return u.push.apply(u,l||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var c=t[a];0!==o[c]&&(n=!1)}n&&(u.splice(r--,1),e=i(i.s=t[0]))}return e}var n={},o={1:0},u=[];function i(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,i),t.l=!0,t.exports}i.e=function(e){var r=[],t=o[e];if(0!==t)if(t)r.push(t[2]);else{var n=new Promise((function(r,n){t=o[e]=[r,n]}));r.push(t[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"996d9368"}[e]+".chunk.js"}(e);var c=new Error;u=function(r){a.onerror=a.onload=null,clearTimeout(l);var t=o[e];if(0!==t){if(t){var n=r&&("load"===r.type?"missing":r.type),u=r&&r.target&&r.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,t[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(r)},i.m=e,i.c=n,i.d=function(e,r,t){i.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,r){if(1&r&&(e=i(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(i.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)i.d(t,n,function(r){return e[r]}.bind(null,n));return t},i.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(r,"a",r),r},i.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},i.p="./",i.oe=function(e){throw console.error(e),e};var a=this["webpackJsonpfactory_burgers-ui"]=this["webpackJsonpfactory_burgers-ui"]||[],c=a.push.bind(a);a.push=r,a=a.slice();for(var l=0;l<a.length;l++)r(a[l]);var f=c;t()}([])</script><script src="./static/js/2.3ff1dc5f.chunk.js"></script><script src="./static/js/main.317bde1c.chunk.js"></script></body></html>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(this["webpackJsonpfactory_burgers-ui"]=this["webpackJsonpfactory_burgers-ui"]||[]).push([[0],{31:function(e,t,n){},32:function(e,t,n){},33:function(e,t,n){},34:function(e,t,n){},42:function(e,t,n){"use strict";n.r(t);var r=n(0),a=n.n(r),c=n(10),i=n.n(c),o=(n(31),n(32),n(33),n(34),n(1));var s=function(){return Object(o.jsx)("div",{children:"86 on that ... something went wrong."})};var u=function(){return Object(o.jsx)("div",{children:"Coming right up..."})},l=n(11),b=n.n(l),j=n(15),d=n(7),f=n(9),h=n(8),m=n.n(h),O=m.a.shape({name:m.a.string.isRequired}),v=m.a.shape({name:m.a.string.isRequired}),p=(m.a.shape({attributes:m.a.arrayOf(O),name:m.a.string.isRequired,traits:m.a.arrayOf(v)}),n(23)),x=n(6),g=n(26),y=n(13);var w=function(e){return Object(o.jsxs)(x.a.Row,{children:[Object(o.jsxs)(y.a,{children:[Object(o.jsx)(x.a.Label,{children:"Attribute Name"}),Object(o.jsxs)(x.a.Control,{as:"select",disabled:e.disabled,name:"attributes[][name]",className:"form-control",value:e.attribute.name,onChange:function(t){return e.onChangeName(t)},children:[Object(o.jsx)("option",{value:e.attribute.name,children:e.attribute.name}),e.children]})]}),Object(o.jsxs)(y.a,{children:[Object(o.jsx)(x.a.Label,{children:"Value"}),Object(o.jsx)("input",{disabled:e.disabled||!e.attribute.name,name:"attributes[][value]",className:"form-control",value:e.attribute.value,onChange:function(t){return e.onChangeValue(t)}})]})]})};var k=function(e){var t=e.attributes,n=Object(r.useState)([]),a=Object(d.a)(n,2),c=a[0],i=a[1],s=Object(r.useMemo)((function(){return function(e,t){var n=new Set(t.map((function(e){return e.name})));return e.filter((function(e){return!n.has(e.name)}))}(t,c)})).map((function(e){return Object(o.jsx)("option",{value:e.name,children:e.name},e.name)}));function u(e){var t=e.name,n=e.value;i([].concat(Object(g.a)(c),[{name:t,value:n}]))}function l(e,t){var n=c.slice();n.splice(e,1,t),i(n)}return Object(o.jsxs)(x.a.Group,{controlId:"factories.Traits",children:[Object(o.jsx)(x.a.Label,{children:"Pickles or onions?"}),c.map((function(t,n){return Object(o.jsx)(w,{attribute:t,disabled:e.disabled,onChangeName:function(e){return function(e,t){l(e,{name:t.target.value,value:c[e].value})}(n,e)},onChangeValue:function(e){return function(e,t){l(e,{name:c[e].name,value:t.target.value})}(n,e)},children:s},n)})),Object(o.jsx)(w,{attribute:{name:"",value:""},disabled:e.disabled,onChangeName:function(e){return u({name:e.target.value,value:""})},onChangeValue:function(e){return u({name:"",value:e.target.value})},children:s},c.length+1)]})};function C(e,t){return t?"".concat(e.association," (").concat(e.factory.name,", ").concat(e.factory.class_name,")"):"".concat(e.factory.name," (").concat(e.factory.class_name,")")}var S=function(e){var t=e.options,n=e.label,r=e.value,a=e.onChange,c=e.owner;return Object(o.jsxs)(x.a.Group,{controlId:"factories.FactorySelect",children:[Object(o.jsx)(x.a.Label,{children:n}),Object(o.jsx)("input",{name:"factory",list:"factories",autoComplete:"off",className:"form-control",value:r,onChange:a}),Object(o.jsx)("datalist",{id:"factories",children:t.map((function(e){return Object(o.jsx)("option",{value:e.factory.name,children:C(e,c)},C(e,c))}))})]})};var N=function(e){var t=e.association,n=e.owner;return Object(o.jsxs)(o.Fragment,{children:[Object(o.jsx)(x.a.Group,{controlId:"factories.OwnerType",children:Object(o.jsx)(x.a.Control,{type:"hidden",value:n&&n.type||"",name:"owner_type"})}),Object(o.jsx)(x.a.Group,{controlId:"factories.OwnerId",children:Object(o.jsx)(x.a.Control,{type:"hidden",value:n&&n.id||"",name:"owner_id"})}),Object(o.jsx)(x.a.Group,{controlId:"factories.OwnerReflection",children:Object(o.jsx)(x.a.Control,{type:"hidden",value:t||"",name:"owner_association"})})]})};var L=f.a.create({traits:{display:"flex",flexDirection:"column",flexWrap:"wrap",maxHeight:"6em"}}),_=function(e){var t=e.traits;return Object(o.jsxs)(x.a.Group,{controlId:"factories.Traits",children:[Object(o.jsx)(x.a.Label,{children:"How would you like that cooked?"}),Object(o.jsx)("div",{className:Object(f.b)(L.traits),children:t.map((function(t){return Object(o.jsx)(x.a.Check,{type:"checkbox",disabled:e.disabled,id:t.name,name:"traits[".concat(t.name),label:t.name},t.name)}))})]})};function M(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}var I=f.a.create({buttons:{display:"flex",justifyContent:"space-between"}}),R=function(e){var t=e.blueprints||[],n=e.owner,a=e.inquiry||"What'll it be?",c=Object(r.useState)(""),i=Object(d.a)(c,2),s=i[0],u=i[1],l=Object(r.useMemo)((function(){return function(e,t){var n={};return e.forEach((function(e){return n[t(e)]=e})),n}(t,(function(e){return e.factory.name}))}),[t]),b=Object(r.useMemo)((function(){return l[s]}),[s]),j=Object(r.useMemo)((function(){return b&&b.factory.attributes||[]}),[b]),h=Object(r.useMemo)((function(){return b&&b.factory.traits||[]}),[b]),m=!!b,O=function(e){var t=Object(r.useRef)();return Object(r.useEffect)((function(){t.current=e})),t.current}(e.owner);Object(r.useEffect)((function(){(function(e,t){var n=e&&e.type,r=e&&e.id,a=t&&t.type,c=t&&t.id;return n===a&&r==c})(e.owner,O)||u("")}),[e.owner]);var v=Object(r.useRef)(null);return Object(o.jsxs)(x.a,{ref:v,onSubmit:e.handleSubmit,children:[Object(o.jsx)(S,{options:t,label:a,value:s,onChange:function(e){var t=e.target.value;u(t)},owner:n}),Object(o.jsx)(N,{owner:n,association:b&&b.association}),h.length>0&&Object(o.jsx)(_,{disabled:e.disabled,traits:h}),j.length>0&&Object(o.jsx)(k,{disabled:e.disabled,attributes:j}),Object(o.jsxs)("div",{className:Object(f.b)(I.buttons),children:[Object(o.jsx)(p.a,{variant:"outline-dark",className:"btn-primary",disabled:e.disabled||!m,type:"submit",children:"Gimme!"}),Object(o.jsx)(p.a,{variant:"outline-dark",className:"btn-danger",disabled:e.disabled,onClick:function(){v.current&&v.current.reset(),u(""),e.startOver()},type:"button",children:"Start Over"})," "]})]})},T=n(25);var F=function(e){var t=e.message||"Something went wrong";return Object(o.jsx)(T.a,{variant:"danger",children:t})};var D=function(){return Object(o.jsx)("svg",{width:"1em",height:"1em",viewBox:"0 0 24 24",children:Object(o.jsxs)("g",{"stroke-width":"2.1",stroke:"#666",fill:"none","stroke-linecap":"round","stroke-linejoin":"round",children:[Object(o.jsx)("polyline",{points:"17 13.5 17 19.5 5 19.5 5 7.5 11 7.5"}),Object(o.jsx)("path",{d:"M14,4.5 L20,4.5 L20,10.5 M20,4.5 L11,13.5"})]})})};var G=f.a.create({active:{boxShadow:"5px 5px 0px #333"},object:{border:"2px solid #222",borderRadius:"1em",display:"flex",flexDirection:"column",padding:"0.5em",marginRight:"0.5em",position:"relative",cursor:"pointer",transition:"background-color 0.2s"},objectDetails:{flex:1,width:"100%"},objectTitle:{flex:0,width:"100%",borderBottom:"2px solid #222",marginBottom:"3px"}}),P=function(e){var t=e.object,n=void 0===t?{}:t,r=n.attributes||{},a=function(e){var t=e.isNew,n=e.isActive;return t?"created":n?"selected":null}({isNew:e.new,isActive:e.active});return Object(o.jsxs)("div",{className:M(Object(f.b)(G.object,e.active&&G.active),a,"background-mayo hoverable"),onClick:e.activate,children:[Object(o.jsxs)("div",{className:Object(f.b)(G.objectTitle),children:[n.type,n.link&&Object(o.jsx)("a",{href:n.link,target:"_blank",rel:"noopener noreferrer",className:"ml-1",children:Object(o.jsx)(D,{})})]}),Object(o.jsx)("div",{className:Object(f.b)(G.objectDetails),children:Object.entries(r).map((function(e){var t=Object(d.a)(e,2),n=t[0],r=t[1];return Object(o.jsx)("div",{children:"".concat(n,": ").concat(r)},n)}))})]})};var B=function(){return Object(o.jsx)("div",{className:"under-construction",children:Object(o.jsx)(P,{object:{type:"building..."}})})};var E=f.a.create({form:{marginBottom:"2em",transition:"opacity 0.5s ease-out",overflow:"hidden"},objectList:{display:"flex",margin:"0.5em 0 1em"}}),q=function(e){var t,n=e.factories,a=Object(r.useState)(!1),c=Object(d.a)(a,2),i=c[0],s=c[1],u=Object(r.useState)(null),l=Object(d.a)(u,2),h=l[0],m=l[1],O=Object(r.useState)(!1),v=Object(d.a)(O,2),p=v[0],x=v[1],g=Object(r.useState)(null),y=Object(d.a)(g,2),w=y[0],k=y[1],C=Object(r.useState)([].concat([])),S=Object(d.a)(C,2),N=S[0],L=S[1],_=Object(r.useState)(null),M=Object(d.a)(_,2),I=M[0],T=M[1],D=n.map((function(e){return{factory:e}})),G=null!==I&&N.length>0&&N[I],q=Object(r.useMemo)((function(){return G&&G.association_factories?G.association_factories.map((function(e){return function(e,t){return{factory:e.find((function(e){return e.name===t.factory_name})),association:t.association_name}}(n,e)})):[]}),[G]),A=G?q:D,J=G?"Would you like fries with that ".concat(G.type,"?"):null;function V(){return(V=Object(j.a)(b.a.mark((function t(n){var r,a,c;return b.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return r=e.submitPath,t.next=3,fetch(r,{method:"POST",body:n});case 3:return a=t.sent,t.next=6,a.json();case 6:c=t.sent,a.ok?H(c):(console.error(JSON.stringify(c)),U(c.error||"Uh oh, something broke."));case 8:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function H(e){e.ok?(console.log(JSON.stringify(e)),function(e){s(!1),m(null),x(!1),L(N.slice().concat([e])),0===N.length&&T(0);k(N.length)}(e.data)):(console.error(e.error),U(e.error||"Uh oh, something went wrong."))}function U(e){s(!1),m(e),x(!1)}return Object(o.jsxs)("div",{className:"container",children:[Object(o.jsx)("h2",{children:"Order Up!"}),(i||N.length>0)&&Object(o.jsxs)(o.Fragment,{children:[i?"Comin' right up!":"Here you go!",N.length>1&&Object(o.jsxs)("span",{children:[" ","P.S. -- select any object to build out its dependencies."]}),Object(o.jsxs)("div",{className:Object(f.b)(E.objectList),children:[N.map((function(e,t){return Object(o.jsx)(P,{object:e,active:I===t,activate:function(){return function(e){k(null),T(e)}(t)},new:w===t},t)})),i&&Object(o.jsx)(B,{})]})]}),h&&Object(o.jsx)(F,{message:h}),Object(o.jsx)("div",{className:Object(f.b)(E.form),children:Object(o.jsx)(R,{owner:G?(t=G,{type:t.type,id:t.attributes.id}):null,blueprints:A,disabled:p,handleSubmit:function(e){var t;e.preventDefault(),s(!0),m(null),x(!0),function(e){V.apply(this,arguments)}((t=e.target,new FormData(t)))},startOver:function(){k(null),k(null),L([]),T(null)},inquiry:J})})]})};function A(){return fetch("./data").then((function(e){return e.json()}))}var J=function(){var e=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=Object(r.useState)(null),a=Object(d.a)(n,2),c=a[0],i=a[1],o=Object(r.useState)(0===t.length),s=Object(d.a)(o,2),u=s[0],l=s[1],f=Object(r.useState)(null),h=Object(d.a)(f,2),m=h[0],O=h[1];function v(){return p.apply(this,arguments)}function p(){return(p=Object(j.a)(b.a.mark((function t(){return b.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.abrupt("return",e());case 1:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function x(){l(!1)}return Object(r.useEffect)((function(){l(!0),v().then(O).catch(i).then(x)}),t),Object(r.useMemo)((function(){return{error:c,fetching:u,response:m}}),[c,u,m])}(A);return Object(r.useEffect)((function(){console.log(e)}),[e]),Object(o.jsxs)("div",{className:"App",children:[Object(o.jsx)("header",{children:Object(o.jsx)("div",{class:"header-text",children:"testing"})}),Object(o.jsxs)("main",{children:[e.fetching&&Object(o.jsx)(u,{}),e.error&&Object(o.jsx)(s,{}),e.response&&Object(o.jsx)(q,{csrfToken:"",submitPath:"./build",factories:e.response})]})]})},V=function(e){e&&e instanceof Function&&n.e(3).then(n.bind(null,44)).then((function(t){var n=t.getCLS,r=t.getFID,a=t.getFCP,c=t.getLCP,i=t.getTTFB;n(e),r(e),a(e),c(e),i(e)}))};i.a.render(Object(o.jsx)(a.a.StrictMode,{children:Object(o.jsx)(J,{})}),document.getElementById("root")),V()}},[[42,1,2]]]);
|
|
2
|
+
//# sourceMappingURL=main.056013c5.chunk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["components/Error.js","components/Fetching.js","lib/shapes.js","components/partials/AttributeRow.js","components/partials/Attributes.js","components/partials/FactorySelection.js","components/partials/FormFieldsForOwner.js","components/partials/Traits.js","components/framework.js","components/FactoryForm.js","components/FactoryMalfunction.js","components/icons/ExternalLinkIcon.js","components/ObjectCard.js","components/ObjectUnderConstruction.js","components/Factories.js","lib/api.js","App.js","lib/hooks.js","reportWebVitals.js","index.js"],"names":["Error","Fetching","attributesShape","PropTypes","shape","name","string","isRequired","traitsShape","attributes","arrayOf","traits","AttributeRow","props","Form","Row","Col","Label","Control","as","disabled","className","value","attribute","onChange","event","onChangeName","children","onChangeValue","Traits","useState","inputAttributes","setInputAttributes","remainingAttributeOptions","useMemo","a","b","bNames","Set","map","item","filter","has","attrDiff","attr","addAttribute","replaceAttribute","ii","replacement","newAttributes","slice","splice","Group","controlId","target","setAttributeName","setAttributeValue","length","displayName","blueprint","owner","association","factory","class_name","FactorySelection","options","label","list","autoComplete","id","FormFieldsForOwner","type","styles","StyleSheet","create","display","flexDirection","flexWrap","maxHeight","css","trait","Check","classes","classNames","x","join","buttons","justifyContent","FactoryForm","blueprints","inquiry","factoryInput","setFactoryInput","indexedBluePrints","items","func","indexed","forEach","indexBy","selectedBlueprint","validSelection","prevOwner","ref","useRef","useEffect","current","usePrevious","other","ownerType","ownerId","otherOwnerType","otherOwnerId","sameOwner","form","onSubmit","handleSubmit","Attributes","Button","variant","onClick","reset","startOver","FactoryMalfunction","message","Alert","ExternalLinkIcon","width","height","viewBox","stroke-width","stroke","fill","stroke-linecap","stroke-linejoin","points","d","active","boxShadow","object","border","borderRadius","padding","marginRight","position","cursor","transition","objectDetails","flex","objectTitle","borderBottom","marginBottom","ObjectCard","isNew","isActive","animationClass","new","activate","link","href","rel","Object","entries","ObjectUnderConstruction","overflow","objectList","margin","Factories","factories","constructing","setConstructing","error","setError","fetching","setFetching","newObjectIndex","setNewObjectIndex","objects","setObjects","selectedObjectIndex","setSelectedObjectIndex","factoryList","selectedObject","associationFactories","association_factories","find","f","factory_name","association_name","findAssociationFactory","data","url","submitPath","fetch","method","body","response","json","responseData","ok","handleResponseData","console","JSON","stringify","handleSubmitError","log","concat","handleObject","selectObject","preventDefault","submit","FormData","index","then","res","App","loadFn","dependencies","setResponse","asyncFetch","done","catch","useRemoteData","api","class","csrfToken","reportWebVitals","onPerfEntry","Function","getCLS","getFID","getFCP","getLCP","getTTFB","ReactDOM","render","StrictMode","document","getElementById"],"mappings":"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","file":"static/js/main.056013c5.chunk.js","sourcesContent":["import React from \"react\";\n\nfunction Error() {\n return (\n <div>86 on that ... something went wrong.</div>\n );\n}\n\nexport default Error;\n","import React from \"react\";\n\nfunction Fetching() {\n return (\n <div>Coming right up...</div>\n );\n}\n\nexport default Fetching;\n","import PropTypes from 'prop-types';\n\nconst attributesShape = PropTypes.shape({\n name: PropTypes.string.isRequired,\n});\n\nconst traitsShape = PropTypes.shape({\n name: PropTypes.string.isRequired,\n});\n\nconst factoryShape = PropTypes.shape({\n attributes: PropTypes.arrayOf(attributesShape),\n name: PropTypes.string.isRequired,\n traits: PropTypes.arrayOf(traitsShape),\n});\n\nexport {\n attributesShape,\n factoryShape,\n traitsShape,\n};\n","import React from \"react\";\n\nimport PropTypes from \"prop-types\";\n\nimport Col from \"react-bootstrap/Col\";\nimport Form from \"react-bootstrap/Form\";\n\nfunction AttributeRow(props) {\n return (\n <Form.Row>\n <Col>\n <Form.Label>Attribute Name</Form.Label>\n <Form.Control\n as=\"select\"\n disabled={props.disabled}\n name={`attributes[][name]`}\n className=\"form-control\"\n value={props.attribute.name}\n onChange={event => props.onChangeName(event)}\n >\n <option value={props.attribute.name}>{props.attribute.name}</option>\n {props.children}\n </Form.Control>\n </Col>\n <Col>\n <Form.Label>Value</Form.Label>\n <input\n disabled={props.disabled || !props.attribute.name}\n name={`attributes[][value]`}\n className=\"form-control\"\n value={props.attribute.value}\n onChange={event => props.onChangeValue(event)}\n />\n </Col>\n </Form.Row>\n );\n}\n\nAttributeRow.propTypes = {\n attribute: PropTypes.shape({\n name: PropTypes.string,\n value: PropTypes.string,\n }),\n children: PropTypes.node,\n disabled: PropTypes.bool,\n onChangeName: PropTypes.func.isRequired,\n onChangeValue: PropTypes.func.isRequired,\n};\n\nexport default AttributeRow;\n","import React, { useMemo, useState } from \"react\";\n\nimport PropTypes from \"prop-types\";\n\nimport Form from \"react-bootstrap/Form\";\n\nimport AttributeRow from \"./AttributeRow\";\n\nimport { attributesShape } from \"lib/shapes\";\n\nfunction attrDiff(a, b) {\n const bNames = new Set(b.map(item => item.name));\n return a.filter(item => !bNames.has(item.name));\n}\n\nfunction Traits(props) {\n const { attributes } = props;\n\n const [inputAttributes, setInputAttributes] = useState([]);\n const remainingAttributes = useMemo(() => attrDiff(attributes, inputAttributes));\n\n const remainingAttributeOptions = remainingAttributes.map(attr => (\n <option key={attr.name} value={attr.name}>{attr.name}</option>\n ));\n\n function addAttribute({name, value}) {\n setInputAttributes([...inputAttributes, {name, value}]);\n }\n\n function setAttributeName(ii, event) {\n const replacement = {name: event.target.value, value: inputAttributes[ii].value};\n replaceAttribute(ii, replacement);\n }\n\n function setAttributeValue(ii, event) {\n const replacement = {name: inputAttributes[ii].name, value: event.target.value};\n replaceAttribute(ii, replacement);\n }\n\n function replaceAttribute(ii, replacement) {\n const newAttributes = inputAttributes.slice();\n newAttributes.splice(ii, 1, replacement);\n setInputAttributes(newAttributes);\n }\n\n return (\n <Form.Group controlId=\"factories.Traits\">\n <Form.Label>Pickles or onions?</Form.Label>\n\n {inputAttributes.map((attr, ii) => (\n <AttributeRow\n key={ii}\n attribute={attr}\n disabled={props.disabled}\n onChangeName={event => setAttributeName(ii, event)}\n onChangeValue={event => setAttributeValue(ii, event)}\n >\n {remainingAttributeOptions}\n </AttributeRow>\n ))}\n\n <AttributeRow\n key={inputAttributes.length + 1}\n attribute={{name: \"\", value: \"\"}}\n disabled={props.disabled}\n onChangeName={event => addAttribute({name: event.target.value, value: \"\"})}\n onChangeValue={event => addAttribute({name: \"\", value: event.target.value})}\n >\n {remainingAttributeOptions}\n </AttributeRow>\n\n </Form.Group>\n );\n}\n\nTraits.propTypes = {\n disabled: PropTypes.bool,\n attributes: PropTypes.arrayOf(attributesShape).isRequired,\n};\n\nexport default Traits;\n","import React from \"react\";\n\nimport PropTypes from \"prop-types\";\n\nimport Form from \"react-bootstrap/Form\";\n\nimport { factoryShape } from \"lib/shapes\";\n\nfunction displayName(blueprint, owner) {\n if (owner) {\n return `${blueprint.association} (${blueprint.factory.name}, ${blueprint.factory.class_name})`;\n } else {\n return `${blueprint.factory.name} (${blueprint.factory.class_name})` ;\n }\n}\n\nfunction FactorySelection(props) {\n const { options, label, value, onChange, owner } = props;\n return (\n <Form.Group controlId=\"factories.FactorySelect\">\n <Form.Label>{label}</Form.Label>\n <input\n name=\"factory\"\n list=\"factories\"\n autoComplete=\"off\"\n className=\"form-control\"\n value={value}\n onChange={onChange}\n />\n <datalist id=\"factories\">\n {options.map(blueprint => (\n <option key={displayName(blueprint, owner)} value={blueprint.factory.name}>\n {displayName(blueprint, owner)}\n </option>\n ))}\n </datalist>\n </Form.Group>\n );\n}\n\nFactorySelection.propTypes = {\n options: PropTypes.arrayOf(\n PropTypes.shape({\n factory: factoryShape.isRequired,\n association: PropTypes.string,\n })\n ).isRequired,\n value: PropTypes.string.isRequired,\n onChange: PropTypes.func.isRequired,\n label: PropTypes.string,\n owner: PropTypes.shape({\n type: PropTypes.string,\n id: PropTypes.any,\n }),\n};\n\nexport default FactorySelection;\n","import React from \"react\";\n\nimport PropTypes from 'prop-types';\n\nimport Form from \"react-bootstrap/Form\";\n\nfunction FormFieldsForOwner(props) {\n const { association, owner } = props;\n\n return (\n <>\n <Form.Group controlId=\"factories.OwnerType\">\n <Form.Control\n type=\"hidden\"\n value={owner && owner.type || \"\"}\n name=\"owner_type\"\n />\n </Form.Group>\n <Form.Group controlId=\"factories.OwnerId\">\n <Form.Control\n type=\"hidden\"\n value={owner && owner.id || \"\"}\n name=\"owner_id\"\n />\n </Form.Group>\n <Form.Group controlId=\"factories.OwnerReflection\">\n <Form.Control\n type=\"hidden\"\n value={association || \"\"}\n name=\"owner_association\"\n />\n </Form.Group>\n </>\n );\n}\n\nFormFieldsForOwner.propTypes = {\n association: PropTypes.string,\n owner: PropTypes.shape({\n type: PropTypes.string,\n id: PropTypes.any,\n }),\n};\n\nexport default FormFieldsForOwner;\n","import React from \"react\";\n\nimport { StyleSheet, css } from \"aphrodite\";\nimport PropTypes from \"prop-types\";\n\nimport Form from \"react-bootstrap/Form\";\n\nimport { traitsShape } from \"lib/shapes\";\n\nfunction Traits(props) {\n const { traits } = props;\n\n return (\n <Form.Group controlId=\"factories.Traits\">\n <Form.Label>How would you like that cooked?</Form.Label>\n <div className={css(styles.traits)}>\n {traits.map(trait => (\n <Form.Check\n key={trait.name}\n type=\"checkbox\"\n disabled={props.disabled}\n id={trait.name}\n name={`traits[${trait.name}`}\n label={trait.name}\n />\n ))}\n </div>\n </Form.Group>\n );\n}\n\nTraits.propTypes = {\n disabled: PropTypes.bool,\n traits: PropTypes.arrayOf(traitsShape).isRequired,\n};\n\nconst styles = StyleSheet.create({\n traits: {\n display: \"flex\",\n flexDirection: \"column\",\n flexWrap: \"wrap\",\n maxHeight: \"6em\",\n },\n});\n\nexport default Traits;\n","import { useEffect, useRef } from \"react\";\n\nexport function classes(...classNames) {\n return classNames.filter(x => x).join(\" \");\n}\n\nexport function indexBy(items, func) {\n const indexed = {};\n items.forEach(item => indexed[func(item)] = item);\n return indexed;\n}\n\nexport function usePrevious(value) {\n const ref = useRef();\n useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n}\n","import React, { useEffect, useMemo, useState, useRef } from 'react';\n\nimport { css, StyleSheet } from 'aphrodite';\nimport PropTypes from 'prop-types';\n\nimport Button from \"react-bootstrap/Button\";\nimport Form from \"react-bootstrap/Form\";\n\nimport Attributes from \"./partials/Attributes\";\nimport FactorySelection from \"./partials/FactorySelection\";\nimport FormFieldsForOwner from \"./partials/FormFieldsForOwner\";\nimport Traits from \"./partials/Traits\";\n\nimport { factoryShape } from \"lib/shapes\";\nimport { indexBy, usePrevious } from \"./framework\";\n\nfunction FactoryForm(props) {\n const blueprints = props.blueprints || [];\n const owner = props.owner;\n const inquiry = props.inquiry || \"What'll it be?\";\n\n const [factoryInput, setFactoryInput] = useState(\"\");\n\n function handleFactory(event) {\n const value = event.target.value;\n setFactoryInput(value);\n }\n\n const indexedBluePrints = useMemo(() => indexBy(blueprints, blueprint => blueprint.factory.name), [blueprints]);\n const selectedBlueprint = useMemo(() => indexedBluePrints[factoryInput], [factoryInput]);\n const attributes = useMemo(() => selectedBlueprint && selectedBlueprint.factory.attributes || [], [selectedBlueprint]);\n const traits = useMemo(() => selectedBlueprint && selectedBlueprint.factory.traits || [], [selectedBlueprint]);\n const validSelection = !!selectedBlueprint;\n\n const prevOwner = usePrevious(props.owner);\n\n function sameOwner(owner, other) {\n const ownerType = owner && owner.type;\n const ownerId = owner && owner.id;\n const otherOwnerType = other && other.type;\n const otherOwnerId = other && other.id;\n return ownerType === otherOwnerType && ownerId == otherOwnerId;\n }\n\n useEffect(() => {\n if (!sameOwner(props.owner, prevOwner)) { setFactoryInput(\"\"); }\n }, [props.owner]);\n\n const form = useRef(null);\n\n function startOver() {\n form.current && form.current.reset();\n setFactoryInput(\"\");\n props.startOver();\n }\n\n return (\n <Form ref={form} onSubmit={props.handleSubmit}>\n\n <FactorySelection\n options={blueprints}\n label={inquiry}\n value={factoryInput}\n onChange={handleFactory}\n owner={owner}\n />\n\n <FormFieldsForOwner owner={owner} association={selectedBlueprint && selectedBlueprint.association} />\n\n {traits.length > 0 && (\n <Traits disabled={props.disabled} traits={traits} />\n )}\n\n {attributes.length > 0 && (\n <Attributes disabled={props.disabled} attributes={attributes} />\n )}\n\n <div className={css(styles.buttons)}>\n <Button variant=\"outline-dark\" className=\"btn-primary\" disabled={props.disabled || !validSelection} type=\"submit\">\n Gimme!\n </Button>\n <Button variant=\"outline-dark\" className=\"btn-danger\" disabled={props.disabled} onClick={startOver} type=\"button\">\n Start Over\n </Button>{' '}\n </div>\n </Form>\n );\n}\n\nFactoryForm.propTypes = {\n blueprints: PropTypes.arrayOf(\n PropTypes.shape({\n factory: factoryShape.isRequired,\n association: PropTypes.string,\n })\n ).isRequired,\n disabled: PropTypes.bool,\n handleSubmit: PropTypes.func,\n inquiry: PropTypes.string,\n owner: PropTypes.shape({\n type: PropTypes.string,\n id: PropTypes.any,\n }),\n startOver: PropTypes.func,\n};\n\nconst styles = StyleSheet.create({\n buttons: {\n display: \"flex\",\n justifyContent: \"space-between\",\n },\n});\n\nexport default FactoryForm;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\nimport Alert from \"react-bootstrap/Alert\";\n\nfunction FactoryMalfunction(props) {\n const message = props.message || \"Something went wrong\";\n return (\n <Alert variant=\"danger\">\n {message}\n </Alert>\n );\n}\n\nFactoryMalfunction.propTypes = {\n message: PropTypes.string,\n};\n\nexport default FactoryMalfunction;\n","import React from \"react\";\n\nfunction ExternalLinkIcon() {\n return (\n <svg width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\">\n <g stroke-width=\"2.1\" stroke=\"#666\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"17 13.5 17 19.5 5 19.5 5 7.5 11 7.5\"></polyline>\n <path d=\"M14,4.5 L20,4.5 L20,10.5 M20,4.5 L11,13.5\"></path>\n </g>\n </svg>\n )\n}\n\nexport default ExternalLinkIcon;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\nimport { StyleSheet, css } from \"aphrodite\";\n\nimport ExternalLinkIcon from \"./icons/ExternalLinkIcon\";\n\nimport { classes } from \"./framework\";\n\nfunction animationClass({ isNew, isActive }) {\n if (isNew) {\n return \"created\";\n } else if (isActive) {\n return \"selected\";\n } else {\n return null;\n }\n}\n\nfunction ObjectCard(props) {\n const { object = {} } = props;\n const attributes = object.attributes || {};\n const className = animationClass({isNew: props.new, isActive: props.active});\n return (\n <div className={classes(css(styles.object, props.active && styles.active), className, \"background-mayo hoverable\")} onClick={props.activate}>\n <div className={css(styles.objectTitle)}>\n {object.type}\n {object.link && (\n <a href={object.link} target=\"_blank\" rel=\"noopener noreferrer\" className=\"ml-1\">\n <ExternalLinkIcon />\n </a>\n )}\n </div>\n <div className={css(styles.objectDetails)}>\n {Object.entries(attributes).map(([name, value]) => (\n <div key={name}>\n {`${name}: ${value}`}\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nObjectCard.propTypes = {\n activate: PropTypes.func.isRequired,\n active: PropTypes.bool,\n new: PropTypes.bool,\n object: PropTypes.shape({\n attributes: PropTypes.object.isRequired,\n type: PropTypes.string.isRequired,\n link: PropTypes.string,\n }).isRequired,\n};\n\nconst styles = StyleSheet.create({\n active: {\n boxShadow: \"5px 5px 0px #333\",\n },\n object: {\n border: \"2px solid #222\",\n borderRadius: \"1em\",\n display: \"flex\",\n flexDirection: \"column\",\n padding: \"0.5em\",\n marginRight: \"0.5em\",\n position: \"relative\",\n cursor: \"pointer\",\n transition: \"background-color 0.2s\",\n },\n objectDetails: {\n flex: 1,\n width: \"100%\",\n },\n objectTitle: {\n flex: 0,\n width: \"100%\",\n borderBottom: \"2px solid #222\",\n marginBottom: \"3px\",\n },\n});\n\nexport default ObjectCard;\n","import React from \"react\";\n\nimport ObjectCard from \"./ObjectCard\";\n\nfunction ObjectUnderConstruction() {\n return (\n <div className=\"under-construction\">\n <ObjectCard\n object={{type: \"building...\"}}\n />\n </div>\n );\n}\n\nexport default ObjectUnderConstruction;\n","import React, { useMemo, useState } from 'react';\nimport PropTypes from 'prop-types';\n\nimport { StyleSheet, css } from \"aphrodite\";\n\nimport { factoryShape } from \"lib/shapes\";\n\nimport FactoryForm from \"./FactoryForm\";\nimport FactoryMalfunction from \"./FactoryMalfunction\";\nimport ObjectCard from \"./ObjectCard\";\nimport ObjectUnderConstruction from \"./ObjectUnderConstruction.js\";\n\nfunction findAssociationFactory(factories, association) {\n return {\n factory: factories.find(f => f.name === association.factory_name),\n association: association.association_name,\n };\n}\n\nfunction objectId(object) {\n return {\n type: object.type,\n id: object.attributes.id,\n };\n}\n\nfunction Factories(props) {\n const { factories } = props;\n\n // Just use this for testing objects without having to create them\n // const staticObject = [{type: \"test\", attributes: {id: 1, name: \"first\"}}, {type: \"test\", attributes: {id: 1, name: \"second\"}}];\n const staticObject = [];\n\n const [constructing, setConstructing] = useState(false);\n const [error, setError] = useState(null);\n const [fetching, setFetching] = useState(false);\n const [newObjectIndex, setNewObjectIndex] = useState(null);\n const [objects, setObjects] = useState([...staticObject]);\n const [selectedObjectIndex, setSelectedObjectIndex] = useState(null);\n\n const factoryList = factories.map(factory => ({factory}));\n const selectedObject = selectedObjectIndex !== null && objects.length > 0 && objects[selectedObjectIndex];\n\n const associationFactories = useMemo(() => {\n if (!selectedObject || !selectedObject.association_factories) { return []; }\n const matchingFactories = selectedObject.association_factories.map(\n item => findAssociationFactory(factories, item)\n );\n return matchingFactories;\n }, [selectedObject]);\n\n const blueprints = selectedObject ? associationFactories : factoryList;\n const inquiry = selectedObject ? `Would you like fries with that ${selectedObject.type}?` : null;\n\n function startOver() {\n setNewObjectIndex(null);\n setNewObjectIndex(null);\n setObjects([]);\n setSelectedObjectIndex(null);\n }\n\n function selectObject(ii) {\n setNewObjectIndex(null);\n setSelectedObjectIndex(ii);\n }\n\n function handleSubmit(event) {\n event.preventDefault();\n setConstructing(true);\n setError(null);\n setFetching(true);\n const data = formData(event.target);\n submit(data);\n }\n\n async function submit(data) {\n const url = props.submitPath;\n\n const response = await fetch(url, {\n method: \"POST\",\n body: data,\n });\n\n const responseData = await response.json();\n\n if (!response.ok) {\n // eslint-disable-next-line no-console\n console.error(JSON.stringify(responseData));\n handleSubmitError(responseData.error || \"Uh oh, something broke.\");\n } else {\n handleResponseData(responseData);\n }\n }\n\n function handleResponseData(responseData) {\n if (responseData.ok) {\n // eslint-disable-next-line no-console\n console.log(JSON.stringify(responseData));\n handleObject(responseData.data);\n } else {\n // eslint-disable-next-line no-console\n console.error(responseData.error);\n handleSubmitError(responseData.error || \"Uh oh, something went wrong.\");\n }\n }\n\n function handleSubmitError(message) {\n setConstructing(false);\n setError(message);\n setFetching(false);\n }\n\n function handleObject(object) {\n setConstructing(false);\n setError(null);\n setFetching(false);\n setObjects(objects.slice().concat([object]));\n if (objects.length === 0) {\n setSelectedObjectIndex(0);\n }\n setNewObjectIndex(objects.length);\n }\n\n function formData(form) {\n return new FormData(form);\n }\n\n return (\n <div className=\"container\">\n <h2>Order Up!</h2>\n\n {(constructing || (objects.length > 0)) && (\n <>\n {constructing ? \"Comin' right up!\" : \"Here you go!\"}\n {objects.length > 1 && (\n <span>{\" \"}P.S. -- select any object to build out its dependencies.</span>\n )}\n <div className={css(styles.objectList)}>\n {objects.map((object, ii) => (\n <ObjectCard\n key={ii}\n object={object}\n active={selectedObjectIndex === ii}\n activate={() => selectObject(ii)}\n new={newObjectIndex === ii}\n />\n ))}\n {constructing && <ObjectUnderConstruction />}\n </div>\n </>\n )}\n\n {error && <FactoryMalfunction message={error} />}\n\n <div className={css(styles.form)}>\n <FactoryForm\n owner={selectedObject ? objectId(selectedObject) : null}\n blueprints={blueprints}\n disabled={fetching}\n handleSubmit={handleSubmit}\n startOver={startOver}\n inquiry={inquiry}\n />\n </div>\n </div>\n );\n}\n\nFactories.propTypes = {\n factories: PropTypes.arrayOf(factoryShape),\n submitPath: PropTypes.string,\n};\n\nconst styles = StyleSheet.create({\n form: {\n marginBottom: \"2em\",\n transition: \"opacity 0.5s ease-out\",\n overflow: \"hidden\",\n },\n objectList: {\n display: \"flex\",\n margin: \"0.5em 0 1em\",\n },\n});\n\nexport default Factories;\n","export function index() {\n return fetch(\"./data\")\n .then(res => res.json());\n}\n","import { useEffect } from \"react\";\n\nimport './App.css';\nimport './burgers.css';\nimport './layout.css';\n\nimport Error from \"components/Error\";\nimport Fetching from \"components/Fetching\";\nimport Factories from \"components/Factories\";\n\nimport * as api from \"lib/api\";\nimport { useRemoteData } from \"lib/hooks\";\n\nfunction App() {\n const factories = useRemoteData(api.index);\n\n useEffect(() => { console.log(factories) }, [factories]);\n\n return (\n <div className=\"App\">\n <header>\n <div class=\"header-text\">testing</div>\n </header>\n <main>\n {factories.fetching && <Fetching />}\n {factories.error && <Error />}\n {factories.response && (\n <Factories\n csrfToken=\"\"\n submitPath=\"./build\"\n factories={factories.response}\n />\n )}\n </main>\n </div>\n );\n}\n\nexport default App;\n","// useRemoteData -- fetch remote data with standardized fetching and error states\n//\n// USAGE\n//\n// function fetchMyData() {\n// // ... return your data or a promise for your data ...\n// }\n//\n// const data = useRemoteData(fetchMyData);\n// // -- OR --\n// const data = useRemoteData(fetchMyData, dependencies);\n//\n// Similar to `useEffect`, `dependencies` will trigger the fetch to occur again.\n// `dependencies` defaults to [], meaning the fetch will happen only once.\n\n\nimport { useEffect, useMemo, useState } from \"react\";\nexport function useRemoteData(loadFn, dependencies = []) {\n const [error, setError] = useState(null);\n const [fetching, setFetching] = useState(dependencies.length === 0);\n const [response, setResponse] = useState(null);\n\n useEffect(() => {\n setFetching(true);\n asyncFetch().then(setResponse).catch(setError).then(done);\n }, dependencies);\n\n async function asyncFetch() {\n return loadFn();\n }\n\n function done() {\n setFetching(false);\n }\n\n const value = useMemo(() => {\n return {error, fetching, response};\n }, [error, fetching, response]);\n\n return value;\n}\n","const reportWebVitals = onPerfEntry => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry);\n getFID(onPerfEntry);\n getFCP(onPerfEntry);\n getLCP(onPerfEntry);\n getTTFB(onPerfEntry);\n });\n }\n};\n\nexport default reportWebVitals;\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport reportWebVitals from './reportWebVitals';\n\nReactDOM.render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n document.getElementById('root')\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"],"sourceRoot":""}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(this["webpackJsonpfactory_burgers-ui"]=this["webpackJsonpfactory_burgers-ui"]||[]).push([[0],{31:function(e,t,n){},32:function(e,t,n){},33:function(e,t,n){},34:function(e,t,n){},42:function(e,t,n){"use strict";n.r(t);var r=n(0),a=n.n(r),c=n(10),i=n.n(c),o=(n(31),n(32),n(33),n(34),n(1));var s=function(){return Object(o.jsx)("div",{children:"86 on that ... something went wrong."})};var u=function(){return Object(o.jsx)("div",{children:"Coming right up..."})},l=n(11),b=n.n(l),j=n(15),d=n(7),f=n(9),h=n(8),m=n.n(h),O=m.a.shape({name:m.a.string.isRequired}),v=m.a.shape({name:m.a.string.isRequired}),p=(m.a.shape({attributes:m.a.arrayOf(O),name:m.a.string.isRequired,traits:m.a.arrayOf(v)}),n(23)),x=n(6),g=n(26),y=n(13);var w=function(e){return Object(o.jsxs)(x.a.Row,{children:[Object(o.jsxs)(y.a,{children:[Object(o.jsx)(x.a.Label,{children:"Attribute Name"}),Object(o.jsxs)(x.a.Control,{as:"select",disabled:e.disabled,name:"attributes[][name]",className:"form-control",value:e.attribute.name,onChange:function(t){return e.onChangeName(t)},children:[Object(o.jsx)("option",{value:e.attribute.name,children:e.attribute.name}),e.children]})]}),Object(o.jsxs)(y.a,{children:[Object(o.jsx)(x.a.Label,{children:"Value"}),Object(o.jsx)("input",{disabled:e.disabled||!e.attribute.name,name:"attributes[][value]",className:"form-control",value:e.attribute.value,onChange:function(t){return e.onChangeValue(t)}})]})]})};var k=function(e){var t=e.attributes,n=Object(r.useState)([]),a=Object(d.a)(n,2),c=a[0],i=a[1],s=Object(r.useMemo)((function(){return function(e,t){var n=new Set(t.map((function(e){return e.name})));return e.filter((function(e){return!n.has(e.name)}))}(t,c)}),[t,c]).map((function(e){return Object(o.jsx)("option",{value:e.name,children:e.name},e.name)}));function u(e){var t=e.name,n=e.value;i([].concat(Object(g.a)(c),[{name:t,value:n}]))}function l(e,t){var n=c.slice();n.splice(e,1,t),i(n)}return Object(o.jsxs)(x.a.Group,{controlId:"factories.Traits",children:[Object(o.jsx)(x.a.Label,{children:"Pickles or onions?"}),c.map((function(t,n){return Object(o.jsx)(w,{attribute:t,disabled:e.disabled,onChangeName:function(e){return function(e,t){l(e,{name:t.target.value,value:c[e].value})}(n,e)},onChangeValue:function(e){return function(e,t){l(e,{name:c[e].name,value:t.target.value})}(n,e)},children:s},n)})),Object(o.jsx)(w,{attribute:{name:"",value:""},disabled:e.disabled,onChangeName:function(e){return u({name:e.target.value,value:""})},onChangeValue:function(e){return u({name:"",value:e.target.value})},children:s},c.length+1)]})};function C(e,t){return t?"".concat(e.association," (").concat(e.factory.name,", ").concat(e.factory.class_name,")"):"".concat(e.factory.name," (").concat(e.factory.class_name,")")}var S=function(e){var t=e.options,n=e.label,r=e.value,a=e.onChange,c=e.owner;return Object(o.jsxs)(x.a.Group,{controlId:"factories.FactorySelect",children:[Object(o.jsx)(x.a.Label,{children:n}),Object(o.jsx)("input",{name:"factory",list:"factories",autoComplete:"off",className:"form-control",value:r,onChange:a}),Object(o.jsx)("datalist",{id:"factories",children:t.map((function(e){return Object(o.jsx)("option",{value:e.factory.name,children:C(e,c)},C(e,c))}))})]})};var N=function(e){var t=e.association,n=e.owner;return Object(o.jsxs)(o.Fragment,{children:[Object(o.jsx)(x.a.Group,{controlId:"factories.OwnerType",children:Object(o.jsx)(x.a.Control,{type:"hidden",value:n&&n.type||"",name:"owner_type"})}),Object(o.jsx)(x.a.Group,{controlId:"factories.OwnerId",children:Object(o.jsx)(x.a.Control,{type:"hidden",value:n&&n.id||"",name:"owner_id"})}),Object(o.jsx)(x.a.Group,{controlId:"factories.OwnerReflection",children:Object(o.jsx)(x.a.Control,{type:"hidden",value:t||"",name:"owner_association"})})]})};var L=f.a.create({traits:{display:"flex",flexDirection:"column",flexWrap:"wrap",maxHeight:"6em"}}),_=function(e){var t=e.traits;return Object(o.jsxs)(x.a.Group,{controlId:"factories.Traits",children:[Object(o.jsx)(x.a.Label,{children:"How would you like that cooked?"}),Object(o.jsx)("div",{className:Object(f.b)(L.traits),children:t.map((function(t){return Object(o.jsx)(x.a.Check,{type:"checkbox",disabled:e.disabled,id:t.name,name:"traits[".concat(t.name),label:t.name},t.name)}))})]})};function M(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter((function(e){return e})).join(" ")}var I=f.a.create({buttons:{display:"flex",justifyContent:"space-between"}}),R=function(e){var t=e.owner,n=e.inquiry||"What'll it be?",a=Object(r.useState)(""),c=Object(d.a)(a,2),i=c[0],s=c[1],u=Object(r.useMemo)((function(){return e.blueprints||[]}),[e.blueprints]),l=Object(r.useMemo)((function(){return function(e,t){var n={};return e.forEach((function(e){return n[t(e)]=e})),n}(u,(function(e){return e.factory.name}))}),[u]),b=Object(r.useMemo)((function(){return l[i]}),[i,l]),j=Object(r.useMemo)((function(){return b&&b.factory.attributes||[]}),[b]),h=Object(r.useMemo)((function(){return b&&b.factory.traits||[]}),[b]),m=!!b,O=function(e){var t=Object(r.useRef)();return Object(r.useEffect)((function(){t.current=e})),t.current}(e.owner);Object(r.useEffect)((function(){(function(e,t){var n=e&&e.type,r=e&&e.id,a=t&&t.type,c=t&&t.id;return n===a&&r===c})(e.owner,O)||s("")}),[e.owner,O]);var v=Object(r.useRef)(null);return Object(o.jsxs)(x.a,{ref:v,onSubmit:e.handleSubmit,children:[Object(o.jsx)(S,{options:u,label:n,value:i,onChange:function(e){var t=e.target.value;s(t)},owner:t}),Object(o.jsx)(N,{owner:t,association:b&&b.association}),h.length>0&&Object(o.jsx)(_,{disabled:e.disabled,traits:h}),j.length>0&&Object(o.jsx)(k,{disabled:e.disabled,attributes:j}),Object(o.jsxs)("div",{className:Object(f.b)(I.buttons),children:[Object(o.jsx)(p.a,{variant:"outline-dark",className:"btn-primary",disabled:e.disabled||!m,type:"submit",children:"Gimme!"}),Object(o.jsx)(p.a,{variant:"outline-dark",className:"btn-danger",disabled:e.disabled,onClick:function(){v.current&&v.current.reset(),s(""),e.startOver()},type:"button",children:"Start Over"})," "]})]})},T=n(25);var F=function(e){var t=e.message||"Something went wrong";return Object(o.jsx)(T.a,{variant:"danger",children:t})};var D=function(){return Object(o.jsx)("svg",{width:"1em",height:"1em",viewBox:"0 0 24 24",children:Object(o.jsxs)("g",{"stroke-width":"2.1",stroke:"#666",fill:"none","stroke-linecap":"round","stroke-linejoin":"round",children:[Object(o.jsx)("polyline",{points:"17 13.5 17 19.5 5 19.5 5 7.5 11 7.5"}),Object(o.jsx)("path",{d:"M14,4.5 L20,4.5 L20,10.5 M20,4.5 L11,13.5"})]})})};var G=f.a.create({active:{boxShadow:"5px 5px 0px #333"},object:{border:"2px solid #222",borderRadius:"1em",display:"flex",flexDirection:"column",padding:"0.5em",marginRight:"0.5em",position:"relative",cursor:"pointer",transition:"background-color 0.2s"},objectDetails:{flex:1,width:"100%"},objectTitle:{flex:0,width:"100%",borderBottom:"2px solid #222",marginBottom:"3px"}}),P=function(e){var t=e.object,n=void 0===t?{}:t,r=n.attributes||{},a=function(e){var t=e.isNew,n=e.isActive;return t?"created":n?"selected":null}({isNew:e.new,isActive:e.active});return Object(o.jsxs)("div",{className:M(Object(f.b)(G.object,e.active&&G.active),a,"background-mayo hoverable"),onClick:e.activate,children:[Object(o.jsxs)("div",{className:Object(f.b)(G.objectTitle),children:[n.type,n.link&&Object(o.jsx)("a",{href:n.link,target:"_blank",rel:"noopener noreferrer",className:"ml-1",children:Object(o.jsx)(D,{})})]}),Object(o.jsx)("div",{className:Object(f.b)(G.objectDetails),children:Object.entries(r).map((function(e){var t=Object(d.a)(e,2),n=t[0],r=t[1];return Object(o.jsx)("div",{children:"".concat(n,": ").concat(r)},n)}))})]})};var B=function(){return Object(o.jsx)("div",{className:"under-construction",children:Object(o.jsx)(P,{object:{type:"building..."}})})};var E=f.a.create({form:{marginBottom:"2em",transition:"opacity 0.5s ease-out",overflow:"hidden"},objectList:{display:"flex",margin:"0.5em 0 1em"}}),q=function(e){var t,n=e.factories,a=Object(r.useState)(!1),c=Object(d.a)(a,2),i=c[0],s=c[1],u=Object(r.useState)(null),l=Object(d.a)(u,2),h=l[0],m=l[1],O=Object(r.useState)(!1),v=Object(d.a)(O,2),p=v[0],x=v[1],g=Object(r.useState)(null),y=Object(d.a)(g,2),w=y[0],k=y[1],C=Object(r.useState)([].concat([])),S=Object(d.a)(C,2),N=S[0],L=S[1],_=Object(r.useState)(null),M=Object(d.a)(_,2),I=M[0],T=M[1],D=n.map((function(e){return{factory:e}})),G=null!==I&&N.length>0&&N[I],q=Object(r.useMemo)((function(){return G&&G.association_factories?G.association_factories.map((function(e){return function(e,t){return{factory:e.find((function(e){return e.name===t.factory_name})),association:t.association_name}}(n,e)})):[]}),[n,G]),A=G?q:D,J=G?"Would you like fries with that ".concat(G.type,"?"):null;function V(){return(V=Object(j.a)(b.a.mark((function t(n){var r,a,c;return b.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return r=e.submitPath,t.next=3,fetch(r,{method:"POST",body:n});case 3:return a=t.sent,t.next=6,a.json();case 6:c=t.sent,a.ok?H(c):(console.error(JSON.stringify(c)),U(c.error||"Uh oh, something broke."));case 8:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function H(e){e.ok?(console.log(JSON.stringify(e)),function(e){s(!1),m(null),x(!1),L(N.slice().concat([e])),0===N.length&&T(0);k(N.length)}(e.data)):(console.error(e.error),U(e.error||"Uh oh, something went wrong."))}function U(e){s(!1),m(e),x(!1)}return Object(o.jsxs)("div",{className:"container",children:[Object(o.jsx)("h2",{children:"Order Up!"}),(i||N.length>0)&&Object(o.jsxs)(o.Fragment,{children:[i?"Comin' right up!":"Here you go!",N.length>1&&Object(o.jsxs)("span",{children:[" ","P.S. -- select any object to build out its dependencies."]}),Object(o.jsxs)("div",{className:Object(f.b)(E.objectList),children:[N.map((function(e,t){return Object(o.jsx)(P,{object:e,active:I===t,activate:function(){return function(e){k(null),T(e)}(t)},new:w===t},t)})),i&&Object(o.jsx)(B,{})]})]}),h&&Object(o.jsx)(F,{message:h}),Object(o.jsx)("div",{className:Object(f.b)(E.form),children:Object(o.jsx)(R,{owner:G?(t=G,{type:t.type,id:t.attributes.id}):null,blueprints:A,disabled:p,handleSubmit:function(e){var t;e.preventDefault(),s(!0),m(null),x(!0),function(e){V.apply(this,arguments)}((t=e.target,new FormData(t)))},startOver:function(){k(null),k(null),L([]),T(null)},inquiry:J})})]})};function A(){return fetch("./data").then((function(e){return e.json()}))}var J=function(){var e=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=Object(r.useState)(null),a=Object(d.a)(n,2),c=a[0],i=a[1],o=Object(r.useState)(0===t.length),s=Object(d.a)(o,2),u=s[0],l=s[1],f=Object(r.useState)(null),h=Object(d.a)(f,2),m=h[0],O=h[1];function v(){return p.apply(this,arguments)}function p(){return(p=Object(j.a)(b.a.mark((function t(){return b.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.abrupt("return",e());case 1:case"end":return t.stop()}}),t)})))).apply(this,arguments)}function x(){l(!1)}return Object(r.useEffect)((function(){l(!0),v().then(O).catch(i).then(x)}),t),Object(r.useMemo)((function(){return{error:c,fetching:u,response:m}}),[c,u,m])}(A);return Object(r.useEffect)((function(){console.log(e)}),[e]),Object(o.jsxs)("div",{className:"App",children:[Object(o.jsx)("header",{children:Object(o.jsx)("div",{class:"header-text",children:"testing"})}),Object(o.jsxs)("main",{children:[e.fetching&&Object(o.jsx)(u,{}),e.error&&Object(o.jsx)(s,{}),e.response&&Object(o.jsx)(q,{csrfToken:"",submitPath:"./build",factories:e.response})]})]})},V=function(e){e&&e instanceof Function&&n.e(3).then(n.bind(null,44)).then((function(t){var n=t.getCLS,r=t.getFID,a=t.getFCP,c=t.getLCP,i=t.getTTFB;n(e),r(e),a(e),c(e),i(e)}))};i.a.render(Object(o.jsx)(a.a.StrictMode,{children:Object(o.jsx)(J,{})}),document.getElementById("root")),V()}},[[42,1,2]]]);
|
|
2
|
+
//# sourceMappingURL=main.317bde1c.chunk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["components/Error.js","components/Fetching.js","lib/shapes.js","components/partials/AttributeRow.js","components/partials/Attributes.js","components/partials/FactorySelection.js","components/partials/FormFieldsForOwner.js","components/partials/Traits.js","components/framework.js","components/FactoryForm.js","components/FactoryMalfunction.js","components/icons/ExternalLinkIcon.js","components/ObjectCard.js","components/ObjectUnderConstruction.js","components/Factories.js","lib/api.js","App.js","lib/hooks.js","reportWebVitals.js","index.js"],"names":["Error","Fetching","attributesShape","PropTypes","shape","name","string","isRequired","traitsShape","attributes","arrayOf","traits","AttributeRow","props","Form","Row","Col","Label","Control","as","disabled","className","value","attribute","onChange","event","onChangeName","children","onChangeValue","Traits","useState","inputAttributes","setInputAttributes","remainingAttributeOptions","useMemo","a","b","bNames","Set","map","item","filter","has","attrDiff","attr","addAttribute","replaceAttribute","ii","replacement","newAttributes","slice","splice","Group","controlId","target","setAttributeName","setAttributeValue","length","displayName","blueprint","owner","association","factory","class_name","FactorySelection","options","label","list","autoComplete","id","FormFieldsForOwner","type","styles","StyleSheet","create","display","flexDirection","flexWrap","maxHeight","css","trait","Check","classes","classNames","x","join","buttons","justifyContent","FactoryForm","inquiry","factoryInput","setFactoryInput","blueprints","indexedBluePrints","items","func","indexed","forEach","indexBy","selectedBlueprint","validSelection","prevOwner","ref","useRef","useEffect","current","usePrevious","other","ownerType","ownerId","otherOwnerType","otherOwnerId","sameOwner","form","onSubmit","handleSubmit","Attributes","Button","variant","onClick","reset","startOver","FactoryMalfunction","message","Alert","ExternalLinkIcon","width","height","viewBox","stroke-width","stroke","fill","stroke-linecap","stroke-linejoin","points","d","active","boxShadow","object","border","borderRadius","padding","marginRight","position","cursor","transition","objectDetails","flex","objectTitle","borderBottom","marginBottom","ObjectCard","isNew","isActive","animationClass","new","activate","link","href","rel","Object","entries","ObjectUnderConstruction","overflow","objectList","margin","Factories","factories","constructing","setConstructing","error","setError","fetching","setFetching","newObjectIndex","setNewObjectIndex","objects","setObjects","selectedObjectIndex","setSelectedObjectIndex","factoryList","selectedObject","associationFactories","association_factories","find","f","factory_name","association_name","findAssociationFactory","data","url","submitPath","fetch","method","body","response","json","responseData","ok","handleResponseData","console","JSON","stringify","handleSubmitError","log","concat","handleObject","selectObject","preventDefault","submit","FormData","index","then","res","App","loadFn","dependencies","setResponse","asyncFetch","done","catch","useRemoteData","api","class","csrfToken","reportWebVitals","onPerfEntry","Function","getCLS","getFID","getFCP","getLCP","getTTFB","ReactDOM","render","StrictMode","document","getElementById"],"mappings":"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","file":"static/js/main.317bde1c.chunk.js","sourcesContent":["import React from \"react\";\n\nfunction Error() {\n return (\n <div>86 on that ... something went wrong.</div>\n );\n}\n\nexport default Error;\n","import React from \"react\";\n\nfunction Fetching() {\n return (\n <div>Coming right up...</div>\n );\n}\n\nexport default Fetching;\n","import PropTypes from 'prop-types';\n\nconst attributesShape = PropTypes.shape({\n name: PropTypes.string.isRequired,\n});\n\nconst traitsShape = PropTypes.shape({\n name: PropTypes.string.isRequired,\n});\n\nconst factoryShape = PropTypes.shape({\n attributes: PropTypes.arrayOf(attributesShape),\n name: PropTypes.string.isRequired,\n traits: PropTypes.arrayOf(traitsShape),\n});\n\nexport {\n attributesShape,\n factoryShape,\n traitsShape,\n};\n","import React from \"react\";\n\nimport PropTypes from \"prop-types\";\n\nimport Col from \"react-bootstrap/Col\";\nimport Form from \"react-bootstrap/Form\";\n\nfunction AttributeRow(props) {\n return (\n <Form.Row>\n <Col>\n <Form.Label>Attribute Name</Form.Label>\n <Form.Control\n as=\"select\"\n disabled={props.disabled}\n name={`attributes[][name]`}\n className=\"form-control\"\n value={props.attribute.name}\n onChange={event => props.onChangeName(event)}\n >\n <option value={props.attribute.name}>{props.attribute.name}</option>\n {props.children}\n </Form.Control>\n </Col>\n <Col>\n <Form.Label>Value</Form.Label>\n <input\n disabled={props.disabled || !props.attribute.name}\n name={`attributes[][value]`}\n className=\"form-control\"\n value={props.attribute.value}\n onChange={event => props.onChangeValue(event)}\n />\n </Col>\n </Form.Row>\n );\n}\n\nAttributeRow.propTypes = {\n attribute: PropTypes.shape({\n name: PropTypes.string,\n value: PropTypes.string,\n }),\n children: PropTypes.node,\n disabled: PropTypes.bool,\n onChangeName: PropTypes.func.isRequired,\n onChangeValue: PropTypes.func.isRequired,\n};\n\nexport default AttributeRow;\n","import React, { useMemo, useState } from \"react\";\n\nimport PropTypes from \"prop-types\";\n\nimport Form from \"react-bootstrap/Form\";\n\nimport AttributeRow from \"./AttributeRow\";\n\nimport { attributesShape } from \"lib/shapes\";\n\nfunction attrDiff(a, b) {\n const bNames = new Set(b.map(item => item.name));\n return a.filter(item => !bNames.has(item.name));\n}\n\nfunction Traits(props) {\n const { attributes } = props;\n\n const [inputAttributes, setInputAttributes] = useState([]);\n const remainingAttributes = useMemo(() => attrDiff(attributes, inputAttributes), [attributes, inputAttributes]);\n\n const remainingAttributeOptions = remainingAttributes.map(attr => (\n <option key={attr.name} value={attr.name}>{attr.name}</option>\n ));\n\n function addAttribute({name, value}) {\n setInputAttributes([...inputAttributes, {name, value}]);\n }\n\n function setAttributeName(ii, event) {\n const replacement = {name: event.target.value, value: inputAttributes[ii].value};\n replaceAttribute(ii, replacement);\n }\n\n function setAttributeValue(ii, event) {\n const replacement = {name: inputAttributes[ii].name, value: event.target.value};\n replaceAttribute(ii, replacement);\n }\n\n function replaceAttribute(ii, replacement) {\n const newAttributes = inputAttributes.slice();\n newAttributes.splice(ii, 1, replacement);\n setInputAttributes(newAttributes);\n }\n\n return (\n <Form.Group controlId=\"factories.Traits\">\n <Form.Label>Pickles or onions?</Form.Label>\n\n {inputAttributes.map((attr, ii) => (\n <AttributeRow\n key={ii}\n attribute={attr}\n disabled={props.disabled}\n onChangeName={event => setAttributeName(ii, event)}\n onChangeValue={event => setAttributeValue(ii, event)}\n >\n {remainingAttributeOptions}\n </AttributeRow>\n ))}\n\n <AttributeRow\n key={inputAttributes.length + 1}\n attribute={{name: \"\", value: \"\"}}\n disabled={props.disabled}\n onChangeName={event => addAttribute({name: event.target.value, value: \"\"})}\n onChangeValue={event => addAttribute({name: \"\", value: event.target.value})}\n >\n {remainingAttributeOptions}\n </AttributeRow>\n\n </Form.Group>\n );\n}\n\nTraits.propTypes = {\n disabled: PropTypes.bool,\n attributes: PropTypes.arrayOf(attributesShape).isRequired,\n};\n\nexport default Traits;\n","import React from \"react\";\n\nimport PropTypes from \"prop-types\";\n\nimport Form from \"react-bootstrap/Form\";\n\nimport { factoryShape } from \"lib/shapes\";\n\nfunction displayName(blueprint, owner) {\n if (owner) {\n return `${blueprint.association} (${blueprint.factory.name}, ${blueprint.factory.class_name})`;\n } else {\n return `${blueprint.factory.name} (${blueprint.factory.class_name})` ;\n }\n}\n\nfunction FactorySelection(props) {\n const { options, label, value, onChange, owner } = props;\n return (\n <Form.Group controlId=\"factories.FactorySelect\">\n <Form.Label>{label}</Form.Label>\n <input\n name=\"factory\"\n list=\"factories\"\n autoComplete=\"off\"\n className=\"form-control\"\n value={value}\n onChange={onChange}\n />\n <datalist id=\"factories\">\n {options.map(blueprint => (\n <option key={displayName(blueprint, owner)} value={blueprint.factory.name}>\n {displayName(blueprint, owner)}\n </option>\n ))}\n </datalist>\n </Form.Group>\n );\n}\n\nFactorySelection.propTypes = {\n options: PropTypes.arrayOf(\n PropTypes.shape({\n factory: factoryShape.isRequired,\n association: PropTypes.string,\n })\n ).isRequired,\n value: PropTypes.string.isRequired,\n onChange: PropTypes.func.isRequired,\n label: PropTypes.string,\n owner: PropTypes.shape({\n type: PropTypes.string,\n id: PropTypes.any,\n }),\n};\n\nexport default FactorySelection;\n","import React from \"react\";\n\nimport PropTypes from 'prop-types';\n\nimport Form from \"react-bootstrap/Form\";\n\nfunction FormFieldsForOwner(props) {\n const { association, owner } = props;\n\n return (\n <>\n <Form.Group controlId=\"factories.OwnerType\">\n <Form.Control\n type=\"hidden\"\n value={(owner && owner.type) || \"\"}\n name=\"owner_type\"\n />\n </Form.Group>\n <Form.Group controlId=\"factories.OwnerId\">\n <Form.Control\n type=\"hidden\"\n value={(owner && owner.id) || \"\"}\n name=\"owner_id\"\n />\n </Form.Group>\n <Form.Group controlId=\"factories.OwnerReflection\">\n <Form.Control\n type=\"hidden\"\n value={association || \"\"}\n name=\"owner_association\"\n />\n </Form.Group>\n </>\n );\n}\n\nFormFieldsForOwner.propTypes = {\n association: PropTypes.string,\n owner: PropTypes.shape({\n type: PropTypes.string,\n id: PropTypes.any,\n }),\n};\n\nexport default FormFieldsForOwner;\n","import React from \"react\";\n\nimport { StyleSheet, css } from \"aphrodite\";\nimport PropTypes from \"prop-types\";\n\nimport Form from \"react-bootstrap/Form\";\n\nimport { traitsShape } from \"lib/shapes\";\n\nfunction Traits(props) {\n const { traits } = props;\n\n return (\n <Form.Group controlId=\"factories.Traits\">\n <Form.Label>How would you like that cooked?</Form.Label>\n <div className={css(styles.traits)}>\n {traits.map(trait => (\n <Form.Check\n key={trait.name}\n type=\"checkbox\"\n disabled={props.disabled}\n id={trait.name}\n name={`traits[${trait.name}`}\n label={trait.name}\n />\n ))}\n </div>\n </Form.Group>\n );\n}\n\nTraits.propTypes = {\n disabled: PropTypes.bool,\n traits: PropTypes.arrayOf(traitsShape).isRequired,\n};\n\nconst styles = StyleSheet.create({\n traits: {\n display: \"flex\",\n flexDirection: \"column\",\n flexWrap: \"wrap\",\n maxHeight: \"6em\",\n },\n});\n\nexport default Traits;\n","import { useEffect, useRef } from \"react\";\n\nexport function classes(...classNames) {\n return classNames.filter(x => x).join(\" \");\n}\n\nexport function indexBy(items, func) {\n const indexed = {};\n items.forEach(item => indexed[func(item)] = item);\n return indexed;\n}\n\nexport function usePrevious(value) {\n const ref = useRef();\n useEffect(() => {\n ref.current = value;\n });\n return ref.current;\n}\n","import React, { useEffect, useMemo, useState, useRef } from 'react';\n\nimport { css, StyleSheet } from 'aphrodite';\nimport PropTypes from 'prop-types';\n\nimport Button from \"react-bootstrap/Button\";\nimport Form from \"react-bootstrap/Form\";\n\nimport Attributes from \"./partials/Attributes\";\nimport FactorySelection from \"./partials/FactorySelection\";\nimport FormFieldsForOwner from \"./partials/FormFieldsForOwner\";\nimport Traits from \"./partials/Traits\";\n\nimport { factoryShape } from \"lib/shapes\";\nimport { indexBy, usePrevious } from \"./framework\";\n\nfunction FactoryForm(props) {\n const owner = props.owner;\n const inquiry = props.inquiry || \"What'll it be?\";\n\n const [factoryInput, setFactoryInput] = useState(\"\");\n\n function handleFactory(event) {\n const value = event.target.value;\n setFactoryInput(value);\n }\n\n const blueprints = useMemo(() => props.blueprints || [], [props.blueprints]);\n const indexedBluePrints = useMemo(() => indexBy(blueprints, blueprint => blueprint.factory.name), [blueprints]);\n const selectedBlueprint = useMemo(() => indexedBluePrints[factoryInput], [factoryInput, indexedBluePrints]);\n const attributes = useMemo(() => (selectedBlueprint && selectedBlueprint.factory.attributes) || [], [selectedBlueprint]);\n const traits = useMemo(() => (selectedBlueprint && selectedBlueprint.factory.traits) || [], [selectedBlueprint]);\n const validSelection = !!selectedBlueprint;\n\n const prevOwner = usePrevious(props.owner);\n\n function sameOwner(owner, other) {\n const ownerType = owner && owner.type;\n const ownerId = owner && owner.id;\n const otherOwnerType = other && other.type;\n const otherOwnerId = other && other.id;\n return ownerType === otherOwnerType && ownerId === otherOwnerId;\n }\n\n useEffect(() => {\n if (!sameOwner(props.owner, prevOwner)) { setFactoryInput(\"\"); }\n }, [props.owner, prevOwner]);\n\n const form = useRef(null);\n\n function startOver() {\n form.current && form.current.reset();\n setFactoryInput(\"\");\n props.startOver();\n }\n\n return (\n <Form ref={form} onSubmit={props.handleSubmit}>\n\n <FactorySelection\n options={blueprints}\n label={inquiry}\n value={factoryInput}\n onChange={handleFactory}\n owner={owner}\n />\n\n <FormFieldsForOwner owner={owner} association={selectedBlueprint && selectedBlueprint.association} />\n\n {traits.length > 0 && (\n <Traits disabled={props.disabled} traits={traits} />\n )}\n\n {attributes.length > 0 && (\n <Attributes disabled={props.disabled} attributes={attributes} />\n )}\n\n <div className={css(styles.buttons)}>\n <Button variant=\"outline-dark\" className=\"btn-primary\" disabled={props.disabled || !validSelection} type=\"submit\">\n Gimme!\n </Button>\n <Button variant=\"outline-dark\" className=\"btn-danger\" disabled={props.disabled} onClick={startOver} type=\"button\">\n Start Over\n </Button>{' '}\n </div>\n </Form>\n );\n}\n\nFactoryForm.propTypes = {\n blueprints: PropTypes.arrayOf(\n PropTypes.shape({\n factory: factoryShape.isRequired,\n association: PropTypes.string,\n })\n ).isRequired,\n disabled: PropTypes.bool,\n handleSubmit: PropTypes.func,\n inquiry: PropTypes.string,\n owner: PropTypes.shape({\n type: PropTypes.string,\n id: PropTypes.any,\n }),\n startOver: PropTypes.func,\n};\n\nconst styles = StyleSheet.create({\n buttons: {\n display: \"flex\",\n justifyContent: \"space-between\",\n },\n});\n\nexport default FactoryForm;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\nimport Alert from \"react-bootstrap/Alert\";\n\nfunction FactoryMalfunction(props) {\n const message = props.message || \"Something went wrong\";\n return (\n <Alert variant=\"danger\">\n {message}\n </Alert>\n );\n}\n\nFactoryMalfunction.propTypes = {\n message: PropTypes.string,\n};\n\nexport default FactoryMalfunction;\n","import React from \"react\";\n\nfunction ExternalLinkIcon() {\n return (\n <svg width=\"1em\" height=\"1em\" viewBox=\"0 0 24 24\">\n <g stroke-width=\"2.1\" stroke=\"#666\" fill=\"none\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"17 13.5 17 19.5 5 19.5 5 7.5 11 7.5\"></polyline>\n <path d=\"M14,4.5 L20,4.5 L20,10.5 M20,4.5 L11,13.5\"></path>\n </g>\n </svg>\n )\n}\n\nexport default ExternalLinkIcon;\n","import React from \"react\";\nimport PropTypes from \"prop-types\";\n\nimport { StyleSheet, css } from \"aphrodite\";\n\nimport ExternalLinkIcon from \"./icons/ExternalLinkIcon\";\n\nimport { classes } from \"./framework\";\n\nfunction animationClass({ isNew, isActive }) {\n if (isNew) {\n return \"created\";\n } else if (isActive) {\n return \"selected\";\n } else {\n return null;\n }\n}\n\nfunction ObjectCard(props) {\n const { object = {} } = props;\n const attributes = object.attributes || {};\n const className = animationClass({isNew: props.new, isActive: props.active});\n return (\n <div className={classes(css(styles.object, props.active && styles.active), className, \"background-mayo hoverable\")} onClick={props.activate}>\n <div className={css(styles.objectTitle)}>\n {object.type}\n {object.link && (\n <a href={object.link} target=\"_blank\" rel=\"noopener noreferrer\" className=\"ml-1\">\n <ExternalLinkIcon />\n </a>\n )}\n </div>\n <div className={css(styles.objectDetails)}>\n {Object.entries(attributes).map(([name, value]) => (\n <div key={name}>\n {`${name}: ${value}`}\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nObjectCard.propTypes = {\n activate: PropTypes.func.isRequired,\n active: PropTypes.bool,\n new: PropTypes.bool,\n object: PropTypes.shape({\n attributes: PropTypes.object.isRequired,\n type: PropTypes.string.isRequired,\n link: PropTypes.string,\n }).isRequired,\n};\n\nconst styles = StyleSheet.create({\n active: {\n boxShadow: \"5px 5px 0px #333\",\n },\n object: {\n border: \"2px solid #222\",\n borderRadius: \"1em\",\n display: \"flex\",\n flexDirection: \"column\",\n padding: \"0.5em\",\n marginRight: \"0.5em\",\n position: \"relative\",\n cursor: \"pointer\",\n transition: \"background-color 0.2s\",\n },\n objectDetails: {\n flex: 1,\n width: \"100%\",\n },\n objectTitle: {\n flex: 0,\n width: \"100%\",\n borderBottom: \"2px solid #222\",\n marginBottom: \"3px\",\n },\n});\n\nexport default ObjectCard;\n","import React from \"react\";\n\nimport ObjectCard from \"./ObjectCard\";\n\nfunction ObjectUnderConstruction() {\n return (\n <div className=\"under-construction\">\n <ObjectCard\n object={{type: \"building...\"}}\n />\n </div>\n );\n}\n\nexport default ObjectUnderConstruction;\n","import React, { useMemo, useState } from 'react';\nimport PropTypes from 'prop-types';\n\nimport { StyleSheet, css } from \"aphrodite\";\n\nimport { factoryShape } from \"lib/shapes\";\n\nimport FactoryForm from \"./FactoryForm\";\nimport FactoryMalfunction from \"./FactoryMalfunction\";\nimport ObjectCard from \"./ObjectCard\";\nimport ObjectUnderConstruction from \"./ObjectUnderConstruction.js\";\n\nfunction findAssociationFactory(factories, association) {\n return {\n factory: factories.find(f => f.name === association.factory_name),\n association: association.association_name,\n };\n}\n\nfunction objectId(object) {\n return {\n type: object.type,\n id: object.attributes.id,\n };\n}\n\nfunction Factories(props) {\n const { factories } = props;\n\n // Just use this for testing objects without having to create them\n // const staticObject = [{type: \"test\", attributes: {id: 1, name: \"first\"}}, {type: \"test\", attributes: {id: 1, name: \"second\"}}];\n const staticObject = [];\n\n const [constructing, setConstructing] = useState(false);\n const [error, setError] = useState(null);\n const [fetching, setFetching] = useState(false);\n const [newObjectIndex, setNewObjectIndex] = useState(null);\n const [objects, setObjects] = useState([...staticObject]);\n const [selectedObjectIndex, setSelectedObjectIndex] = useState(null);\n\n const factoryList = factories.map(factory => ({factory}));\n const selectedObject = selectedObjectIndex !== null && objects.length > 0 && objects[selectedObjectIndex];\n\n const associationFactories = useMemo(() => {\n if (!selectedObject || !selectedObject.association_factories) { return []; }\n const matchingFactories = selectedObject.association_factories.map(\n item => findAssociationFactory(factories, item)\n );\n return matchingFactories;\n }, [factories, selectedObject]);\n\n const blueprints = selectedObject ? associationFactories : factoryList;\n const inquiry = selectedObject ? `Would you like fries with that ${selectedObject.type}?` : null;\n\n function startOver() {\n setNewObjectIndex(null);\n setNewObjectIndex(null);\n setObjects([]);\n setSelectedObjectIndex(null);\n }\n\n function selectObject(ii) {\n setNewObjectIndex(null);\n setSelectedObjectIndex(ii);\n }\n\n function handleSubmit(event) {\n event.preventDefault();\n setConstructing(true);\n setError(null);\n setFetching(true);\n const data = formData(event.target);\n submit(data);\n }\n\n async function submit(data) {\n const url = props.submitPath;\n\n const response = await fetch(url, {\n method: \"POST\",\n body: data,\n });\n\n const responseData = await response.json();\n\n if (!response.ok) {\n // eslint-disable-next-line no-console\n console.error(JSON.stringify(responseData));\n handleSubmitError(responseData.error || \"Uh oh, something broke.\");\n } else {\n handleResponseData(responseData);\n }\n }\n\n function handleResponseData(responseData) {\n if (responseData.ok) {\n // eslint-disable-next-line no-console\n console.log(JSON.stringify(responseData));\n handleObject(responseData.data);\n } else {\n // eslint-disable-next-line no-console\n console.error(responseData.error);\n handleSubmitError(responseData.error || \"Uh oh, something went wrong.\");\n }\n }\n\n function handleSubmitError(message) {\n setConstructing(false);\n setError(message);\n setFetching(false);\n }\n\n function handleObject(object) {\n setConstructing(false);\n setError(null);\n setFetching(false);\n setObjects(objects.slice().concat([object]));\n if (objects.length === 0) {\n setSelectedObjectIndex(0);\n }\n setNewObjectIndex(objects.length);\n }\n\n function formData(form) {\n return new FormData(form);\n }\n\n return (\n <div className=\"container\">\n <h2>Order Up!</h2>\n\n {(constructing || (objects.length > 0)) && (\n <>\n {constructing ? \"Comin' right up!\" : \"Here you go!\"}\n {objects.length > 1 && (\n <span>{\" \"}P.S. -- select any object to build out its dependencies.</span>\n )}\n <div className={css(styles.objectList)}>\n {objects.map((object, ii) => (\n <ObjectCard\n key={ii}\n object={object}\n active={selectedObjectIndex === ii}\n activate={() => selectObject(ii)}\n new={newObjectIndex === ii}\n />\n ))}\n {constructing && <ObjectUnderConstruction />}\n </div>\n </>\n )}\n\n {error && <FactoryMalfunction message={error} />}\n\n <div className={css(styles.form)}>\n <FactoryForm\n owner={selectedObject ? objectId(selectedObject) : null}\n blueprints={blueprints}\n disabled={fetching}\n handleSubmit={handleSubmit}\n startOver={startOver}\n inquiry={inquiry}\n />\n </div>\n </div>\n );\n}\n\nFactories.propTypes = {\n factories: PropTypes.arrayOf(factoryShape),\n submitPath: PropTypes.string,\n};\n\nconst styles = StyleSheet.create({\n form: {\n marginBottom: \"2em\",\n transition: \"opacity 0.5s ease-out\",\n overflow: \"hidden\",\n },\n objectList: {\n display: \"flex\",\n margin: \"0.5em 0 1em\",\n },\n});\n\nexport default Factories;\n","export function index() {\n return fetch(\"./data\")\n .then(res => res.json());\n}\n","import { useEffect } from \"react\";\n\nimport './App.css';\nimport './burgers.css';\nimport './layout.css';\n\nimport Error from \"components/Error\";\nimport Fetching from \"components/Fetching\";\nimport Factories from \"components/Factories\";\n\nimport * as api from \"lib/api\";\nimport { useRemoteData } from \"lib/hooks\";\n\nfunction App() {\n const factories = useRemoteData(api.index);\n\n useEffect(() => { console.log(factories) }, [factories]);\n\n return (\n <div className=\"App\">\n <header>\n <div class=\"header-text\">testing</div>\n </header>\n <main>\n {factories.fetching && <Fetching />}\n {factories.error && <Error />}\n {factories.response && (\n <Factories\n csrfToken=\"\"\n submitPath=\"./build\"\n factories={factories.response}\n />\n )}\n </main>\n </div>\n );\n}\n\nexport default App;\n","// useRemoteData -- fetch remote data with standardized fetching and error states\n//\n// USAGE\n//\n// function fetchMyData() {\n// // ... return your data or a promise for your data ...\n// }\n//\n// const data = useRemoteData(fetchMyData);\n// // -- OR --\n// const data = useRemoteData(fetchMyData, dependencies);\n//\n// Similar to `useEffect`, `dependencies` will trigger the fetch to occur again.\n// `dependencies` defaults to [], meaning the fetch will happen only once.\n\n\nimport { useEffect, useMemo, useState } from \"react\";\nexport function useRemoteData(loadFn, dependencies = []) {\n const [error, setError] = useState(null);\n const [fetching, setFetching] = useState(dependencies.length === 0);\n const [response, setResponse] = useState(null);\n\n useEffect(() => {\n setFetching(true);\n asyncFetch().then(setResponse).catch(setError).then(done);\n }, dependencies); // eslint-disable-line react-hooks/exhaustive-deps\n\n async function asyncFetch() {\n return loadFn();\n }\n\n function done() {\n setFetching(false);\n }\n\n const value = useMemo(() => {\n return {error, fetching, response};\n }, [error, fetching, response]);\n\n return value;\n}\n","const reportWebVitals = onPerfEntry => {\n if (onPerfEntry && onPerfEntry instanceof Function) {\n import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n getCLS(onPerfEntry);\n getFID(onPerfEntry);\n getFCP(onPerfEntry);\n getLCP(onPerfEntry);\n getTTFB(onPerfEntry);\n });\n }\n};\n\nexport default reportWebVitals;\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport reportWebVitals from './reportWebVitals';\n\nReactDOM.render(\n <React.StrictMode>\n <App />\n </React.StrictMode>,\n document.getElementById('root')\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"],"sourceRoot":""}
|
data/lib/factory_burgers.rb
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
require Pathname(__dir__).join("factory_burgers/init.rb")
|
|
2
2
|
|
|
3
|
-
Dir[Pathname(__dir__).join("factory_burgers/**/*.rb")].each do |file|
|
|
3
|
+
Dir[Pathname(__dir__).join("factory_burgers/**/*.rb")].sort.each do |file|
|
|
4
4
|
require file
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
+
#:nodoc:
|
|
7
8
|
module FactoryBurgers
|
|
8
9
|
class << self
|
|
9
10
|
def root
|
data/lib/factory_burgers/app.rb
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
Dir[Pathname(__dir__).join("middleware/*")].each do |file|
|
|
1
|
+
Dir[Pathname(__dir__).join("middleware/*")].sort.each do |file|
|
|
2
2
|
require file
|
|
3
3
|
end
|
|
4
4
|
|
|
5
5
|
module FactoryBurgers
|
|
6
|
+
# This is the main mounted app, handling all FactoryBugers requests
|
|
6
7
|
App = Rack::Builder.new do
|
|
7
8
|
map "/data" do
|
|
8
9
|
run Middleware::Data.new
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
module FactoryBurgers
|
|
2
|
+
# This module contrains utilities to manipulate sequences that might fail for
|
|
3
|
+
# usage in development environments that do not roll back db transactions for
|
|
4
|
+
# factory creations.
|
|
2
5
|
module Cheating
|
|
3
6
|
module_function
|
|
4
7
|
|
|
8
|
+
# Given a factory, discover what sequences are used in its attributes.
|
|
9
|
+
# Since factories' attributes are defined as blocks, there is no way to know
|
|
10
|
+
# which blocks use sequences without executing the block. We do this with
|
|
11
|
+
# SequenceCheater to take notes without actually using the seqence itself.
|
|
5
12
|
def discover_sequences(factory)
|
|
6
13
|
cheater = SequenceCheater.new
|
|
7
14
|
attributes = factory.definition.attributes
|
|
@@ -12,27 +19,53 @@ module FactoryBurgers
|
|
|
12
19
|
return cheater.sequence_names
|
|
13
20
|
end
|
|
14
21
|
|
|
22
|
+
# Find the highest value of a sequence in the database and advance the
|
|
23
|
+
# sequence past it to avoid uniqueness violations.
|
|
24
|
+
# This is by no means foolproof nor performant; use it with care.
|
|
25
|
+
# There isn't a good way to access the iterator state; instead, we measure
|
|
26
|
+
# how far we must advance the sequence and call `generate` that many times.
|
|
27
|
+
# This works well for sequential iterations, but more complex sequences
|
|
28
|
+
# might break this.
|
|
15
29
|
def advance_sequence(name, klass, column, sql: nil, regex: nil)
|
|
16
30
|
sequence = FactoryBot::Internal.sequences.find(name)
|
|
17
31
|
sql ||= sql_condition(sequence, column)
|
|
18
32
|
regex ||= regex_pattern(sequence)
|
|
19
33
|
|
|
20
|
-
|
|
21
|
-
highest = matches.map { |value| value =~ regex && Regexp.last_match(1) }.map(&:to_i).max
|
|
34
|
+
highest = find_highest_index_value(klass, column, sql, regex) or return nil
|
|
22
35
|
highest&.times { FactoryBot.generate name }
|
|
23
|
-
return FactoryBot.generate(name)
|
|
24
36
|
end
|
|
25
37
|
|
|
38
|
+
def find_highest_index_value(klass, column, sql, regex)
|
|
39
|
+
matches = klass.where(sql).pluck(column).select { |val| val =~ regex }
|
|
40
|
+
return matches.map { |value| value =~ regex && Regexp.last_match(1) }.map(&:to_i).max
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# ---
|
|
44
|
+
# TODO: Use this same principle, but without swallowing `method_missing`, to
|
|
45
|
+
# probe sequences at specific numeric values. This will allow us to determine if
|
|
46
|
+
# a sequence is doing unexpected things like descending, e.g.
|
|
47
|
+
# `sequence :negatives { |ii| -ii }`
|
|
48
|
+
# ---
|
|
49
|
+
|
|
50
|
+
# For a sequence defined with { |ii| "foo#{ii}" }, `sql_condition` returns
|
|
51
|
+
# the SQL fragemnt "<name> like 'foo%'"
|
|
52
|
+
# TODO: does this work in pg, sqlite?
|
|
53
|
+
# TODO: support mongo as well
|
|
26
54
|
def sql_condition(sequence, column)
|
|
55
|
+
# This proc is defined by the block used in the sequence definition
|
|
56
|
+
# This may be fragile, but may also be out only option
|
|
27
57
|
proc = sequence.instance_variable_get(:@proc)
|
|
28
58
|
injector = SequenceInjector.new("%")
|
|
29
59
|
sql_value = proc.call(injector)
|
|
30
60
|
return "#{column} like '#{sql_value}'"
|
|
31
61
|
end
|
|
32
62
|
|
|
33
|
-
|
|
63
|
+
# For a sequence defined with { |ii| "foo#{ii}" }, `sql_condition` returns
|
|
64
|
+
# the regex /foo(\d+)/
|
|
65
|
+
def regex_pattern(sequence, numeric: true)
|
|
66
|
+
wildcard = numeric ? "\\d" : "."
|
|
34
67
|
proc = sequence.instance_variable_get(:@proc)
|
|
35
|
-
injector = SequenceInjector.new("(
|
|
68
|
+
injector = SequenceInjector.new("(#{wildcard}+)")
|
|
36
69
|
return Regexp.new(proc.call(injector))
|
|
37
70
|
end
|
|
38
71
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
module FactoryBurgers
|
|
2
|
+
# Wrap FactoryBot knowledge, eventually switch on version
|
|
2
3
|
module FactoryBotAdapter
|
|
3
4
|
module_function
|
|
4
5
|
|
|
@@ -20,7 +21,7 @@ module FactoryBurgers
|
|
|
20
21
|
|
|
21
22
|
# TODO: support non-v6 versions
|
|
22
23
|
def load_factories
|
|
23
|
-
|
|
24
|
+
FactoryBotAdapter::FactoryBotV6.load_factories
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
def factories
|
|
@@ -33,7 +34,8 @@ module FactoryBurgers
|
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
module FactoryBotAdapter
|
|
36
|
-
|
|
37
|
+
#:nodoc:
|
|
38
|
+
module FactoryBotV6
|
|
37
39
|
module_function
|
|
38
40
|
|
|
39
41
|
def load_factories
|
|
@@ -3,15 +3,11 @@ require "json"
|
|
|
3
3
|
|
|
4
4
|
module FactoryBurgers
|
|
5
5
|
module Middleware
|
|
6
|
+
# Build a requested resource and return data for follow-up actions
|
|
6
7
|
# TODO: extract controller methods into controller-like classes
|
|
7
8
|
class Build
|
|
8
9
|
def call(env)
|
|
9
|
-
|
|
10
|
-
factory = params.fetch("factory")
|
|
11
|
-
traits = params["traits"]&.keys
|
|
12
|
-
attributes = attribute_overrides(params)
|
|
13
|
-
owner = get_resource_owner(params)
|
|
14
|
-
resource = FactoryBurgers::Builder.new.build(factory, traits, attributes, owner)
|
|
10
|
+
resource = build(env)
|
|
15
11
|
object_data = FactoryBurgers::Models::FactoryOutput.new(resource).data
|
|
16
12
|
response_data = {ok: true, data: object_data}
|
|
17
13
|
return [200, {"Content-Type" => "application/json"}, [JSON.dump(response_data)]]
|
|
@@ -23,6 +19,15 @@ module FactoryBurgers
|
|
|
23
19
|
return [500, {"Content-Type" => "application/json"}, [JSON.dump({ok: false, error: err.message})]]
|
|
24
20
|
end
|
|
25
21
|
|
|
22
|
+
def build(env)
|
|
23
|
+
params = paramters(env)
|
|
24
|
+
factory = params.fetch("factory")
|
|
25
|
+
traits = params["traits"]&.keys
|
|
26
|
+
attributes = attribute_overrides(params["attributes"])
|
|
27
|
+
owner = get_resource_owner(params[:owner_type], params[:owner_id], params[:owner_association])
|
|
28
|
+
return FactoryBurgers::Builder.new.build(factory, traits, attributes, owner)
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
def request(env)
|
|
27
32
|
Rack::Request.new(env)
|
|
28
33
|
end
|
|
@@ -31,23 +36,22 @@ module FactoryBurgers
|
|
|
31
36
|
request(env).params
|
|
32
37
|
end
|
|
33
38
|
|
|
34
|
-
def attribute_overrides(
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
def attribute_overrides(attribute_items)
|
|
40
|
+
return [] if attribute_items.nil?
|
|
41
|
+
|
|
42
|
+
attribute_items = attribute_items.select { |attr| attr["name"].present? }
|
|
37
43
|
return attribute_items.map { |attr| [attr["name"], attr["value"]] }.to_h
|
|
38
44
|
end
|
|
39
45
|
|
|
40
46
|
# TODO: make params explicit
|
|
41
|
-
def get_resource_owner(
|
|
42
|
-
return nil if
|
|
43
|
-
|
|
44
|
-
valid_owner_types = ActiveRecord::Base.descendants.map(&:name)
|
|
45
|
-
raise "Danger, will Robinson! #{params[:owner_type]} is an impostor!" if !valid_owner_types.include?(params[:owner_type])
|
|
47
|
+
def get_resource_owner(owner_type, owner_id, owner_association)
|
|
48
|
+
return nil if owner_type.blank? || owner_id.blank? || owner_association.blank?
|
|
46
49
|
|
|
47
|
-
klass =
|
|
48
|
-
|
|
50
|
+
klass = owner_type.constantize
|
|
51
|
+
invalid_build_class(klass) if !valid_build_class?(klass)
|
|
52
|
+
invalid_association(klass) if !valid_owner?(klass, owner_association)
|
|
49
53
|
|
|
50
|
-
return
|
|
54
|
+
return klass.constantize.find(owner_id)
|
|
51
55
|
end
|
|
52
56
|
|
|
53
57
|
def log_error(error)
|
|
@@ -57,6 +61,24 @@ module FactoryBurgers
|
|
|
57
61
|
def logger
|
|
58
62
|
@logger ||= Logger.new($stdout)
|
|
59
63
|
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def valid_build_class?(klass)
|
|
68
|
+
klass < ActiveRecord::Base
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def invalid_build_class(klass)
|
|
72
|
+
raise "#{klass.name} is not a thing I can build."
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def valid_association?(klass, assoc_name)
|
|
76
|
+
klass.reflections.include?(assoc_name)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def invalid_association(klass, association)
|
|
80
|
+
raise "#{association} is not an association for #{klass.name}!"
|
|
81
|
+
end
|
|
60
82
|
end
|
|
61
83
|
end
|
|
62
84
|
end
|
|
@@ -2,8 +2,9 @@ require "json"
|
|
|
2
2
|
|
|
3
3
|
module FactoryBurgers
|
|
4
4
|
module Middleware
|
|
5
|
+
# Respond with factory data to display in the main form
|
|
5
6
|
class Data
|
|
6
|
-
def call(
|
|
7
|
+
def call(*)
|
|
7
8
|
factories = FactoryBot.factories.sort_by(&:name)
|
|
8
9
|
factory_data = factories.map { |factory| factory_data(factory) }
|
|
9
10
|
return [200, {"Content-Type" => "application/json"}, [JSON.dump(factory_data)]]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
module FactoryBurgers
|
|
2
2
|
module Middleware
|
|
3
|
+
# Serve static assets build for the UI
|
|
3
4
|
class Static
|
|
4
5
|
def call(env)
|
|
5
6
|
return slashpath_redirect(env["REQUEST_PATH"]) if slashpath_redirect?(env)
|
|
@@ -14,7 +15,7 @@ module FactoryBurgers
|
|
|
14
15
|
def slashpath_redirect(path)
|
|
15
16
|
return [
|
|
16
17
|
302,
|
|
17
|
-
{'Location' => path
|
|
18
|
+
{'Location' => "#{path}/", 'Content-Type' => 'text/html', 'Content-Length' => '0'},
|
|
18
19
|
[],
|
|
19
20
|
]
|
|
20
21
|
end
|
|
@@ -2,6 +2,7 @@ require "json"
|
|
|
2
2
|
|
|
3
3
|
module FactoryBurgers
|
|
4
4
|
module Models
|
|
5
|
+
# Represent a factory and associated data needed for UI
|
|
5
6
|
# TODO: support transient attributes (f.definition.attributes ...?)
|
|
6
7
|
# TODO: support associations
|
|
7
8
|
class Factory
|
|
@@ -55,6 +56,7 @@ module FactoryBurgers
|
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
|
|
59
|
+
#:nodoc:
|
|
58
60
|
class Attribute
|
|
59
61
|
attr_reader :column
|
|
60
62
|
|
|
@@ -75,6 +77,7 @@ module FactoryBurgers
|
|
|
75
77
|
end
|
|
76
78
|
end
|
|
77
79
|
|
|
80
|
+
#:nodoc:
|
|
78
81
|
class Trait
|
|
79
82
|
attr_reader :trait
|
|
80
83
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
module FactoryBurgers
|
|
2
|
+
# The PresenterBuilder is resposible for building anonymous subclasses of
|
|
3
|
+
# FactoryBurgers::Presenters::Base when FactoryBurgers::Presenters.present is
|
|
4
|
+
# called with a block. The block is evaluated in the context of a
|
|
5
|
+
# FactoryBurgers::PresenterBuilder instance, which understands the DSL.
|
|
2
6
|
class PresenterBuilder < BasicObject
|
|
3
7
|
def initialize(klass)
|
|
4
8
|
@presenter = ::Class.new(::FactoryBurgers::Presenters::Base)
|
|
@@ -20,12 +24,6 @@ module FactoryBurgers
|
|
|
20
24
|
end
|
|
21
25
|
end
|
|
22
26
|
|
|
23
|
-
def type(&blk)
|
|
24
|
-
@presenter.define_method(:type) do
|
|
25
|
-
blk.call(object)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
27
|
def attributes(&blk)
|
|
30
28
|
@presenter.define_method(:attributes) do
|
|
31
29
|
blk.call(object)
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
module FactoryBurgers
|
|
2
|
+
# Module for adding, finding, and using application data presenters. Presenters
|
|
3
|
+
# are used to define what attributes to show in the front end, what to call the
|
|
4
|
+
# built objects, and managing links to the objects in the application if they
|
|
5
|
+
# exist.
|
|
2
6
|
module Presenters
|
|
3
7
|
@presenters = {}
|
|
4
8
|
|
|
@@ -28,12 +32,12 @@ module FactoryBurgers
|
|
|
28
32
|
return matching_class ? @presenters[matching_class] : FactoryBurgers::Presenters::Base
|
|
29
33
|
end
|
|
30
34
|
|
|
31
|
-
# TODO use this from FactoryOutput
|
|
35
|
+
# TODO: use this from FactoryOutput
|
|
32
36
|
def data_for(object)
|
|
33
37
|
presenter = presenter_for(object) or return nil
|
|
34
38
|
{
|
|
35
39
|
type: presenter.type,
|
|
36
|
-
|
|
40
|
+
attributes: presenter.attributes,
|
|
37
41
|
link: presenter.link_path,
|
|
38
42
|
}
|
|
39
43
|
end
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
module FactoryBurgers
|
|
2
2
|
module Presenters
|
|
3
|
+
# Presenter classes are responsible for formatting application object data for
|
|
4
|
+
# the UI. This defatul presenter will display the id and name attributes, if
|
|
5
|
+
# they exist, and does not have an application link. Create subclasses of this
|
|
6
|
+
# class to present different information for different application models.
|
|
3
7
|
class Base
|
|
4
8
|
class << self
|
|
5
9
|
def presents(name)
|
|
@@ -1,4 +1,21 @@
|
|
|
1
1
|
module FactoryBurgers
|
|
2
|
+
# A SequenceCheater is able to take the block associated with a factory's
|
|
3
|
+
# attribute and discover if it uses a sequence (specifically, if it calls
|
|
4
|
+
# `generate`). It does this by evaluting the block in its own context, where
|
|
5
|
+
# the `generate` method has been defined to save the name it was called with.
|
|
6
|
+
#
|
|
7
|
+
# For example, in the following factory:
|
|
8
|
+
#
|
|
9
|
+
# FactoryBot.define do
|
|
10
|
+
# factory :foo do
|
|
11
|
+
# bar { generate :baz }
|
|
12
|
+
# end
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# We can discover the `bar` attribute of the factory, and throgh some slightly
|
|
16
|
+
# dangerous non-public access (it's Ruby, after all) we can get the block
|
|
17
|
+
# defined as `{ generate :baz }`. We then call that block on a SequenceCheater,
|
|
18
|
+
# which simply records that `generate` was called with the name `:baz`.
|
|
2
19
|
class SequenceCheater < BasicObject
|
|
3
20
|
attr_reader :sequence_names
|
|
4
21
|
|
|
@@ -10,13 +27,11 @@ module FactoryBurgers
|
|
|
10
27
|
@sequence_names |= [name] unless name.nil?
|
|
11
28
|
end
|
|
12
29
|
|
|
13
|
-
# rubocop:disable Style/MethodMissingSuper
|
|
14
30
|
# We explicitly want to swallow and do nothing on method_missing;
|
|
15
31
|
# We only want to detect occurences of `generate`.
|
|
16
32
|
def method_missing(_name, *_args)
|
|
17
33
|
# do nothing, do not fail
|
|
18
34
|
end
|
|
19
|
-
# rubocop:enable Style/MethodMissingSuper
|
|
20
35
|
|
|
21
36
|
private
|
|
22
37
|
|
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
module FactoryBurgers
|
|
2
|
+
# A SequenceInjector is a probe that can be used to hijcak a FactoryBot sequence.
|
|
3
|
+
# It injects a specific replacement value in place of the sequence argument, or
|
|
4
|
+
# any usage of that argument.
|
|
5
|
+
#
|
|
6
|
+
# For an injector with a replacement value "foo":
|
|
7
|
+
#
|
|
8
|
+
# * A sequence defined with a block ``{ |ii| "thing-#{ii} "}`
|
|
9
|
+
# will evaluate to "thing-foo".
|
|
10
|
+
# * A sequence defined with a block ``{ |ii| "thing-#{ii.days.from_onw.month} "}`
|
|
11
|
+
# will also evaluate to "thing-foo".
|
|
12
|
+
#
|
|
13
|
+
# This allows us to generate wildcard, such as for SQL
|
|
14
|
+
# SequenceInjector.new("%")
|
|
15
|
+
# or Regex
|
|
16
|
+
# SequenceInjector.new(".")
|
|
2
17
|
class SequenceInjector < BasicObject
|
|
3
18
|
def initialize(replacement_value)
|
|
4
19
|
@replacement_value = replacement_value
|
|
@@ -8,13 +23,11 @@ module FactoryBurgers
|
|
|
8
23
|
@replacement_value
|
|
9
24
|
end
|
|
10
25
|
|
|
11
|
-
# rubocop:disable Style/MethodMissingSuper
|
|
12
26
|
# We explicitly want to swallow and do nothing on method_missing;
|
|
13
27
|
# We want to chain all method calls until we get to to_s
|
|
14
28
|
def method_missing(_name, *_args)
|
|
15
29
|
return self
|
|
16
30
|
end
|
|
17
|
-
# rubocop:enable Style/MethodMissingSuper
|
|
18
31
|
|
|
19
32
|
private
|
|
20
33
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: factory_burgers
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Schwartz
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-05-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: factory_bot
|
|
@@ -80,6 +80,34 @@ dependencies:
|
|
|
80
80
|
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rubocop
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rubocop-rspec
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
83
111
|
- !ruby/object:Gem::Dependency
|
|
84
112
|
name: sqlite3
|
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -154,6 +182,8 @@ files:
|
|
|
154
182
|
- lib/assets/static/js/3.ee90b0ac.chunk.js.map
|
|
155
183
|
- lib/assets/static/js/3.f6dcabfc.chunk.js
|
|
156
184
|
- lib/assets/static/js/3.f6dcabfc.chunk.js.map
|
|
185
|
+
- lib/assets/static/js/main.056013c5.chunk.js
|
|
186
|
+
- lib/assets/static/js/main.056013c5.chunk.js.map
|
|
157
187
|
- lib/assets/static/js/main.06049a6c.chunk.js
|
|
158
188
|
- lib/assets/static/js/main.06049a6c.chunk.js.map
|
|
159
189
|
- lib/assets/static/js/main.0d902f02.chunk.js
|
|
@@ -162,6 +192,8 @@ files:
|
|
|
162
192
|
- lib/assets/static/js/main.1aaab429.chunk.js.map
|
|
163
193
|
- lib/assets/static/js/main.2d0b71bd.chunk.js
|
|
164
194
|
- lib/assets/static/js/main.2d0b71bd.chunk.js.map
|
|
195
|
+
- lib/assets/static/js/main.317bde1c.chunk.js
|
|
196
|
+
- lib/assets/static/js/main.317bde1c.chunk.js.map
|
|
165
197
|
- lib/assets/static/js/main.5b37e0b8.chunk.js
|
|
166
198
|
- lib/assets/static/js/main.5b37e0b8.chunk.js.map
|
|
167
199
|
- lib/assets/static/js/main.6d8f3ae8.chunk.js
|
|
@@ -225,6 +257,7 @@ files:
|
|
|
225
257
|
- lib/factory_burgers/presenters/base.rb
|
|
226
258
|
- lib/factory_burgers/sequence_cheater.rb
|
|
227
259
|
- lib/factory_burgers/sequence_injector.rb
|
|
260
|
+
- lib/factory_burgers/version.rb
|
|
228
261
|
homepage: https://github.com/ozydingo/factory_burgers
|
|
229
262
|
licenses:
|
|
230
263
|
- MIT
|