bullet_train 1.0.96 → 1.0.99

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e32e536643be032d267207a75c56fabf21aebe72287282c6b50ada2f3493df88
4
- data.tar.gz: 49a9a73f61d045595ef8259953b3066d442c591b5bb15bbc1dee9998e8d560eb
3
+ metadata.gz: 00a1173803e9bee7ab0710b0b58cc2acd39410f253b1998ddbac32ad2d7aa159
4
+ data.tar.gz: 3fb346b3c73b5f6dc7d423f7cf40e1c98f35832850c13d9afaeecf7260c222d7
5
5
  SHA512:
6
- metadata.gz: 4d97ef875b0d800b5cb807d4e1257b2ec7564e1e08f85e437d4d75437c4b5a6b4ef2f58aa380c5ce2b674dd92ecd2f58a910a68811b61a6847f7933219409823
7
- data.tar.gz: 56cb003bdccdc8baad20d91be3b3bb0bbfda1cb3b1bb50759c91c1d062b9a357e98db79cf55583bedddd8480629ea4f12aeb5fc727e1f7bc79f6729578827b7a
6
+ metadata.gz: f69696c007457c625b410741693ef467c5c528d9a23871fedcacd7ec926cc73d8d9fa369c72f3f8048f47acbff62264e1cb3d1877e4ad51b5937fbf3e9eb940d
7
+ data.tar.gz: c7eff30ad9b7faa0770b481a1b3967981105b005bb0e4520f64d26a0e08e4f68583a26599098c93cddd68b948c716ad1a7e6a64d13f80d1a2b629324e890467c
@@ -1,2 +1,2 @@
1
- import{Controller as e}from"@hotwired/stimulus";function t(e){const t=(e.match(/^(?:\.\/)?(.+)(?:[_-]controller\..+?)$/)||[])[1];if(t)return t.replace(/_/g,"-").replace(/\//g,"--")}class l extends e{connect(){this.updateAvailability()}updateFormAndSubmit(e){return this.recreateIdsHiddenFields(),this.createOrUpdateAllField(),!0}updateIds(e){var t;null!=e&&null!=(t=e.detail)&&t.ids&&(this.idsValue=e.detail.ids,this.allValue=e.detail.all),this.updateAvailability(),this.updateButtonLabel()}updateAvailability(){this.element.classList.toggle(this.hiddenClass,0===this.idsValue.length)}updateButtonLabel(){let e=this.buttonIfAllValue;this.idsValue.length&&!1===this.allValue&&(e=this.buttonIfIdsValue.replace("{num}",this.idsValue.length)),"INPUT"===this.buttonTarget.tagName?this.buttonTarget.value=e:this.buttonTarget.textContent=e}recreateIdsHiddenFields(){this.removeIdsHiddenFields(),this.createIdsHiddenFields()}removeIdsHiddenFields(){this.idsHiddenFieldTargets.forEach(e=>{this.element.removeChild(e)})}createIdsHiddenFields(){this.idsValue.forEach(e=>{let t=document.createElement("input");t.type="hidden",t.name=this.objectNameValue+"["+this.idsFieldNameValue+"][]",t.value=e,this.element.appendChild(t)})}createOrUpdateAllField(){this.hasAllHiddenFieldTarget?this.allHiddenFieldTarget.value=this.allValue?"true":"false":this.createAllField()}createAllField(){let e=document.createElement("input");e.type="hidden",e.name=this.objectNameValue+"["+this.allFieldNameValue+"]",e.value=this.allValue?"true":"false",this.element.appendChild(e)}}l.targets=["button","idsHiddenField","allHiddenField"],l.classes=["hidden"],l.values={buttonIfAll:String,buttonIfIds:String,ids:Array,all:Boolean,objectName:String,idsFieldName:String,allFieldName:String};class s extends e{connect(){this.element.classList.add(this.selectableAvailableClass)}toggleSelectable(){this.selectableValue=!this.selectableValue}updateSelectedIds(){this.updateActions(),this.updateSelectAllCheckbox()}updateActions(){this.actionTargets.forEach(e=>{e.dispatchEvent(new CustomEvent("update-ids",{detail:{ids:this.selectedIds,all:this.allSelected}}))})}selectAllOrNone(e){this.allSelected?this.selectNone():this.selectAll(),this.updateSelectAllCheckbox()}selectAll(){this.checkboxTargets.forEach(e=>{e.checked=!0}),this.updateActions()}selectNone(){this.checkboxTargets.forEach(e=>{e.checked=!1}),this.updateActions()}updateSelectAllCheckbox(){let e=this.selectAllCheckboxTarget,t=this.selectAllLabelTarget;this.allSelected?(e.checked=!0,e.indeterminate=!1,t.dispatchEvent(new CustomEvent("toggle",{detail:{useAlternate:!0}}))):this.selectedIds.length>0?(e.indeterminate=!0,t.dispatchEvent(new CustomEvent("toggle",{detail:{useAlternate:!1}}))):(e.checked=!1,e.indeterminate=!1,t.dispatchEvent(new CustomEvent("toggle",{detail:{useAlternate:!1}})))}selectableValueChanged(){this.element.classList.toggle(this.selectableClass,this.selectableValue),this.updateToggleLabel()}updateToggleLabel(){this.selectableToggleTarget.dispatchEvent(new CustomEvent("toggle",{detail:{useAlternate:this.selectableValue}}))}get selectedIds(){let e=[];return this.checkboxTargets.forEach(t=>{t.checked&&e.push(t.value)}),e}get allSelected(){return this.selectedIds.length===this.checkboxTargets.length}}s.targets=["checkbox","selectAllCheckbox","action","selectableToggle","selectAllLabel"],s.classes=["selectableAvailable","selectable"],s.values={selectable:Boolean};class i extends e{copy(){this.inputTarget.value=this.sourceTarget.innerText,this.inputTarget.select(),document.execCommand("copy"),this.buttonTarget.innerHTML='<i id="copied" class="fas fa-check w-4 h-4 block text-green-600"></i>',setTimeout(function(){document.getElementById("copied").innerHTML='<i class="far fa-copy w-4 h-4 block text-gray-600"></i>'},1500)}}i.targets=["source","input","button"];class a extends e{constructor(){super(...arguments),this.removeTrailingNewlines=e=>{e.element.innerHTML.match(/<br><\/div>$/)&&(e.element.innerHTML=e.element.innerHTML.slice(0,-10)+"</div>",this.removeTrailingNewlines(e))},this.removeTrailingWhitespace=e=>{e.element.innerHTML.match(/&nbsp;<\/div>$/)?(e.element.innerHTML=e.element.innerHTML.slice(0,-12)+"</div>",this.removeTrailingWhitespace(e)):e.element.innerHTML.match(/&nbsp; <\/div>$/)&&(e.element.innerHTML=e.element.innerHTML.slice(0,-13)+"</div>",this.removeTrailingWhitespace(e))}}resetOnSuccess(e){e.detail.success&&e.target.reset()}stripTrix(){this.trixFieldTargets.forEach(e=>{this.removeTrailingNewlines(e.editor),this.removeTrailingWhitespace(e.editor),e.parentElement.querySelector("input").value=e.innerHTML})}submitOnReturn(e){if((e.metaKey||e.ctrlKey)&&13==e.keyCode){e.preventDefault();let t=e.target.closest("form");this.submitForm(t)}}submitForm(e){e.requestSubmit?e.requestSubmit():e.querySelector("[type=submit]").click()}}a.targets=["trixField","scroll"];class n extends e{toggle(){const e=this.isWrapperHidden?this.showEventNameValue:this.hideEventNameValue;this.isWrapperHidden&&this.showWrapper(),this.wrapperTarget.dispatchEvent(new CustomEvent(e))}get isWrapperHidden(){return this.wrapperTarget.classList.contains(this.hiddenClass)}showWrapper(){this.wrapperTarget.classList.remove(this.hiddenClass)}hideWrapper(){this.wrapperTarget.classList.add(this.hiddenClass)}}n.targets=["wrapper"],n.classes=["hidden"],n.values={showEventName:String,hideEventName:String};const r=[[l,"bulk_action_form_controller.js"],[s,"bulk_actions_controller.js"],[i,"clipboard_controller.js"],[a,"form_controller.js"],[n,"mobile_menu_controller.js"]].map(function(e){const l=e[0];return{identifier:t(e[1]),controllerConstructor:l}});document.addEventListener("turbo:load",()=>{navigator.userAgent.toLocaleLowerCase().includes("electron")&&document.body.classList.add("electron")});export{r as controllerDefinitions};
1
+ import{Controller as e}from"@hotwired/stimulus";function t(e){const t=(e.match(/^(?:\.\/)?(.+)(?:[_-]controller\..+?)$/)||[])[1];if(t)return t.replace(/_/g,"-").replace(/\//g,"--")}class l extends e{connect(){this.updateAvailability()}updateFormAndSubmit(e){return this.recreateIdsHiddenFields(),this.createOrUpdateAllField(),!0}updateIds(e){var t;null!=e&&null!=(t=e.detail)&&t.ids&&(this.idsValue=e.detail.ids,this.allValue=e.detail.all),this.updateAvailability(),this.updateButtonLabel()}updateAvailability(){this.element.classList.toggle(this.hiddenClass,0===this.idsValue.length)}updateButtonLabel(){let e=this.buttonIfAllValue;this.idsValue.length&&!1===this.allValue&&(e=this.buttonIfIdsValue.replace("{num}",this.idsValue.length)),"INPUT"===this.buttonTarget.tagName?this.buttonTarget.value=e:this.buttonTarget.textContent=e}recreateIdsHiddenFields(){this.removeIdsHiddenFields(),this.createIdsHiddenFields()}removeIdsHiddenFields(){this.idsHiddenFieldTargets.forEach(e=>{this.element.removeChild(e)})}createIdsHiddenFields(){this.idsValue.forEach(e=>{let t=document.createElement("input");t.type="hidden",t.name=this.objectNameValue+"["+this.idsFieldNameValue+"][]",t.value=e,this.element.appendChild(t)})}createOrUpdateAllField(){this.hasAllHiddenFieldTarget?this.allHiddenFieldTarget.value=this.allValue?"true":"false":this.createAllField()}createAllField(){let e=document.createElement("input");e.type="hidden",e.name=this.objectNameValue+"["+this.allFieldNameValue+"]",e.value=this.allValue?"true":"false",this.element.appendChild(e)}}l.targets=["button","idsHiddenField","allHiddenField"],l.classes=["hidden"],l.values={buttonIfAll:String,buttonIfIds:String,ids:Array,all:Boolean,objectName:String,idsFieldName:String,allFieldName:String};class s extends e{connect(){this.element.classList.add(this.selectableAvailableClass)}toggleSelectable(){this.selectableValue=!this.selectableValue}updateSelectedIds(){this.updateActions(),this.updateSelectAllCheckbox()}updateActions(){this.actionTargets.forEach(e=>{e.dispatchEvent(new CustomEvent("update-ids",{detail:{ids:this.selectedIds,all:this.allSelected}}))})}selectAllOrNone(e){this.allSelected?this.selectNone():this.selectAll(),this.updateSelectAllCheckbox()}selectAll(){this.checkboxTargets.forEach(e=>{e.checked=!0}),this.updateActions()}selectNone(){this.checkboxTargets.forEach(e=>{e.checked=!1}),this.updateActions()}updateSelectAllCheckbox(){let e=this.selectAllCheckboxTarget,t=this.selectAllLabelTarget;this.allSelected?(e.checked=!0,e.indeterminate=!1,t.dispatchEvent(new CustomEvent("toggle",{detail:{useAlternate:!0}}))):this.selectedIds.length>0?(e.indeterminate=!0,t.dispatchEvent(new CustomEvent("toggle",{detail:{useAlternate:!1}}))):(e.checked=!1,e.indeterminate=!1,t.dispatchEvent(new CustomEvent("toggle",{detail:{useAlternate:!1}})))}selectableValueChanged(){this.element.classList.toggle(this.selectableClass,this.selectableValue),this.updateToggleLabel()}updateToggleLabel(){this.selectableToggleTarget.dispatchEvent(new CustomEvent("toggle",{detail:{useAlternate:this.selectableValue}}))}get selectedIds(){let e=[];return this.checkboxTargets.forEach(t=>{t.checked&&e.push(t.value)}),e}get allSelected(){return this.selectedIds.length===this.checkboxTargets.length}}s.targets=["checkbox","selectAllCheckbox","action","selectableToggle","selectAllLabel"],s.classes=["selectableAvailable","selectable"],s.values={selectable:Boolean};class a extends e{copy(){this.inputTarget.value=this.sourceTarget.innerText,this.inputTarget.select(),document.execCommand("copy"),this.buttonTarget.innerHTML='<i id="copied" class="fas fa-check w-4 h-4 block text-green-600"></i>',setTimeout(function(){document.getElementById("copied").innerHTML='<i class="far fa-copy w-4 h-4 block text-gray-600"></i>'},1500)}}a.targets=["source","input","button"];class i extends e{constructor(){super(...arguments),this.removeTrailingNewlines=e=>{e.element.innerHTML.match(/<br><\/div>$/)&&(e.element.innerHTML=e.element.innerHTML.slice(0,-10)+"</div>",this.removeTrailingNewlines(e))},this.removeTrailingWhitespace=e=>{e.element.innerHTML.match(/&nbsp;<\/div>$/)?(e.element.innerHTML=e.element.innerHTML.slice(0,-12)+"</div>",this.removeTrailingWhitespace(e)):e.element.innerHTML.match(/&nbsp; <\/div>$/)&&(e.element.innerHTML=e.element.innerHTML.slice(0,-13)+"</div>",this.removeTrailingWhitespace(e))}}resetOnSuccess(e){e.detail.success&&e.target.reset()}stripTrix(){this.trixFieldTargets.forEach(e=>{this.removeTrailingNewlines(e.editor),this.removeTrailingWhitespace(e.editor),e.parentElement.querySelector("input").value=e.innerHTML})}submitOnReturn(e){if((e.metaKey||e.ctrlKey)&&13==e.keyCode){e.preventDefault();let t=e.target.closest("form");this.submitForm(t)}}submitForm(e){e.requestSubmit?e.requestSubmit():e.querySelector("[type=submit]").click()}}async function n(e,t,l){const s=t.dataset,a=l?`${l}-${e}`:e;let i=`transition${e.charAt(0).toUpperCase()+e.slice(1)}`;const n=s[i]?s[i].split(" "):[a],c=s[`${i}Start`]?s[`${i}Start`].split(" "):[`${a}-start`],o=s[`${i}End`]?s[`${i}End`].split(" "):[`${a}-end`];r(t,n),r(t,c),await new Promise(e=>{requestAnimationFrame(()=>{requestAnimationFrame(e)})}),d(t,c),r(t,o),await function(e){return new Promise(t=>{const l=getComputedStyle(e).transitionDuration.split(",")[0],s=1e3*Number(l.replace("s",""));setTimeout(()=>{t()},s)})}(t),d(t,o),d(t,n)}function r(e,t){e.classList.add(...t)}function d(e,t){e.classList.remove(...t)}i.targets=["trixField","scroll"];class c extends e{open(){this.showWrapper(),this.revealableTargets.forEach(e=>{!async function(e,t=null){e.classList.remove("hidden"),await n("enter",e,t)}(e)})}close(){Promise.all(this.revealableTargets.map(e=>async function(e,t=null){await n("leave",e,t),e.classList.add("hidden")}(e))).then(()=>{this.hideWrapper()})}showWrapper(){this.wrapperTarget.classList.remove(this.hiddenClass)}hideWrapper(){this.wrapperTarget.classList.add(this.hiddenClass)}}c.targets=["wrapper","revealable"],c.classes=["hidden"];class o extends e{connect(){this.updateLabel()}toggle(e){var t;this.useAlternateValue=void 0!==(null==e||null==(t=e.detail)?void 0:t.useAlternate)?e.detail.useAlternate:!this.useAlternateValue}useAlternateValueChanged(){this.updateLabel()}updateLabel(){this.hasLabelValue&&this.hasLabelAlternateValue&&this.hasUseAlternateValue&&(this.element.textContent=!0===this.useAlternateValue?this.labelAlternateValue:this.labelValue)}}o.values={label:String,labelAlternate:String,useAlternate:Boolean};const h=[[l,"bulk_action_form_controller.js"],[s,"bulk_actions_controller.js"],[a,"clipboard_controller.js"],[i,"form_controller.js"],[c,"mobile_menu_controller.js"],[o,"text_toggle_controller.js"]].map(function(e){const l=e[0];return{identifier:t(e[1]),controllerConstructor:l}});document.addEventListener("turbo:load",()=>{navigator.userAgent.toLocaleLowerCase().includes("electron")&&document.body.classList.add("electron")});export{h as controllerDefinitions};
2
2
  //# sourceMappingURL=bullet-train.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bullet-train.js","sources":["../../../node_modules/@hotwired/stimulus-webpack-helpers/dist/stimulus-webpack-helpers.js","../../javascript/controllers/bulk_action_form_controller.js","../../javascript/controllers/bulk_actions_controller.js","../../javascript/controllers/clipboard_controller.js","../../javascript/controllers/form_controller.js","../../javascript/controllers/mobile_menu_controller.js","../../javascript/controllers/index.js","../../javascript/electron/index.js"],"sourcesContent":["/*\nStimulus Webpack Helpers 1.0.0\nCopyright © 2021 Basecamp, LLC\n */\nfunction definitionsFromContext(context) {\n return context.keys()\n .map((key) => definitionForModuleWithContextAndKey(context, key))\n .filter((value) => value);\n}\nfunction definitionForModuleWithContextAndKey(context, key) {\n const identifier = identifierForContextKey(key);\n if (identifier) {\n return definitionForModuleAndIdentifier(context(key), identifier);\n }\n}\nfunction definitionForModuleAndIdentifier(module, identifier) {\n const controllerConstructor = module.default;\n if (typeof controllerConstructor == \"function\") {\n return { identifier, controllerConstructor };\n }\n}\nfunction identifierForContextKey(key) {\n const logicalName = (key.match(/^(?:\\.\\/)?(.+)(?:[_-]controller\\..+?)$/) || [])[1];\n if (logicalName) {\n return logicalName.replace(/_/g, \"-\").replace(/\\//g, \"--\");\n }\n}\n\nexport { definitionForModuleAndIdentifier, definitionForModuleWithContextAndKey, definitionsFromContext, identifierForContextKey };\n","import { Controller } from '@hotwired/stimulus'\n\nexport default class extends Controller {\n static targets = [ \"button\", \"idsHiddenField\", \"allHiddenField\" ]\n static classes = [ \"hidden\" ]\n static values = {\n buttonIfAll: String,\n buttonIfIds: String,\n ids: Array,\n all: Boolean,\n objectName: String,\n idsFieldName: String,\n allFieldName: String\n }\n\n connect() {\n this.updateAvailability()\n }\n\n updateFormAndSubmit(event) {\n this.recreateIdsHiddenFields()\n this.createOrUpdateAllField()\n return true\n }\n\n updateIds(event) {\n if (event?.detail?.ids) {\n this.idsValue = event.detail.ids\n this.allValue = event.detail.all\n }\n\n this.updateAvailability()\n this.updateButtonLabel()\n }\n\n updateAvailability() {\n this.element.classList.toggle(this.hiddenClass, this.idsValue.length === 0)\n }\n\n updateButtonLabel() {\n let label = this.buttonIfAllValue\n if (this.idsValue.length && this.allValue === false) {\n label = this.buttonIfIdsValue.replace('{num}', this.idsValue.length)\n }\n\n switch (this.buttonTarget.tagName) {\n case 'INPUT': this.buttonTarget.value = label; break;\n default: this.buttonTarget.textContent = label; break;\n }\n }\n\n recreateIdsHiddenFields() {\n this.removeIdsHiddenFields()\n this.createIdsHiddenFields()\n }\n\n removeIdsHiddenFields() {\n this.idsHiddenFieldTargets.forEach(field => {\n this.element.removeChild(field)\n })\n }\n\n createIdsHiddenFields() {\n this.idsValue.forEach(id => {\n let field = document.createElement('input')\n field.type = 'hidden'\n field.name = `${this.objectNameValue}[${this.idsFieldNameValue}][]`\n field.value = id\n this.element.appendChild(field)\n })\n }\n\n createOrUpdateAllField() {\n if (this.hasAllHiddenFieldTarget) {\n this.allHiddenFieldTarget.value = this.allValue? 'true': 'false'\n } else {\n this.createAllField()\n }\n }\n\n createAllField() {\n let field = document.createElement('input')\n field.type = 'hidden'\n field.name = `${this.objectNameValue}[${this.allFieldNameValue}]`\n field.value = this.allValue? 'true': 'false'\n this.element.appendChild(field)\n }\n}","import { Controller } from '@hotwired/stimulus'\n\nexport default class extends Controller {\n static targets = [ \"checkbox\", \"selectAllCheckbox\", \"action\", \"selectableToggle\", \"selectAllLabel\" ]\n static classes = [ \"selectableAvailable\", \"selectable\" ]\n static values = {\n selectable: Boolean\n }\n\n connect() {\n this.element.classList.add(this.selectableAvailableClass)\n }\n\n toggleSelectable() {\n this.selectableValue = !this.selectableValue\n }\n\n updateSelectedIds() {\n this.updateActions()\n this.updateSelectAllCheckbox()\n }\n\n updateActions() {\n this.actionTargets.forEach(actionTarget => {\n actionTarget.dispatchEvent(new CustomEvent('update-ids', { detail: {\n ids: this.selectedIds,\n all: this.allSelected\n }}))\n })\n }\n\n selectAllOrNone(event) {\n if (this.allSelected) {\n this.selectNone()\n } else {\n this.selectAll()\n }\n this.updateSelectAllCheckbox()\n }\n\n selectAll() {\n this.checkboxTargets.forEach(checkbox => {\n checkbox.checked = true\n })\n this.updateActions()\n }\n\n selectNone() {\n this.checkboxTargets.forEach(checkbox => {\n checkbox.checked = false\n })\n this.updateActions()\n }\n\n updateSelectAllCheckbox() {\n let checkbox = this.selectAllCheckboxTarget\n let label = this.selectAllLabelTarget\n\n if (this.allSelected) {\n checkbox.checked = true\n checkbox.indeterminate = false\n label.dispatchEvent(new CustomEvent('toggle', { detail: { useAlternate: true }} ))\n } else if (this.selectedIds.length > 0) {\n checkbox.indeterminate = true\n label.dispatchEvent(new CustomEvent('toggle', { detail: { useAlternate: false }} ))\n } else {\n checkbox.checked = false\n checkbox.indeterminate = false\n label.dispatchEvent(new CustomEvent('toggle', { detail: { useAlternate: false }} ))\n }\n }\n\n selectableValueChanged() {\n this.element.classList.toggle(this.selectableClass, this.selectableValue)\n this.updateToggleLabel()\n }\n\n updateToggleLabel() {\n this.selectableToggleTarget.dispatchEvent(new CustomEvent('toggle', { detail: { useAlternate: this.selectableValue }} ))\n }\n\n get selectedIds() {\n let ids = []\n this.checkboxTargets.forEach(checkbox => {\n if (checkbox.checked) {\n ids.push(checkbox.value)\n }\n })\n return ids\n }\n\n get allSelected() {\n return this.selectedIds.length === this.checkboxTargets.length\n }\n}","import { Controller } from \"@hotwired/stimulus\"\n\nexport default class extends Controller {\n static targets = ['source', 'input', 'button']\n\n copy() {\n this.inputTarget.value = this.sourceTarget.innerText\n this.inputTarget.select()\n document.execCommand('copy')\n this.buttonTarget.innerHTML = '<i id=\"copied\" class=\"fas fa-check w-4 h-4 block text-green-600\"></i>'\n setTimeout(function () {\n document.getElementById('copied').innerHTML = '<i class=\"far fa-copy w-4 h-4 block text-gray-600\"></i>'\n }, 1500)\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\n// TODO Some of this feels really specific to the conversation messages form. Should we rename this controller?\nexport default class extends Controller {\n static targets = ['trixField', 'scroll']\n\n resetOnSuccess(e){\n if(e.detail.success) {\n e.target.reset();\n }\n }\n\n stripTrix(){\n this.trixFieldTargets.forEach(element => {\n this.removeTrailingNewlines(element.editor)\n this.removeTrailingWhitespace(element.editor)\n // When doing this as part of the form submission, Trix does not update the input element's value attribute fast enough.\n // In order to submit the stripped value, we manually update it here to fix the race condition\n element.parentElement.querySelector(\"input\").value = element.innerHTML\n })\n }\n\n submitOnReturn(e) {\n if((e.metaKey || e.ctrlKey) && e.keyCode == 13) {\n e.preventDefault();\n let form = e.target.closest(\"form\")\n this.submitForm(form)\n }\n }\n\n removeTrailingNewlines = (trixEditor) => {\n if (trixEditor.element.innerHTML.match(/<br><\\/div>$/)) {\n trixEditor.element.innerHTML = trixEditor.element.innerHTML.slice(0, -10) + \"</div>\"\n this.removeTrailingNewlines(trixEditor)\n }\n }\n\n removeTrailingWhitespace = (trixEditor) => {\n if (trixEditor.element.innerHTML.match(/&nbsp;<\\/div>$/)) {\n trixEditor.element.innerHTML = trixEditor.element.innerHTML.slice(0, -12) + \"</div>\"\n this.removeTrailingWhitespace(trixEditor)\n } else if (trixEditor.element.innerHTML.match(/&nbsp; <\\/div>$/)) {\n trixEditor.element.innerHTML = trixEditor.element.innerHTML.slice(0, -13) + \"</div>\"\n this.removeTrailingWhitespace(trixEditor)\n }\n }\n\n submitForm(form) {\n // Right now, Safari and IE don't support the requestSubmit method which is required for Turbo\n // Doing form.submit() doesn't actually fire the submit event which Turbo needs\n if (form.requestSubmit) {\n form.requestSubmit()\n } else {\n form.querySelector(\"[type=submit]\").click()\n }\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\nexport default class extends Controller {\n static targets = [ \"wrapper\"]\n static classes = [ \"hidden\" ] // necessary because stimulus-reveal will mess with the [hidden] attribute on the wrapper\n static values = {\n showEventName: String,\n hideEventName: String,\n }\n\n toggle() {\n const eventName = this.isWrapperHidden? this.showEventNameValue: this.hideEventNameValue\n if (this.isWrapperHidden) {\n this.showWrapper()\n }\n \n this.wrapperTarget.dispatchEvent(new CustomEvent(eventName))\n }\n \n get isWrapperHidden() {\n return this.wrapperTarget.classList.contains(this.hiddenClass)\n }\n \n showWrapper() {\n this.wrapperTarget.classList.remove(this.hiddenClass)\n }\n \n hideWrapper() {\n this.wrapperTarget.classList.add(this.hiddenClass)\n }\n}","import { identifierForContextKey } from \"@hotwired/stimulus-webpack-helpers\"\n\nimport BulkActionFormController from './bulk_action_form_controller'\nimport BulkActionsController from './bulk_actions_controller'\nimport ClipboardController from './clipboard_controller'\nimport FormController from './form_controller'\nimport MobileMenuController from './mobile_menu_controller'\n\nexport const controllerDefinitions = [\n [BulkActionFormController, 'bulk_action_form_controller.js'],\n [BulkActionsController, 'bulk_actions_controller.js'],\n [ClipboardController, 'clipboard_controller.js'],\n [FormController, 'form_controller.js'],\n [MobileMenuController, 'mobile_menu_controller.js'],\n].map(function(d) {\n const key = d[1]\n const controller = d[0]\n return {\n identifier: identifierForContextKey(key),\n controllerConstructor: controller\n }\n})\n","document.addEventListener(\"turbo:load\", () => {\n if (navigator.userAgent.toLocaleLowerCase().includes('electron')) {\n document.body.classList.add('electron')\n }\n})"],"names":["identifierForContextKey","key","logicalName","match","replace","Controller","connect","this","updateAvailability","updateFormAndSubmit","event","recreateIdsHiddenFields","createOrUpdateAllField","updateIds","detail","_event$detail","ids","idsValue","allValue","all","updateButtonLabel","element","classList","toggle","hiddenClass","length","label","buttonIfAllValue","buttonIfIdsValue","buttonTarget","tagName","value","textContent","removeIdsHiddenFields","createIdsHiddenFields","idsHiddenFieldTargets","forEach","field","removeChild","id","document","createElement","type","name","objectNameValue","idsFieldNameValue","appendChild","hasAllHiddenFieldTarget","allHiddenFieldTarget","createAllField","allFieldNameValue","targets","classes","values","buttonIfAll","String","buttonIfIds","Array","Boolean","objectName","idsFieldName","allFieldName","add","selectableAvailableClass","toggleSelectable","selectableValue","updateSelectedIds","updateActions","updateSelectAllCheckbox","actionTargets","actionTarget","dispatchEvent","CustomEvent","selectedIds","allSelected","selectAllOrNone","selectNone","selectAll","checkboxTargets","checkbox","checked","selectAllCheckboxTarget","selectAllLabelTarget","indeterminate","useAlternate","selectableValueChanged","selectableClass","updateToggleLabel","selectableToggleTarget","push","selectable","copy","inputTarget","sourceTarget","innerText","select","execCommand","innerHTML","setTimeout","getElementById","removeTrailingNewlines","trixEditor","slice","removeTrailingWhitespace","resetOnSuccess","e","success","target","reset","stripTrix","trixFieldTargets","editor","parentElement","querySelector","submitOnReturn","metaKey","ctrlKey","keyCode","preventDefault","form","closest","submitForm","requestSubmit","click","eventName","isWrapperHidden","showEventNameValue","hideEventNameValue","showWrapper","wrapperTarget","contains","remove","hideWrapper","showEventName","hideEventName","controllerDefinitions","BulkActionFormController","BulkActionsController","ClipboardController","FormController","MobileMenuController","map","d","controller","identifier","controllerConstructor","addEventListener","navigator","userAgent","toLocaleLowerCase","includes","body"],"mappings":"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"}
1
+ {"version":3,"file":"bullet-train.js","sources":["../../../node_modules/@hotwired/stimulus-webpack-helpers/dist/stimulus-webpack-helpers.js","../../javascript/controllers/bulk_action_form_controller.js","../../javascript/controllers/bulk_actions_controller.js","../../javascript/controllers/clipboard_controller.js","../../javascript/controllers/form_controller.js","../../../node_modules/el-transition/index.js","../../javascript/controllers/mobile_menu_controller.js","../../javascript/controllers/text_toggle_controller.js","../../javascript/controllers/index.js","../../javascript/electron/index.js"],"sourcesContent":["/*\nStimulus Webpack Helpers 1.0.0\nCopyright © 2021 Basecamp, LLC\n */\nfunction definitionsFromContext(context) {\n return context.keys()\n .map((key) => definitionForModuleWithContextAndKey(context, key))\n .filter((value) => value);\n}\nfunction definitionForModuleWithContextAndKey(context, key) {\n const identifier = identifierForContextKey(key);\n if (identifier) {\n return definitionForModuleAndIdentifier(context(key), identifier);\n }\n}\nfunction definitionForModuleAndIdentifier(module, identifier) {\n const controllerConstructor = module.default;\n if (typeof controllerConstructor == \"function\") {\n return { identifier, controllerConstructor };\n }\n}\nfunction identifierForContextKey(key) {\n const logicalName = (key.match(/^(?:\\.\\/)?(.+)(?:[_-]controller\\..+?)$/) || [])[1];\n if (logicalName) {\n return logicalName.replace(/_/g, \"-\").replace(/\\//g, \"--\");\n }\n}\n\nexport { definitionForModuleAndIdentifier, definitionForModuleWithContextAndKey, definitionsFromContext, identifierForContextKey };\n","import { Controller } from '@hotwired/stimulus'\n\nexport default class extends Controller {\n static targets = [ \"button\", \"idsHiddenField\", \"allHiddenField\" ]\n static classes = [ \"hidden\" ]\n static values = {\n buttonIfAll: String,\n buttonIfIds: String,\n ids: Array,\n all: Boolean,\n objectName: String,\n idsFieldName: String,\n allFieldName: String\n }\n\n connect() {\n this.updateAvailability()\n }\n\n updateFormAndSubmit(event) {\n this.recreateIdsHiddenFields()\n this.createOrUpdateAllField()\n return true\n }\n\n updateIds(event) {\n if (event?.detail?.ids) {\n this.idsValue = event.detail.ids\n this.allValue = event.detail.all\n }\n\n this.updateAvailability()\n this.updateButtonLabel()\n }\n\n updateAvailability() {\n this.element.classList.toggle(this.hiddenClass, this.idsValue.length === 0)\n }\n\n updateButtonLabel() {\n let label = this.buttonIfAllValue\n if (this.idsValue.length && this.allValue === false) {\n label = this.buttonIfIdsValue.replace('{num}', this.idsValue.length)\n }\n\n switch (this.buttonTarget.tagName) {\n case 'INPUT': this.buttonTarget.value = label; break;\n default: this.buttonTarget.textContent = label; break;\n }\n }\n\n recreateIdsHiddenFields() {\n this.removeIdsHiddenFields()\n this.createIdsHiddenFields()\n }\n\n removeIdsHiddenFields() {\n this.idsHiddenFieldTargets.forEach(field => {\n this.element.removeChild(field)\n })\n }\n\n createIdsHiddenFields() {\n this.idsValue.forEach(id => {\n let field = document.createElement('input')\n field.type = 'hidden'\n field.name = `${this.objectNameValue}[${this.idsFieldNameValue}][]`\n field.value = id\n this.element.appendChild(field)\n })\n }\n\n createOrUpdateAllField() {\n if (this.hasAllHiddenFieldTarget) {\n this.allHiddenFieldTarget.value = this.allValue? 'true': 'false'\n } else {\n this.createAllField()\n }\n }\n\n createAllField() {\n let field = document.createElement('input')\n field.type = 'hidden'\n field.name = `${this.objectNameValue}[${this.allFieldNameValue}]`\n field.value = this.allValue? 'true': 'false'\n this.element.appendChild(field)\n }\n}","import { Controller } from '@hotwired/stimulus'\n\nexport default class extends Controller {\n static targets = [ \"checkbox\", \"selectAllCheckbox\", \"action\", \"selectableToggle\", \"selectAllLabel\" ]\n static classes = [ \"selectableAvailable\", \"selectable\" ]\n static values = {\n selectable: Boolean\n }\n\n connect() {\n this.element.classList.add(this.selectableAvailableClass)\n }\n\n toggleSelectable() {\n this.selectableValue = !this.selectableValue\n }\n\n updateSelectedIds() {\n this.updateActions()\n this.updateSelectAllCheckbox()\n }\n\n updateActions() {\n this.actionTargets.forEach(actionTarget => {\n actionTarget.dispatchEvent(new CustomEvent('update-ids', { detail: {\n ids: this.selectedIds,\n all: this.allSelected\n }}))\n })\n }\n\n selectAllOrNone(event) {\n if (this.allSelected) {\n this.selectNone()\n } else {\n this.selectAll()\n }\n this.updateSelectAllCheckbox()\n }\n\n selectAll() {\n this.checkboxTargets.forEach(checkbox => {\n checkbox.checked = true\n })\n this.updateActions()\n }\n\n selectNone() {\n this.checkboxTargets.forEach(checkbox => {\n checkbox.checked = false\n })\n this.updateActions()\n }\n\n updateSelectAllCheckbox() {\n let checkbox = this.selectAllCheckboxTarget\n let label = this.selectAllLabelTarget\n\n if (this.allSelected) {\n checkbox.checked = true\n checkbox.indeterminate = false\n label.dispatchEvent(new CustomEvent('toggle', { detail: { useAlternate: true }} ))\n } else if (this.selectedIds.length > 0) {\n checkbox.indeterminate = true\n label.dispatchEvent(new CustomEvent('toggle', { detail: { useAlternate: false }} ))\n } else {\n checkbox.checked = false\n checkbox.indeterminate = false\n label.dispatchEvent(new CustomEvent('toggle', { detail: { useAlternate: false }} ))\n }\n }\n\n selectableValueChanged() {\n this.element.classList.toggle(this.selectableClass, this.selectableValue)\n this.updateToggleLabel()\n }\n\n updateToggleLabel() {\n this.selectableToggleTarget.dispatchEvent(new CustomEvent('toggle', { detail: { useAlternate: this.selectableValue }} ))\n }\n\n get selectedIds() {\n let ids = []\n this.checkboxTargets.forEach(checkbox => {\n if (checkbox.checked) {\n ids.push(checkbox.value)\n }\n })\n return ids\n }\n\n get allSelected() {\n return this.selectedIds.length === this.checkboxTargets.length\n }\n}","import { Controller } from \"@hotwired/stimulus\"\n\nexport default class extends Controller {\n static targets = ['source', 'input', 'button']\n\n copy() {\n this.inputTarget.value = this.sourceTarget.innerText\n this.inputTarget.select()\n document.execCommand('copy')\n this.buttonTarget.innerHTML = '<i id=\"copied\" class=\"fas fa-check w-4 h-4 block text-green-600\"></i>'\n setTimeout(function () {\n document.getElementById('copied').innerHTML = '<i class=\"far fa-copy w-4 h-4 block text-gray-600\"></i>'\n }, 1500)\n }\n}\n","import { Controller } from \"@hotwired/stimulus\"\n\n// TODO Some of this feels really specific to the conversation messages form. Should we rename this controller?\nexport default class extends Controller {\n static targets = ['trixField', 'scroll']\n\n resetOnSuccess(e){\n if(e.detail.success) {\n e.target.reset();\n }\n }\n\n stripTrix(){\n this.trixFieldTargets.forEach(element => {\n this.removeTrailingNewlines(element.editor)\n this.removeTrailingWhitespace(element.editor)\n // When doing this as part of the form submission, Trix does not update the input element's value attribute fast enough.\n // In order to submit the stripped value, we manually update it here to fix the race condition\n element.parentElement.querySelector(\"input\").value = element.innerHTML\n })\n }\n\n submitOnReturn(e) {\n if((e.metaKey || e.ctrlKey) && e.keyCode == 13) {\n e.preventDefault();\n let form = e.target.closest(\"form\")\n this.submitForm(form)\n }\n }\n\n removeTrailingNewlines = (trixEditor) => {\n if (trixEditor.element.innerHTML.match(/<br><\\/div>$/)) {\n trixEditor.element.innerHTML = trixEditor.element.innerHTML.slice(0, -10) + \"</div>\"\n this.removeTrailingNewlines(trixEditor)\n }\n }\n\n removeTrailingWhitespace = (trixEditor) => {\n if (trixEditor.element.innerHTML.match(/&nbsp;<\\/div>$/)) {\n trixEditor.element.innerHTML = trixEditor.element.innerHTML.slice(0, -12) + \"</div>\"\n this.removeTrailingWhitespace(trixEditor)\n } else if (trixEditor.element.innerHTML.match(/&nbsp; <\\/div>$/)) {\n trixEditor.element.innerHTML = trixEditor.element.innerHTML.slice(0, -13) + \"</div>\"\n this.removeTrailingWhitespace(trixEditor)\n }\n }\n\n submitForm(form) {\n // Right now, Safari and IE don't support the requestSubmit method which is required for Turbo\n // Doing form.submit() doesn't actually fire the submit event which Turbo needs\n if (form.requestSubmit) {\n form.requestSubmit()\n } else {\n form.querySelector(\"[type=submit]\").click()\n }\n }\n}\n","export async function enter(element, transitionName = null) {\n element.classList.remove('hidden')\n await transition('enter', element, transitionName)\n}\n\nexport async function leave(element, transitionName = null) {\n await transition('leave', element, transitionName)\n element.classList.add('hidden')\n}\n\nexport async function toggle(element, transitionName = null) {\n if (element.classList.contains('hidden')) {\n await enter(element, transitionName)\n } else {\n await leave(element, transitionName)\n }\n}\n\nasync function transition(direction, element, animation) {\n const dataset = element.dataset\n const animationClass = animation ? `${animation}-${direction}` : direction\n let transition = `transition${direction.charAt(0).toUpperCase() + direction.slice(1)}`\n const genesis = dataset[transition] ? dataset[transition].split(\" \") : [animationClass]\n const start = dataset[`${transition}Start`] ? dataset[`${transition}Start`].split(\" \") : [`${animationClass}-start`]\n const end = dataset[`${transition}End`] ? dataset[`${transition}End`].split(\" \") : [`${animationClass}-end`]\n\n addClasses(element, genesis)\n addClasses(element, start)\n await nextFrame()\n removeClasses(element, start)\n addClasses(element, end);\n await afterTransition(element)\n removeClasses(element, end)\n removeClasses(element, genesis)\n}\n\nfunction addClasses(element, classes) {\n element.classList.add(...classes)\n}\n\nfunction removeClasses(element, classes) {\n element.classList.remove(...classes)\n}\n\nfunction nextFrame() {\n return new Promise(resolve => {\n requestAnimationFrame(() => {\n requestAnimationFrame(resolve)\n });\n });\n}\n\nfunction afterTransition(element) {\n return new Promise(resolve => {\n // safari return string with comma separate values\n const computedDuration = getComputedStyle(element).transitionDuration.split(\",\")[0]\n const duration = Number(computedDuration.replace('s', '')) * 1000;\n setTimeout(() => {\n resolve()\n }, duration)\n });\n}","import { Controller } from \"@hotwired/stimulus\"\nimport { enter, leave } from \"el-transition\"\n\nexport default class extends Controller {\n static targets = [ \"wrapper\", \"revealable\"]\n static classes = [ \"hidden\" ] // necessary because we're always hiding the mobile menu on larger screens and this is the class used for only mobile screen sizes\n \n open() {\n this.showWrapper()\n this.revealableTargets.forEach(revealableTarget => {\n enter(revealableTarget)\n })\n }\n \n close() {\n Promise.all(\n this.revealableTargets.map(revealableTarget => {\n return leave(revealableTarget)\n })\n ).then(() => {\n this.hideWrapper()\n })\n \n }\n \n showWrapper() {\n this.wrapperTarget.classList.remove(this.hiddenClass)\n }\n \n hideWrapper() {\n this.wrapperTarget.classList.add(this.hiddenClass)\n }\n}","import { Controller } from \"@hotwired/stimulus\"\n\nexport default class extends Controller {\n static values = {\n label: String,\n labelAlternate: String,\n useAlternate: Boolean,\n }\n\n connect() {\n this.updateLabel()\n }\n\n toggle(event) {\n if (undefined !== event?.detail?.useAlternate) {\n this.useAlternateValue = event.detail.useAlternate\n } else {\n this.useAlternateValue = !this.useAlternateValue\n }\n }\n\n useAlternateValueChanged() {\n this.updateLabel()\n }\n\n updateLabel() {\n if (!this.hasLabelValue || !this.hasLabelAlternateValue || !this.hasUseAlternateValue) {\n return\n }\n\n this.element.textContent = this.useAlternateValue === true ? this.labelAlternateValue : this.labelValue\n }\n}\n","import { identifierForContextKey } from \"@hotwired/stimulus-webpack-helpers\"\n\nimport BulkActionFormController from './bulk_action_form_controller'\nimport BulkActionsController from './bulk_actions_controller'\nimport ClipboardController from './clipboard_controller'\nimport FormController from './form_controller'\nimport MobileMenuController from './mobile_menu_controller'\nimport TextToggleController from './text_toggle_controller'\n\nexport const controllerDefinitions = [\n [BulkActionFormController, 'bulk_action_form_controller.js'],\n [BulkActionsController, 'bulk_actions_controller.js'],\n [ClipboardController, 'clipboard_controller.js'],\n [FormController, 'form_controller.js'],\n [MobileMenuController, 'mobile_menu_controller.js'],\n [TextToggleController, 'text_toggle_controller.js'],\n].map(function(d) {\n const key = d[1]\n const controller = d[0]\n return {\n identifier: identifierForContextKey(key),\n controllerConstructor: controller\n }\n})\n","document.addEventListener(\"turbo:load\", () => {\n if (navigator.userAgent.toLocaleLowerCase().includes('electron')) {\n document.body.classList.add('electron')\n }\n})"],"names":["identifierForContextKey","key","logicalName","match","replace","_class","connect","this","updateAvailability","updateFormAndSubmit","event","recreateIdsHiddenFields","createOrUpdateAllField","updateIds","_event$detail","detail","ids","idsValue","allValue","all","updateButtonLabel","element","classList","toggle","hiddenClass","length","label","buttonIfAllValue","buttonIfIdsValue","buttonTarget","tagName","value","textContent","removeIdsHiddenFields","createIdsHiddenFields","idsHiddenFieldTargets","forEach","field","removeChild","id","document","createElement","type","name","objectNameValue","idsFieldNameValue","appendChild","hasAllHiddenFieldTarget","allHiddenFieldTarget","createAllField","allFieldNameValue","targets","classes","values","buttonIfAll","String","buttonIfIds","Array","Boolean","objectName","idsFieldName","allFieldName","Controller","add","selectableAvailableClass","toggleSelectable","selectableValue","updateSelectedIds","updateActions","updateSelectAllCheckbox","actionTargets","actionTarget","dispatchEvent","selectedIds","allSelected","selectAllOrNone","selectNone","selectAll","checkboxTargets","checkbox","checked","selectAllCheckboxTarget","selectAllLabelTarget","indeterminate","CustomEvent","useAlternate","selectableValueChanged","selectableClass","updateToggleLabel","selectableToggleTarget","push","selectable","copy","inputTarget","sourceTarget","innerText","select","execCommand","innerHTML","setTimeout","getElementById","removeTrailingNewlines","trixEditor","slice","removeTrailingWhitespace","resetOnSuccess","e","success","target","reset","stripTrix","trixFieldTargets","editor","parentElement","querySelector","submitOnReturn","metaKey","ctrlKey","keyCode","preventDefault","form","closest","submitForm","requestSubmit","click","async","transition","direction","animation","dataset","animationClass","charAt","toUpperCase","genesis","split","start","end","addClasses","Promise","resolve","requestAnimationFrame","removeClasses","computedDuration","getComputedStyle","transitionDuration","duration","Number","afterTransition","remove","open","showWrapper","revealableTargets","revealableTarget","transitionName","enter","close","map","leave","then","hideWrapper","wrapperTarget","updateLabel","useAlternateValue","undefined","useAlternateValueChanged","hasLabelValue","hasLabelAlternateValue","hasUseAlternateValue","labelAlternateValue","labelValue","labelAlternate","controllerDefinitions","BulkActionFormController","BulkActionsController","ClipboardController","FormController","MobileMenuController","TextToggleController","d","controller","identifier","controllerConstructor","addEventListener","navigator","userAgent","toLocaleLowerCase","includes","body"],"mappings":"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"}
@@ -60,17 +60,24 @@ module Account::Invitations::ControllerBase
60
60
  # assume the user needs to create an account.
61
61
  # this is not the default for devise, but a sensible default here.
62
62
  redirect_to new_user_registration_path
63
- elsif @invitation
64
- @team = @invitation.team
65
- if @invitation.is_for?(current_user) || request.post?
66
- @invitation.accept_for(current_user)
67
- redirect_to account_dashboard_path, notice: I18n.t("invitations.notifications.welcome", team_name: @team.name)
63
+
64
+ # session[:invitation_uuid] should only be present if the user is registering for the first time.
65
+ elsif (@invitation = Invitation.find_by(uuid: session[:invitation_uuid] || params[:id]))
66
+ session.delete(:invitation_uuid) if session[:invitation_uuid].present?
67
+
68
+ if @invitation
69
+ @team = @invitation.team
70
+ if @invitation.is_for?(current_user) || request.post?
71
+ @invitation.accept_for(current_user)
72
+ redirect_to account_dashboard_path, notice: I18n.t("invitations.notifications.welcome", team_name: @team.name)
73
+ else
74
+ redirect_to account_invitation_path(@invitation.uuid)
75
+ end
68
76
  else
69
77
  redirect_to account_invitation_path(@invitation.uuid)
70
78
  end
71
79
  else
72
80
  redirect_to account_dashboard_path
73
-
74
81
  end
75
82
  end
76
83
 
@@ -33,8 +33,7 @@ module Controllers::Base
33
33
  end
34
34
  else
35
35
  respond_to do |format|
36
- # TODO we do this for now because it ensures `current_team` doesn't remain set in an invalid state.
37
- format.html { redirect_to [:account, current_user.teams.first], alert: exception.message }
36
+ format.html { redirect_to account_teams_url, alert: exception.message }
38
37
  end
39
38
  end
40
39
  end
@@ -19,14 +19,11 @@ module Registrations::ControllerBase
19
19
 
20
20
  # if current_user is defined, that means they were successful registering.
21
21
  if current_user
22
-
23
- # TODO i think this might be redundant. we've added a hook into `session["user_return_to"]` in the
24
- # `invitations#accept` action and that might be enough to get them where they're supposed to be after
25
- # either creating a new account or signing into an existing account.
26
- handle_outstanding_invitation
27
-
28
22
  # if the user doesn't have a team at this point, create one.
29
- unless current_user.teams.any?
23
+ # If the user is accepting an invitation, then the user's current_team is populated
24
+ # with the information attached to their invitation via `@invitation.accept_for` later on,
25
+ # so we don't have to create a default team for them here.
26
+ unless current_user.teams.any? || session[:invitation_uuid].present?
30
27
  current_user.create_default_team
31
28
  end
32
29
 
@@ -1,12 +1,6 @@
1
1
  module Sessions::ControllerBase
2
2
  extend ActiveSupport::Concern
3
3
 
4
- included do
5
- # TODO I'm not sure why the sign-in page started throwing a `ActionController::InvalidAuthenticityToken`. I'm doing
6
- # this as a temporary workaround, but this shouldn't be here long-term.
7
- skip_before_action :verify_authenticity_token, only: [:create]
8
- end
9
-
10
4
  def pre_otp
11
5
  if (@email = params["user"]["email"].downcase.strip.presence)
12
6
  @user = User.find_by(email: @email)
@@ -27,10 +27,6 @@ module Account::FormsHelper
27
27
  string.present? ? string : nil
28
28
  end
29
29
 
30
- def id_for(form, method)
31
- [form.object.class.name, form.index, method].compact.join("_").underscore
32
- end
33
-
34
30
  def model_key(form)
35
31
  form.object.class.name.pluralize.underscore
36
32
  end
@@ -1,17 +1,2 @@
1
1
  module InvitationsHelper
2
- def handle_outstanding_invitation
3
- # was this user registering to claim an invitation?
4
- if session[:invitation_uuid].present?
5
-
6
- # try to find the invitation, if it still exists.
7
- invitation = Invitation.find_by_uuid(session[:invitation_uuid])
8
-
9
- # if the invitation was found, claim it for this user.
10
- invitation&.accept_for(current_user)
11
-
12
- # remove the uuid from the session.
13
- session.delete(:invitation_uuid)
14
-
15
- end
16
- end
17
2
  end
@@ -5,6 +5,7 @@ import BulkActionsController from './bulk_actions_controller'
5
5
  import ClipboardController from './clipboard_controller'
6
6
  import FormController from './form_controller'
7
7
  import MobileMenuController from './mobile_menu_controller'
8
+ import TextToggleController from './text_toggle_controller'
8
9
 
9
10
  export const controllerDefinitions = [
10
11
  [BulkActionFormController, 'bulk_action_form_controller.js'],
@@ -12,6 +13,7 @@ export const controllerDefinitions = [
12
13
  [ClipboardController, 'clipboard_controller.js'],
13
14
  [FormController, 'form_controller.js'],
14
15
  [MobileMenuController, 'mobile_menu_controller.js'],
16
+ [TextToggleController, 'text_toggle_controller.js'],
15
17
  ].map(function(d) {
16
18
  const key = d[1]
17
19
  const controller = d[0]
@@ -1,24 +1,26 @@
1
1
  import { Controller } from "@hotwired/stimulus"
2
+ import { enter, leave } from "el-transition"
2
3
 
3
4
  export default class extends Controller {
4
- static targets = [ "wrapper"]
5
- static classes = [ "hidden" ] // necessary because stimulus-reveal will mess with the [hidden] attribute on the wrapper
6
- static values = {
7
- showEventName: String,
8
- hideEventName: String,
9
- }
10
-
11
- toggle() {
12
- const eventName = this.isWrapperHidden? this.showEventNameValue: this.hideEventNameValue
13
- if (this.isWrapperHidden) {
14
- this.showWrapper()
15
- }
16
-
17
- this.wrapperTarget.dispatchEvent(new CustomEvent(eventName))
5
+ static targets = [ "wrapper", "revealable"]
6
+ static classes = [ "hidden" ] // necessary because we're always hiding the mobile menu on larger screens and this is the class used for only mobile screen sizes
7
+
8
+ open() {
9
+ this.showWrapper()
10
+ this.revealableTargets.forEach(revealableTarget => {
11
+ enter(revealableTarget)
12
+ })
18
13
  }
19
14
 
20
- get isWrapperHidden() {
21
- return this.wrapperTarget.classList.contains(this.hiddenClass)
15
+ close() {
16
+ Promise.all(
17
+ this.revealableTargets.map(revealableTarget => {
18
+ return leave(revealableTarget)
19
+ })
20
+ ).then(() => {
21
+ this.hideWrapper()
22
+ })
23
+
22
24
  }
23
25
 
24
26
  showWrapper() {
@@ -0,0 +1,33 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ static values = {
5
+ label: String,
6
+ labelAlternate: String,
7
+ useAlternate: Boolean,
8
+ }
9
+
10
+ connect() {
11
+ this.updateLabel()
12
+ }
13
+
14
+ toggle(event) {
15
+ if (undefined !== event?.detail?.useAlternate) {
16
+ this.useAlternateValue = event.detail.useAlternate
17
+ } else {
18
+ this.useAlternateValue = !this.useAlternateValue
19
+ }
20
+ }
21
+
22
+ useAlternateValueChanged() {
23
+ this.updateLabel()
24
+ }
25
+
26
+ updateLabel() {
27
+ if (!this.hasLabelValue || !this.hasLabelAlternateValue || !this.hasUseAlternateValue) {
28
+ return
29
+ }
30
+
31
+ this.element.textContent = this.useAlternateValue === true ? this.labelAlternateValue : this.labelValue
32
+ }
33
+ }
@@ -1,3 +1,5 @@
1
+ require "rake"
2
+
1
3
  module Records::Base
2
4
  extend ActiveSupport::Concern
3
5
 
@@ -65,4 +67,12 @@ module Records::Base
65
67
  # parent_key = model_name.reflect_on_all_associations(:belongs_to).first.name
66
68
  raise "You're trying to use a feature that requires #{model_name} to have a `collection` method defined that returns the Active Record association that this model belongs to within its parent object."
67
69
  end
70
+
71
+ def seeding?
72
+ rake_tasks = ObjectSpace.each_object(Rake::Task)
73
+ return false if rake_tasks.count.zero?
74
+
75
+ db_seed_task = rake_tasks.find { |task| task.name.match?(/^db:seed$/) }
76
+ db_seed_task.already_invoked
77
+ end
68
78
  end
@@ -37,11 +37,8 @@ module Users::Base
37
37
  after_update :set_teams_time_zone
38
38
  end
39
39
 
40
- # TODO we need to update this to some sort of invalid email address or something
41
- # people know to ignore. it would be a security problem to have this pointing
42
- # at anybody's real email address.
43
40
  def email_is_oauth_placeholder?
44
- !!email.match(/noreply\+.*@bullettrain.co/)
41
+ !!email.match(/noreply@\h{32}\.example\.com/)
45
42
  end
46
43
 
47
44
  def label_string
@@ -42,12 +42,12 @@
42
42
  <%= form.submit t('global.buttons.sign_in'), class: 'button full' %>
43
43
  </div>
44
44
 
45
- <div class="flex items-center">
46
- <input id="remember_me" name="remember_me" type="checkbox" class="h-4 w-4 text-blue focus:ring-blue-dark border-gray-300 rounded">
47
- <label for="remember_me" class="ml-2 block">
48
- Remember me
49
- </label>
50
- </div>
45
+ <% if devise_mapping.rememberable? %>
46
+ <div class="flex items-center">
47
+ <%= form.check_box :remember_me, class: "h-4 w-4 text-blue focus:ring-blue-dark border-gray-300 rounded" %>
48
+ <%= form.label :remember_me, class: "ml-2 block" %>
49
+ </div>
50
+ <% end %>
51
51
  <% end %>
52
52
  <% end %>
53
53
  <% end %>
@@ -37,8 +37,6 @@
37
37
  <div class="h-screen md:h-auto overflow-hidden md:rounded-lg flex shadow"
38
38
  data-controller="mobile-menu"
39
39
  data-mobile-menu-hidden-class="hidden"
40
- data-mobile-menu-show-event-name-value="mobile-menu:show"
41
- data-mobile-menu-hide-event-name-value="mobile-menu:hide"
42
40
  >
43
41
 
44
42
  <% menu = capture do %>
@@ -47,7 +45,7 @@
47
45
 
48
46
  <div class="lg:hidden absolute right-0">
49
47
  <button class="ml-1 flex items-center justify-center h-10 w-10 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
50
- data-action="reveal#hide"
48
+ data-action="mobile-menu#close"
51
49
  >
52
50
  <span class="sr-only">Close Application Menu</span>
53
51
  <svg class="h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
@@ -265,20 +263,12 @@
265
263
 
266
264
  <div class="lg:hidden hidden"
267
265
  data-mobile-menu-target="wrapper"
268
-
269
- data-controller="reveal"
270
- data-reveal-away-value="true"
271
- data-reveal-hide-keys-value="escape"
272
-
273
- data-action="mobile-menu:show->reveal#show mobile-menu:hide->reveal#hide mobile-menu-toggle->reveal#toggle reveal:hidden->mobile-menu#hideWrapper"
274
266
  >
275
267
  <div class="fixed inset-0 flex z-40">
276
268
  <button
277
- data-action="reveal#hide"
278
-
279
- hidden
280
- data-reveal
281
- data-transition
269
+ data-mobile-menu-target="revealable"
270
+ data-action="mobile-menu#close"
271
+
282
272
  data-transition-enter="transition-opacity ease-linear duration-200"
283
273
  data-transition-enter-start="opacity-0"
284
274
  data-transition-enter-end="opacity-100"
@@ -291,9 +281,8 @@
291
281
  <div class="absolute inset-0 bg-light-gradient opacity-75"></div>
292
282
  </button>
293
283
  <div
294
- hidden
295
- data-reveal
296
- data-transition
284
+ data-mobile-menu-target="revealable"
285
+
297
286
  data-transition-enter="transition ease-in-out duration-200 transform"
298
287
  data-transition-enter-start="-translate-x-full"
299
288
  data-transition-enter-end="translate-x-0"
@@ -319,7 +308,7 @@
319
308
  <main class="flex-1 relative z-0 overflow-y-auto focus:outline-none" tabindex="0">
320
309
 
321
310
  <button class="lg:hidden h-12 w-12 ml-1 flex-none inline-flex items-center justify-center rounded-md text-gray-500 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue"
322
- data-action="mobile-menu#toggle"
311
+ data-action="mobile-menu#open"
323
312
  >
324
313
  <span class="sr-only">Open Application Menu</span>
325
314
  <svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
@@ -1,6 +1,6 @@
1
1
  # Examples for the `super_select` Field Partial
2
2
 
3
- The `super_select` partial provides a wonderful default UI (in contrast to the vanilla browser experience for this, which is horrible) with optional search and multi-select functionality out-of-the-box. It invokes the [Select2](https://select2.org) library to provide you these features.
3
+ The `super_select` partial provides a wonderful default UI (in contrast to the vanilla browser experience for this, which is horrible) with optional search and multi-select functionality out-of-the-box. It invokes the [Select2][select2] library to provide you these features.
4
4
 
5
5
  ## Define Available Buttons via Localization Yaml
6
6
 
@@ -66,4 +66,62 @@ Here is an example allowing a new option to be entered by the user:
66
66
  other_options: {accepts_new: true} %>
67
67
  </code></pre>
68
68
 
69
- Note: this will set the option `value` (which will be submitted to the server) to the entered text.
69
+ Note: this will set the option `value` (which will be submitted to the server) to the entered text.
70
+ ## Events
71
+
72
+ All events dispatched from the `super_select` partial are [Select2's jQuery events][select2_events] re-dispatched as native DOM events with the following caveats:
73
+
74
+ 1. The native DOM event name is pre-pended with `$`
75
+ 2. The original jQuery event is passed through under `event.detail.event`
76
+
77
+ | Select2 event name | DOM event name |
78
+ |---------------------|----------------------|
79
+ | change | $change |
80
+ | select2:closing | $select2:closing |
81
+ | select2:close | $select2:close |
82
+ | select2:opening | $select2:opening |
83
+ | select2:open | $select2:open |
84
+ | select2:selecting | $select2:selecting |
85
+ | select2:select | $select2:select |
86
+ | select2:unselecting | $select2:unselecting |
87
+ | select2:unselect | $select2:unselect |
88
+ | select2:clearing | $select2:clearing |
89
+ | select2:clear | $select2:clear |
90
+
91
+ For example, catching the `$change` events in a parent `dependent-form-fields` Stimulus controller with a single `updateDependentFields` method would look like this:
92
+
93
+ <pre><code>&lt;div data-controller="dependent-form-fields"&gt;
94
+ &lt;div data-action="$change->dependent-form-fields#updateDependentFields"&gt;
95
+ <%= render 'shared/fields/super_select', form: form, method: :category_id,
96
+ choices: Category.all.map { |category| [category.label_string, category.id] } %>
97
+ &lt;/div&gt;
98
+ &lt;div&gt;
99
+ &lt;!-- This is the dependent field that would get updated when the previous one changes --&gt;
100
+ <%= render 'shared/fields/super_select', form: form, method: :category_id,
101
+ choices: Category.all.map { |category| [category.label_string, category.id] },
102
+ html_options: { data: { 'dependent-form-fields-target': 'dependentField' }} %>
103
+ &lt;/div&gt;
104
+ &lt;/div&gt;</code></pre>
105
+
106
+ And this is an example of what the `dependent-form-fields` Stimulus controller would look like.
107
+
108
+ <pre><code>
109
+ // dependent_form_fields_controller.js
110
+ import { Controller } from "stimulus"
111
+
112
+ export default class extends Controller {
113
+ static targets = [ "dependentField" ]
114
+
115
+ updateDependentFields(event) {
116
+ const originalSelect2Event = event.detail.event
117
+ console.log(`catching event ${event.type}`, originalSelect2Event)
118
+
119
+ this.dependentFieldTargets.forEach((dependentField) => {
120
+ // update dependentField based on value found in originalSelect2Event.target.value
121
+ })
122
+ }
123
+ }
124
+ </code></pre>
125
+
126
+ [select2]: https://select2.org
127
+ [select2_events]: https://select2.org/programmatic-control/events
@@ -109,23 +109,30 @@ Certain form field partials like `buttons` and `super_select` can also have thei
109
109
 
110
110
  ## Available Field Partials
111
111
 
112
- | Field Partial | Multiple Values? | Assignment Helpers | JavaScript Library | Description | Commercial License Required |
113
- | --- | --- | --- | --- | --- | --- |
114
- | `boolean` | | `assign_boolean` | | | |
115
- | [`buttons`](/docs/field-partials/buttons.md) | Optionally | `assign_checkboxes` | | | |
116
- | `cloudinary_image` | | | | | |
117
- | `color_picker` | | | [pickr](https://simonwep.github.io/pickr/) | | |
118
- | `date_and_time_field` | | `assign_date_and_time` | [Date Range Picker](https://www.daterangepicker.com) | | |
119
- | `date_field` | | `assign_date` | [Date Range Picker](https://www.daterangepicker.com) | | |
120
- | `email_field` | | | | | |
121
- | `file_field` | | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | | |
122
- | `options` | Optionally | `assign_checkboxes` | | | |
123
- | `password_field` | | | | | |
124
- | `phone_field` | | | [International Telephone Input](https://intl-tel-input.com) | Ensures telephone numbers are in a format that can be used by providers like Twilio. | |
125
- | [`super_select`](/docs/field-partials/super-select.md) | Optionally | `assign_select_options` | [Select2](https://select2.org) | Provides powerful option search, AJAX search, and multi-select functionality. | |
126
- | `text_area` | | | | | |
127
- | `text_field` | | | | | |
128
- | `trix_editor` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. | |
112
+ | Field Partial | Data Type | Multiple Values? | Assignment Helpers | JavaScript Library | Description | Commercial License Required |
113
+ | --- | --- | --- | --- | --- | --- | --- |
114
+ | `boolean` | `boolean` | `assign_boolean` | | | |
115
+ | [`buttons`](/docs/field-partials/buttons.md) | `string` | Optionally | `assign_checkboxes` | | | |
116
+ | `cloudinary_image` | `string` | | | | | |
117
+ | `color_picker` | | | | [pickr](https://simonwep.github.io/pickr/) | | |
118
+ | `date_and_time_field` | `datetime` | | `assign_date_and_time` | [Date Range Picker](https://www.daterangepicker.com) | | |
119
+ | `date_field` | `date` | | `assign_date` | [Date Range Picker](https://www.daterangepicker.com) | | |
120
+ | `email_field` | `string` | | | | | |
121
+ | `file_field` | `attachment` | | [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html) | | |
122
+ | `options` | `string` | Optionally | `assign_checkboxes` | | | |
123
+ | `password_field` | `string` | | | | | |
124
+ | `phone_field` | `string` | | | [International Telephone Input](https://intl-tel-input.com) | Ensures telephone numbers are in a format that can be used by providers like Twilio. | |
125
+ | [`super_select`](/docs/field-partials/super-select.md) | `string` | Optionally | `assign_select_options` | [Select2](https://select2.org) | Provides powerful option search, AJAX search, and multi-select functionality. | |
126
+ | `text_area` | `text` | | | | | |
127
+ | `text_field` | `string` | | | | | |
128
+ | `trix_editor` | `text` | | | [Trix](https://github.com/basecamp/trix) | Basic HTML-powered formatting features and support for at-mentions amongst team members. | |
129
+
130
+ ## A Note On Data Types
131
+ Set the data type to `jsonb` whenever passing the `multiple` option to a new attribute.
132
+ ```
133
+ > rails generate model Project team:references multiple_buttons:jsonb
134
+ > bin/super-scaffold crud Project Team multiple_buttons:buttons{multiple}
135
+ ```
129
136
 
130
137
  ## Additional Field Partials Documentation
131
138
  - [`buttons`](/docs/field-partials/buttons.md)
data/docs/index.md CHANGED
@@ -27,6 +27,7 @@
27
27
  - [Roles and Permissions](/docs/permissions.md)
28
28
  - [Onboarding](/docs/onboarding.md)
29
29
  - [Namespacing](/docs/namespacing.md)
30
+ - [Invitation Only Mode](/docs/invitation_only.md)
30
31
 
31
32
  ## UI
32
33
  - [Field Partials](/docs/field-partials.md)
@@ -0,0 +1,13 @@
1
+ # Invitation Only Mode
2
+
3
+ By providing a randomized string to `ENV["INVITATION_KEYS"]`, you can enable invitation only mode on your Bullet Train application. This will set up your app so that users cannot register to your website unless they have access to a specific link, or if they are invited via email.
4
+
5
+ `config/application.yml`:
6
+ ```ruby
7
+ INVITATION_KEYS: ofr9h5h9ghzeodh
8
+ ```
9
+
10
+ In this case, the user will be able to register their own account by accessing the following link:
11
+ ```
12
+ http://localhost:3000/invitations?key=ofr9h5h9ghzeodh
13
+ ```
@@ -34,7 +34,7 @@ rails g model Message subject:string
34
34
  rails g model Comment content:text
35
35
  ```
36
36
 
37
- Note that in this specific approach we don't need a `team:references` on `Message` and `Comment`. That's because in this approach there are no controllers specific to `Message` and `Comment`, so all permissions are being inforced by checking the ownership of `Entry`. (That's not to say it would be wrong to add them for other reasons, we're just keeping it as simple as possible here.)
37
+ Note that in this specific approach we don't need a `team:references` on `Message` and `Comment`. That's because in this approach there are no controllers specific to `Message` and `Comment`, so all permissions are being enforced by checking the ownership of `Entry`. (That's not to say it would be wrong to add them for other reasons, we're just keeping it as simple as possible here.)
38
38
 
39
39
  ### 2. Super Scaffolding for `Entry`
40
40
 
@@ -59,7 +59,33 @@ fields: &fields
59
59
  "Comment": Comment
60
60
  ```
61
61
 
62
- <small>TODO Insert a live example of what `shared/fields/buttons` looks like with these options passed in.</small>
62
+ We will add this block below in the next step on our `new.html.erb` page so you don't have to worry about it now, but with the options above in place, our buttons partial will now allow your users to select either a `Message` or a `Comment` before creating the `Entry` itself:
63
+
64
+ ```
65
+ <% with_field_settings form: form do %>
66
+ <%= render 'shared/fields/buttons', method: :entryable_type, html_options: {autofocus: true} %>
67
+ <%# 🚅 super scaffolding will insert new fields above this line. %>
68
+ <% end %>
69
+ ```
70
+
71
+ This will produce the following HTML:
72
+ ```
73
+ <div>
74
+ <label class="btn-toggle" data-controller="fields--button-toggle">
75
+ <input data-fields--button-toggle-target="shadowField" type="radio" value="Message" name="entry[entryable_type]" id="entry_entryable_type_message">
76
+ <button type="button" class="button-alternative mb-1.5 mr-1" data-action="fields--button-toggle#clickShadowField">
77
+ Message
78
+ </button>
79
+ </label>
80
+ <label class="btn-toggle" data-controller="fields--button-toggle">
81
+ <input data-fields--button-toggle-target="shadowField" type="radio" value="Comment" name="entry[entryable_type]" id="entry_entryable_type_comment">
82
+ <button type="button" class="button-alternative mb-1.5 mr-1" data-action="fields--button-toggle#clickShadowField">
83
+ Comment
84
+ </button>
85
+ </label>
86
+ </div>
87
+ ```
88
+
63
89
 
64
90
  ### 4. Add Our First Step to `new.html.erb`
65
91
 
@@ -234,9 +260,11 @@ We add this _below_ the Super Scaffolding hook because we want any additional fi
234
260
 
235
261
  ### 10. Add Attributes of the Concrete Children to `show.html.erb`
236
262
 
237
- Under the Super Scaffolding hook in `app/views/account/entries/show.html.erb`, add the following:
263
+ Add the following in `app/views/account/entries/show.html.erb` under the Super Scaffolding hook shown in the example code below:
238
264
 
239
265
  ```
266
+ <%# 🚅 super scaffolding will insert new fields above this line. %>
267
+
240
268
  <% with_attribute_settings object: @entry.entryable, strategy: :label do %>
241
269
  <% case @entry.entryable %>
242
270
  <% when Message %>
@@ -1,3 +1,3 @@
1
1
  module BulletTrain
2
- VERSION = "1.0.96"
2
+ VERSION = "1.0.99"
3
3
  end
data/lib/bullet_train.rb CHANGED
@@ -129,3 +129,7 @@ end
129
129
  def multiple_locales?
130
130
  @multiple_locales ||= I18n.available_locales.many?
131
131
  end
132
+
133
+ def silence_logs?
134
+ ENV["SILENCE_LOGS"].present?
135
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet_train
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.96
4
+ version: 1.0.99
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-25 00:00:00.000000000 Z
11
+ date: 2022-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard
@@ -477,6 +477,7 @@ files:
477
477
  - app/javascript/controllers/form_controller.js
478
478
  - app/javascript/controllers/index.js
479
479
  - app/javascript/controllers/mobile_menu_controller.js
480
+ - app/javascript/controllers/text_toggle_controller.js
480
481
  - app/javascript/electron/index.js
481
482
  - app/javascript/index.js
482
483
  - app/mailers/concerns/mailers/base.rb
@@ -622,6 +623,7 @@ files:
622
623
  - docs/i18n.md
623
624
  - docs/index.md
624
625
  - docs/indirection.md
626
+ - docs/invitation_only.md
625
627
  - docs/javascript.md
626
628
  - docs/modeling.md
627
629
  - docs/namespacing.md