factory_burgers 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d38bf6e3b7f2fb833beea29b3bd237d990af98e2dfb2ac2d9c14812c49d93a21
4
- data.tar.gz: b33e0e9823962d342a9b1015c1070933a0e13ea684c07e1089d4ecb56a34e61f
3
+ metadata.gz: 58af4b9f7e01058ecbcc53a746ae65250a933230b9522926f94d84e19e586fc2
4
+ data.tar.gz: bd22e7febdb4674ba7de8b83c3079ab8b9ce7d560dcc98fc966a4785fe969fd8
5
5
  SHA512:
6
- metadata.gz: b543e722dd579849580831649e25f20db94afefe0a0c929cea4c999149b4fcb9a8d2b15a421fa4b6fadf630dd721eeb5a71cfc2258b30e3b6c0c9181b14a4f3a
7
- data.tar.gz: da62d0e0fd43225b697294923fbe743b4a23d1a6403766e7ef2ec280cf422acb27585e946e1a4ec566ed147e7ef75b824468c6ea3e387627b9d9e007e32506be
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.06049a6c.chunk.js",
5
- "main.js.map": "./static/js/main.06049a6c.chunk.js.map",
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.06049a6c.chunk.js"
21
+ "static/js/main.317bde1c.chunk.js"
22
22
  ]
23
23
  }
@@ -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.06049a6c.chunk.js"></script></body></html>
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":""}
@@ -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
@@ -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,4 +1,5 @@
1
1
  module FactoryBurgers
2
+ # Build resources from specified factories, traits, and attributes
2
3
  class Builder
3
4
  # TODO: clean up method signature
4
5
  def build(factory, traits, attributes, owner)
@@ -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
- matches = klass.where(sql).pluck(column).select { |val| val =~ regex }
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
- def regex_pattern(sequence)
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("(\\d+)")
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
- FactoryBot::V6.load_factories
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
- module FactoryBot::V6
37
+ #:nodoc:
38
+ module FactoryBotV6
37
39
  module_function
38
40
 
39
41
  def load_factories
@@ -1,4 +1,6 @@
1
1
  module FactoryBurgers
2
+ # Discover information about factories for a class, such as what associations
3
+ # are defined on that class that also have factories we can use
2
4
  module Introspection
3
5
  module_function
4
6
 
@@ -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
- params = paramters(env)
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(params)
35
- attribute_items = params["attributes"] || []
36
- attribute_items = attribute_items.reject{ |attr| !attr["name"].present? }
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(params)
42
- return nil if params[:owner_type].blank? || params[:owner_id].blank? || params[:owner_association].blank?
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 = params[:owner_type].constantize
48
- raise "Danger, will Robinson! #{params[:owner_association]} is an impostor!" if !klass.reflections.include?(params[:owner_association])
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 params[:owner_type].constantize.find(params[:owner_id])
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(env)
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 + "/", 'Content-Type' => 'text/html', 'Content-Length' => '0'},
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,5 +1,6 @@
1
1
  module FactoryBurgers
2
2
  module Models
3
+ # Data class for the output of a factory create action
3
4
  class FactoryOutput
4
5
  attr_reader :object, :presenter
5
6
 
@@ -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
- attribuets: presenter.attributes,
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
 
@@ -0,0 +1,3 @@
1
+ module FactoryBurgers
2
+ VERSION = '0.1.0'.freeze
3
+ end
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.0.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-04-20 00:00:00.000000000 Z
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