factory_burgers 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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":"gSAQeA,MANf,WACE,OACE,wECIWC,MANf,WACE,OACE,sD,uDCFEC,EAAkBC,IAAUC,MAAM,CACtCC,KAAMF,IAAUG,OAAOC,aAGnBC,EAAcL,IAAUC,MAAM,CAClCC,KAAMF,IAAUG,OAAOC,a,GAGJJ,IAAUC,MAAM,CACnCK,WAAYN,IAAUO,QAAQR,GAC9BG,KAAMF,IAAUG,OAAOC,WACvBI,OAAQR,IAAUO,QAAQF,K,8BCoCbI,MA1Cf,SAAsBC,GACpB,OACE,eAACC,EAAA,EAAKC,IAAN,WACE,eAACC,EAAA,EAAD,WACE,cAACF,EAAA,EAAKG,MAAN,6BACA,eAACH,EAAA,EAAKI,QAAN,CACEC,GAAG,SACHC,SAAUP,EAAMO,SAChBf,KAAI,qBACJgB,UAAU,eACVC,MAAOT,EAAMU,UAAUlB,KACvBmB,SAAU,SAAAC,GAAK,OAAIZ,EAAMa,aAAaD,IANxC,UAQE,wBAAQH,MAAOT,EAAMU,UAAUlB,KAA/B,SAAsCQ,EAAMU,UAAUlB,OACrDQ,EAAMc,eAGX,eAACX,EAAA,EAAD,WACE,cAACF,EAAA,EAAKG,MAAN,oBACA,uBACEG,SAAUP,EAAMO,WAAaP,EAAMU,UAAUlB,KAC7CA,KAAI,sBACJgB,UAAU,eACVC,MAAOT,EAAMU,UAAUD,MACvBE,SAAU,SAAAC,GAAK,OAAIZ,EAAMe,cAAcH,aCiDlCI,MAjEf,SAAgBhB,GACd,IAAQJ,EAAeI,EAAfJ,WAER,EAA8CqB,mBAAS,IAAvD,mBAAOC,EAAP,KAAwBC,EAAxB,KAGMC,EAFsBC,mBAAQ,kBATtC,SAAkBC,EAAGC,GACnB,IAAMC,EAAS,IAAIC,IAAIF,EAAEG,KAAI,SAAAC,GAAI,OAAIA,EAAKnC,SAC1C,OAAO8B,EAAEM,QAAO,SAAAD,GAAI,OAAKH,EAAOK,IAAIF,EAAKnC,SAOCsC,CAASlC,EAAYsB,MAETQ,KAAI,SAAAK,GAAI,OAC5D,wBAAwBtB,MAAOsB,EAAKvC,KAApC,SAA2CuC,EAAKvC,MAAnCuC,EAAKvC,SAGpB,SAASwC,EAAT,GAAsC,IAAfxC,EAAc,EAAdA,KAAMiB,EAAQ,EAARA,MAC3BU,EAAmB,GAAD,mBAAKD,GAAL,CAAsB,CAAC1B,OAAMiB,YAajD,SAASwB,EAAiBC,EAAIC,GAC5B,IAAMC,EAAgBlB,EAAgBmB,QACtCD,EAAcE,OAAOJ,EAAI,EAAGC,GAC5BhB,EAAmBiB,GAGrB,OACE,eAACnC,EAAA,EAAKsC,MAAN,CAAYC,UAAU,mBAAtB,UACE,cAACvC,EAAA,EAAKG,MAAN,iCAECc,EAAgBQ,KAAI,SAACK,EAAMG,GAAP,OACnB,cAAC,EAAD,CAEExB,UAAWqB,EACXxB,SAAUP,EAAMO,SAChBM,aAAc,SAAAD,GAAK,OAzB3B,SAA0BsB,EAAItB,GAE5BqB,EAAiBC,EADG,CAAC1C,KAAMoB,EAAM6B,OAAOhC,MAAOA,MAAOS,EAAgBgB,GAAIzB,QAwB7CiC,CAAiBR,EAAItB,IAC5CG,cAAe,SAAAH,GAAK,OArB5B,SAA2BsB,EAAItB,GAE7BqB,EAAiBC,EADG,CAAC1C,KAAM0B,EAAgBgB,GAAI1C,KAAMiB,MAAOG,EAAM6B,OAAOhC,QAoB3CkC,CAAkBT,EAAItB,IALhD,SAOGQ,GANIc,MAUT,cAAC,EAAD,CAEExB,UAAW,CAAClB,KAAM,GAAIiB,MAAO,IAC7BF,SAAUP,EAAMO,SAChBM,aAAc,SAAAD,GAAK,OAAIoB,EAAa,CAACxC,KAAMoB,EAAM6B,OAAOhC,MAAOA,MAAO,MACtEM,cAAe,SAAAH,GAAK,OAAIoB,EAAa,CAACxC,KAAM,GAAIiB,MAAOG,EAAM6B,OAAOhC,SALtE,SAOGW,GANIF,EAAgB0B,OAAS,OCtDtC,SAASC,EAAYC,EAAWC,GAC9B,OAAIA,EACI,GAAN,OAAUD,EAAUE,YAApB,aAAoCF,EAAUG,QAAQzD,KAAtD,aAA+DsD,EAAUG,QAAQC,WAAjF,KAEM,GAAN,OAAUJ,EAAUG,QAAQzD,KAA5B,aAAqCsD,EAAUG,QAAQC,WAAvD,KA4CWC,MAxCf,SAA0BnD,GACxB,IAAQoD,EAA2CpD,EAA3CoD,QAASC,EAAkCrD,EAAlCqD,MAAO5C,EAA2BT,EAA3BS,MAAOE,EAAoBX,EAApBW,SAAUoC,EAAU/C,EAAV+C,MACzC,OACE,eAAC9C,EAAA,EAAKsC,MAAN,CAAYC,UAAU,0BAAtB,UACE,cAACvC,EAAA,EAAKG,MAAN,UAAaiD,IACb,uBACE7D,KAAK,UACL8D,KAAK,YACLC,aAAa,MACb/C,UAAU,eACVC,MAAOA,EACPE,SAAUA,IAEZ,0BAAU6C,GAAG,YAAb,SACGJ,EAAQ1B,KAAI,SAAAoB,GAAS,OACpB,wBAA4CrC,MAAOqC,EAAUG,QAAQzD,KAArE,SACGqD,EAAYC,EAAWC,IADbF,EAAYC,EAAWC,aCa/BU,MAtCf,SAA4BzD,GAC1B,IAAQgD,EAAuBhD,EAAvBgD,YAAaD,EAAU/C,EAAV+C,MAErB,OACE,qCACE,cAAC9C,EAAA,EAAKsC,MAAN,CAAYC,UAAU,sBAAtB,SACE,cAACvC,EAAA,EAAKI,QAAN,CACEqD,KAAK,SACLjD,MAAOsC,GAASA,EAAMW,MAAQ,GAC9BlE,KAAK,iBAGT,cAACS,EAAA,EAAKsC,MAAN,CAAYC,UAAU,oBAAtB,SACE,cAACvC,EAAA,EAAKI,QAAN,CACEqD,KAAK,SACLjD,MAAOsC,GAASA,EAAMS,IAAM,GAC5BhE,KAAK,eAGT,cAACS,EAAA,EAAKsC,MAAN,CAAYC,UAAU,4BAAtB,SACE,cAACvC,EAAA,EAAKI,QAAN,CACEqD,KAAK,SACLjD,MAAOuC,GAAe,GACtBxD,KAAK,4BCOf,IAAMmE,EAASC,IAAWC,OAAO,CAC/B/D,OAAQ,CACNgE,QAAS,OACTC,cAAe,SACfC,SAAU,OACVC,UAAW,SAIAjD,EApCf,SAAgBhB,GACd,IAAQF,EAAWE,EAAXF,OAER,OACE,eAACG,EAAA,EAAKsC,MAAN,CAAYC,UAAU,mBAAtB,UACE,cAACvC,EAAA,EAAKG,MAAN,8CACA,qBAAKI,UAAW0D,YAAIP,EAAO7D,QAA3B,SACGA,EAAO4B,KAAI,SAAAyC,GAAK,OACf,cAAClE,EAAA,EAAKmE,MAAN,CAEEV,KAAK,WACLnD,SAAUP,EAAMO,SAChBiD,GAAIW,EAAM3E,KACVA,KAAI,iBAAY2E,EAAM3E,MACtB6D,MAAOc,EAAM3E,MALR2E,EAAM3E,eChBhB,SAAS6E,IAAwB,IAAD,uBAAZC,EAAY,yBAAZA,EAAY,gBACrC,OAAOA,EAAW1C,QAAO,SAAA2C,GAAC,OAAIA,KAAGC,KAAK,KCuGxC,IAAMb,EAASC,IAAWC,OAAO,CAC/BY,QAAS,CACPX,QAAS,OACTY,eAAgB,mBAILC,EAjGf,SAAqB3E,GACnB,IAAM4E,EAAa5E,EAAM4E,YAAc,GACjC7B,EAAQ/C,EAAM+C,MACd8B,EAAU7E,EAAM6E,SAAW,iBAEjC,EAAwC5D,mBAAS,IAAjD,mBAAO6D,EAAP,KAAqBC,EAArB,KAOMC,EAAoB3D,mBAAQ,kBDtB7B,SAAiB4D,EAAOC,GAC7B,IAAMC,EAAU,GAEhB,OADAF,EAAMG,SAAQ,SAAAzD,GAAI,OAAIwD,EAAQD,EAAKvD,IAASA,KACrCwD,ECmBiCE,CAAQT,GAAY,SAAA9B,GAAS,OAAIA,EAAUG,QAAQzD,UAAO,CAACoF,IAC7FU,EAAoBjE,mBAAQ,kBAAM2D,EAAkBF,KAAe,CAACA,IACpElF,EAAayB,mBAAQ,kBAAMiE,GAAqBA,EAAkBrC,QAAQrD,YAAc,KAAI,CAAC0F,IAC7FxF,EAASuB,mBAAQ,kBAAMiE,GAAqBA,EAAkBrC,QAAQnD,QAAU,KAAI,CAACwF,IACrFC,IAAmBD,EAEnBE,EDtBD,SAAqB/E,GAC1B,IAAMgF,EAAMC,mBAIZ,OAHAC,qBAAU,WACRF,EAAIG,QAAUnF,KAETgF,EAAIG,QCiBOC,CAAY7F,EAAM+C,OAUpC4C,qBAAU,YARV,SAAmB5C,EAAO+C,GACxB,IAAMC,EAAYhD,GAASA,EAAMW,KAC3BsC,EAAUjD,GAASA,EAAMS,GACzByC,EAAiBH,GAASA,EAAMpC,KAChCwC,EAAeJ,GAASA,EAAMtC,GACpC,OAAOuC,IAAcE,GAAkBD,GAAWE,GAI7CC,CAAUnG,EAAM+C,MAAOyC,IAAcT,EAAgB,MACzD,CAAC/E,EAAM+C,QAEV,IAAMqD,EAAOV,iBAAO,MAQpB,OACE,eAACzF,EAAA,EAAD,CAAMwF,IAAKW,EAAMC,SAAUrG,EAAMsG,aAAjC,UAEE,cAAC,EAAD,CACElD,QAASwB,EACTvB,MAAOwB,EACPpE,MAAOqE,EACPnE,SAxCN,SAAuBC,GACrB,IAAMH,EAAQG,EAAM6B,OAAOhC,MAC3BsE,EAAgBtE,IAuCZsC,MAAOA,IAGT,cAAC,EAAD,CAAoBA,MAAOA,EAAOC,YAAasC,GAAqBA,EAAkBtC,cAErFlD,EAAO8C,OAAS,GACf,cAAC,EAAD,CAAQrC,SAAUP,EAAMO,SAAUT,OAAQA,IAG3CF,EAAWgD,OAAS,GACnB,cAAC2D,EAAD,CAAYhG,SAAUP,EAAMO,SAAUX,WAAYA,IAGpD,sBAAKY,UAAW0D,YAAIP,EAAOc,SAA3B,UACE,cAAC+B,EAAA,EAAD,CAAQC,QAAQ,eAAejG,UAAU,cAAcD,SAAUP,EAAMO,WAAagF,EAAgB7B,KAAK,SAAzG,oBAGA,cAAC8C,EAAA,EAAD,CAAQC,QAAQ,eAAejG,UAAU,aAAaD,SAAUP,EAAMO,SAAUmG,QA/BtF,WACEN,EAAKR,SAAWQ,EAAKR,QAAQe,QAC7B5B,EAAgB,IAChB/E,EAAM4G,aA4BkGlD,KAAK,SAAzG,wBAEU,W,QCjEHmD,MAbf,SAA4B7G,GAC1B,IAAM8G,EAAU9G,EAAM8G,SAAW,uBACjC,OACE,cAACC,EAAA,EAAD,CAAON,QAAQ,SAAf,SACGK,KCIQE,MAXf,WACE,OACE,qBAAKC,MAAM,MAAMC,OAAO,MAAMC,QAAQ,YAAtC,SACE,oBAAGC,eAAa,MAAMC,OAAO,OAAOC,KAAK,OAAOC,iBAAe,QAAQC,kBAAgB,QAAvF,UACE,0BAAUC,OAAO,wCACjB,sBAAMC,EAAE,oDCgDhB,IAAM/D,EAASC,IAAWC,OAAO,CAC/B8D,OAAQ,CACNC,UAAW,oBAEbC,OAAQ,CACNC,OAAQ,iBACRC,aAAc,MACdjE,QAAS,OACTC,cAAe,SACfiE,QAAS,QACTC,YAAa,QACbC,SAAU,WACVC,OAAQ,UACRC,WAAY,yBAEdC,cAAe,CACbC,KAAM,EACNrB,MAAO,QAETsB,YAAa,CACXD,KAAM,EACNrB,MAAO,OACPuB,aAAc,iBACdC,aAAc,SAIHC,EA/Df,SAAoB1I,GAClB,MAAwBA,EAAhB6H,cAAR,MAAiB,GAAjB,EACMjI,EAAaiI,EAAOjI,YAAc,GAClCY,EAbR,YAA8C,IAApBmI,EAAmB,EAAnBA,MAAOC,EAAY,EAAZA,SAC/B,OAAID,EACK,UACEC,EACF,WAEA,KAOSC,CAAe,CAACF,MAAO3I,EAAM8I,IAAKF,SAAU5I,EAAM2H,SACpE,OACE,sBAAKnH,UAAW6D,EAAQH,YAAIP,EAAOkE,OAAQ7H,EAAM2H,QAAUhE,EAAOgE,QAASnH,EAAW,6BAA8BkG,QAAS1G,EAAM+I,SAAnI,UACE,sBAAKvI,UAAW0D,YAAIP,EAAO4E,aAA3B,UACGV,EAAOnE,KACPmE,EAAOmB,MACN,mBAAGC,KAAMpB,EAAOmB,KAAMvG,OAAO,SAASyG,IAAI,sBAAsB1I,UAAU,OAA1E,SACE,cAAC,EAAD,SAIN,qBAAKA,UAAW0D,YAAIP,EAAO0E,eAA3B,SACGc,OAAOC,QAAQxJ,GAAY8B,KAAI,mCAAElC,EAAF,KAAQiB,EAAR,YAC9B,wCACMjB,EADN,aACeiB,IADLjB,YCrBL6J,MAVf,WACE,OACE,qBAAK7I,UAAU,qBAAf,SACE,cAAC,EAAD,CACEqH,OAAQ,CAACnE,KAAM,oBCqKvB,IAAMC,EAASC,IAAWC,OAAO,CAC/BuC,KAAM,CACJqC,aAAc,MACdL,WAAY,wBACZkB,SAAU,UAEZC,WAAY,CACVzF,QAAS,OACT0F,OAAQ,iBAIGC,EA/Jf,SAAmBzJ,GACjB,IARgB6H,EAQR6B,EAAc1J,EAAd0J,UAMR,EAAwCzI,oBAAS,GAAjD,mBAAO0I,EAAP,KAAqBC,EAArB,KACA,EAA0B3I,mBAAS,MAAnC,mBAAO4I,EAAP,KAAcC,EAAd,KACA,EAAgC7I,oBAAS,GAAzC,mBAAO8I,EAAP,KAAiBC,EAAjB,KACA,EAA4C/I,mBAAS,MAArD,mBAAOgJ,EAAP,KAAuBC,EAAvB,KACA,EAA8BjJ,mBAAS,GAAD,OANjB,KAMrB,mBAAOkJ,EAAP,KAAgBC,EAAhB,KACA,EAAsDnJ,mBAAS,MAA/D,mBAAOoJ,EAAP,KAA4BC,EAA5B,KAEMC,EAAcb,EAAUhI,KAAI,SAAAuB,GAAO,MAAK,CAACA,cACzCuH,EAAyC,OAAxBH,GAAgCF,EAAQvH,OAAS,GAAKuH,EAAQE,GAE/EI,EAAuBpJ,mBAAQ,WACnC,OAAKmJ,GAAmBA,EAAeE,sBACbF,EAAeE,sBAAsBhJ,KAC7D,SAAAC,GAAI,OAlCV,SAAgC+H,EAAW1G,GACzC,MAAO,CACLC,QAASyG,EAAUiB,MAAK,SAAAC,GAAC,OAAIA,EAAEpL,OAASwD,EAAY6H,gBACpD7H,YAAaA,EAAY8H,kBA+BfC,CAAuBrB,EAAW/H,MAF2B,KAKtE,CAAC6I,IAEE5F,EAAa4F,EAAiBC,EAAuBF,EACrD1F,EAAU2F,EAAc,yCAAqCA,EAAe9G,KAApD,KAA8D,KA1BpE,4CAiDxB,WAAsBsH,GAAtB,mBAAA1J,EAAA,6DACQ2J,EAAMjL,EAAMkL,WADpB,SAGyBC,MAAMF,EAAK,CAChCG,OAAQ,OACRC,KAAML,IALV,cAGQM,EAHR,gBAQ6BA,EAASC,OARtC,OAQQC,EARR,OAUOF,EAASG,GAKZC,EAAmBF,IAHnBG,QAAQ9B,MAAM+B,KAAKC,UAAUL,IAC7BM,EAAkBN,EAAa3B,OAAS,4BAb5C,4CAjDwB,sBAoExB,SAAS6B,EAAmBF,GACtBA,EAAaC,IAEfE,QAAQI,IAAIH,KAAKC,UAAUL,IAe/B,SAAsB3D,GACpB+B,GAAgB,GAChBE,EAAS,MACTE,GAAY,GACZI,EAAWD,EAAQ9H,QAAQ2J,OAAO,CAACnE,KACZ,IAAnBsC,EAAQvH,QACV0H,EAAuB,GAEzBJ,EAAkBC,EAAQvH,QAtBxBqJ,CAAaT,EAAaR,QAG1BW,QAAQ9B,MAAM2B,EAAa3B,OAC3BiC,EAAkBN,EAAa3B,OAAS,iCAI5C,SAASiC,EAAkBhF,GACzB8C,GAAgB,GAChBE,EAAShD,GACTkD,GAAY,GAkBd,OACE,sBAAKxJ,UAAU,YAAf,UACE,4CAEEmJ,GAAiBQ,EAAQvH,OAAS,IAClC,qCACG+G,EAAe,mBAAqB,eACpCQ,EAAQvH,OAAS,GAChB,iCAAO,IAAP,8DAEF,sBAAKpC,UAAW0D,YAAIP,EAAO4F,YAA3B,UACGY,EAAQzI,KAAI,SAACmG,EAAQ3F,GAAT,OACX,cAAC,EAAD,CAEE2F,OAAQA,EACRF,OAAQ0C,IAAwBnI,EAChC6G,SAAU,kBAlFxB,SAAsB7G,GACpBgI,EAAkB,MAClBI,EAAuBpI,GAgFKgK,CAAahK,IAC7B4G,IAAKmB,IAAmB/H,GAJnBA,MAORyH,GAAgB,cAAC,EAAD,UAKtBE,GAAS,cAAC,EAAD,CAAoB/C,QAAS+C,IAEvC,qBAAKrJ,UAAW0D,YAAIP,EAAOyC,MAA3B,SACE,cAAC,EAAD,CACErD,MAAOyH,GAzIC3C,EAyIyB2C,EAxIlC,CACL9G,KAAMmE,EAAOnE,KACbF,GAAIqE,EAAOjI,WAAW4D,KAsImC,KACnDoB,WAAYA,EACZrE,SAAUwJ,EACVzD,aA7FR,SAAsB1F,GAKpB,IAoDgBwF,EAxDhBxF,EAAMuL,iBACNvC,GAAgB,GAChBE,EAAS,MACTE,GAAY,GA5CU,oCA8CtBoC,EAmDgBhG,EApDMxF,EAAM6B,OAqDrB,IAAI4J,SAASjG,MAoCdQ,UA1GR,WACEsD,EAAkB,MAClBA,EAAkB,MAClBE,EAAW,IACXE,EAAuB,OAuGjBzF,QAASA,UCjKZ,SAASyH,IACd,OAAOnB,MAAM,UACVoB,MAAK,SAAAC,GAAG,OAAIA,EAAIjB,UCoCNkB,MAzBf,WACE,IAAM/C,ECGD,SAAuBgD,GAA4B,IAApBC,EAAmB,uDAAJ,GACnD,EAA0B1L,mBAAS,MAAnC,mBAAO4I,EAAP,KAAcC,EAAd,KACA,EAAgC7I,mBAAiC,IAAxB0L,EAAa/J,QAAtD,mBAAOmH,EAAP,KAAiBC,EAAjB,KACA,EAAgC/I,mBAAS,MAAzC,mBAAOqK,EAAP,KAAiBsB,EAAjB,KAHuD,SAUxCC,IAVwC,2EAUvD,sBAAAvL,EAAA,+EACSoL,KADT,4CAVuD,sBAcvD,SAASI,IACP9C,GAAY,GAOd,OAjBArE,qBAAU,WACRqE,GAAY,GACZ6C,IAAaN,KAAKK,GAAaG,MAAMjD,GAAUyC,KAAKO,KACnDH,GAUWtL,mBAAQ,WACpB,MAAO,CAACwI,QAAOE,WAAUuB,cACxB,CAACzB,EAAOE,EAAUuB,IDvBH0B,CAAcC,GAIhC,OAFAtH,qBAAU,WAAQgG,QAAQI,IAAIrC,KAAc,CAACA,IAG3C,sBAAKlJ,UAAU,MAAf,UACE,iCACE,qBAAK0M,MAAM,cAAX,uBAEF,iCACGxD,EAAUK,UAAY,cAAC,EAAD,IACtBL,EAAUG,OAAS,cAAC,EAAD,IACnBH,EAAU4B,UACT,cAAC,EAAD,CACE6B,UAAU,GACVjC,WAAW,UACXxB,UAAWA,EAAU4B,kBElBlB8B,EAZS,SAAAC,GAClBA,GAAeA,aAAuBC,UACxC,6BAAqBf,MAAK,YAAkD,IAA/CgB,EAA8C,EAA9CA,OAAQC,EAAsC,EAAtCA,OAAQC,EAA8B,EAA9BA,OAAQC,EAAsB,EAAtBA,OAAQC,EAAc,EAAdA,QAC3DJ,EAAOF,GACPG,EAAOH,GACPI,EAAOJ,GACPK,EAAOL,GACPM,EAAQN,OCDdO,IAASC,OACP,cAAC,IAAMC,WAAP,UACE,cAAC,EAAD,MAEFC,SAASC,eAAe,SAM1BZ,M","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