[
  {
    "path": ".github/workflows/main.yml",
    "content": "name: Ruby\n\non:\n  push:\n    branches:\n      - main\n\n  pull_request:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    name: Ruby ${{ matrix.ruby }}\n    strategy:\n      matrix:\n        ruby:\n          - '3.3.4'\n\n    steps:\n    - uses: actions/checkout@v4\n    - name: Set up Ruby\n      uses: ruby/setup-ruby@v1\n      with:\n        ruby-version: ${{ matrix.ruby }}\n        bundler-cache: true\n    - name: Run the default task\n      run: bundle exec rake\n"
  },
  {
    "path": ".gitignore",
    "content": "/.bundle/\n/.yardoc\n/_yardoc/\n/coverage/\n/doc/\n/pkg/\n/spec/reports/\n/tmp/\n/.idea/\n/node_modules/\n/test_app/storage/*.sqlite3\n/test_app/storage/*.sqlite3*\n/test_app/log/\n/test_app/tmp/\n/*.gem\n\n"
  },
  {
    "path": ".rubocop.yml",
    "content": "inherit_gem:\n  rubocop-rails-omakase: rubocop.yml\n\nAllCops:\n  TargetRubyVersion: 3.0\n\nStyle/StringLiterals:\n  EnforcedStyle: double_quotes\n\nStyle/StringLiteralsInInterpolation:\n  EnforcedStyle: double_quotes\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [Unreleased]\n\n## [0.2.0] - October 17, 2024\n\n- Show running jobs\n- Add charts\n- Add auto-refresh\n- Add number of current processes and recurring tasks to navbar\n- Fix dark mode not switching for the first time\n\n## [0.1.1] - October 7, 2024\n\n- Replace OpenStruct with a Hash to avoid including the `ostruct` gem\n\n## [0.1.0] - October 7, 2024\n\n- Initial release\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official email address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\n[INSERT CONTACT METHOD].\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][Mozilla CoC].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at\n[https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n[Mozilla CoC]: https://github.com/mozilla/diversity\n[FAQ]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\nsource \"https://rubygems.org\"\n\n# Specify your gem's dependencies in solid_queue_dashboard.gemspec\ngemspec\n\ngem \"vite_ruby\", \"~> 3.8\"\ngem \"rake\", \"~> 13.2\"\ngem \"minitest\", \"~> 5.25\"\ngem \"rubocop\", \"~> 1.66\"\ngem \"rubocop-rails-omakase\", \"~> 1.0\"\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2024 Andrew Kodkod\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Procfile.dev",
    "content": "test_app:   cd test_app && ./bin/rails server -p 3000\njobs:       cd test_app && ./bin/jobs\ntailwind:   bun watch\n"
  },
  {
    "path": "README.md",
    "content": "# Solid Queue Dashboard <sup>BETA</sup>\n\n<p align=\"center\">\n  <a href=\"https://github.com/akodkod/solid-queue-dashboard#gh-light-mode-only\">\n    <img src=\"https://github.com/user-attachments/assets/55aa4a3c-da51-471b-8f58-0cf1f9a1f8da\" alt=\"Solid Queue Dashboard Light Mode\">\n  </a>\n  <a href=\"https://github.com/akodkod/solid-queue-dashboard#gh-dark-mode-only\">\n    <img src=\"https://github.com/user-attachments/assets/645558cb-c20f-4d4b-9697-55282710ea6c\" alt=\"Solid Queue Dashboard Dark Mode\">\n  </a>\n\n  _👋 I'm Available for Hire → [kodkod.me](https://kodkod.me)_\n</p>\n\n## Features\n- 🎨 Beautiful UI\n- 🧠 Smart status detection\n- 📊 Track failure rates\n- 💀 Find dead processes\n- 📜 View execution history\n- 🔍 Filter options\n- 🔄 Retry jobs from the UI\n- 🥬 Auto-refresh\n- 📈 Add charts\n- 🐒 No monkey patching\n- 💈 TailwindCSS\n\n## Roadmap\n- 🚀 Manually trigger jobs\n- ⏹️ Cancel long jobs (if possible)\n- 📊 More statistics and insights\n- 🔎 Search feature\n- 🔢 Sorting options\n- 🏗️ Add tests\n\n## Installation\n\nTo install, run this command in your terminal:\n\n```bash\nbundle add solid_queue_dashboard\n```\n\nOr add this line to your `Gemfile`:\n\n```bash\ngem \"solid_queue_dashboard\", \"~> 0.2.0\"\n```\n\nAdd this line to `routes.rb`:\n\n```ruby\nmount SolidQueueDashboard::Engine, at: \"/solid-queue\"\n```\n\n**IMPORTANT: Protect your SolidQueueDashboard with authentication to prevent unauthorized access.**\n\nFor example, if using Devise:\n\n```ruby\nRails.application.routes.draw do\n  authenticate :current_admin do\n    mount SolidQueueDashboard::Engine, at: \"/solid-queue\"\n  end\nend\n```\n\n## Contributing\n\nAfter cloning the repo, run:\n\n```\n./bin/setup\n./bin/setup-test-app\n```\n\nTo run the test application:\n\n```\ngem install foreman\n./bin/dev\n```\n\nTo generate dummy data:\n\n```\ncd test_app\nrails jobs:generate_dummy_data\n```\n\n## License\n\nThis gem is open source under the [MIT License](http://opensource.org/licenses/MIT).\n\n---\n\n_Made with love by Ukrainians 💙💛_  \n_[Help Ukraine](https://u24.gov.ua/)_\n\n"
  },
  {
    "path": "Rakefile",
    "content": "# frozen_string_literal: true\n\nrequire \"bundler/gem_tasks\"\nrequire \"minitest/test_task\"\n\nMinitest::TestTask.create\n\nrequire \"rubocop/rake_task\"\n\nRuboCop::RakeTask.new\n\ntask default: %i[test rubocop]\n"
  },
  {
    "path": "app/assets/javascripts/solid_queue_dashboard/alpine.js",
    "content": "(()=>{var rt=!1,nt=!1,U=[],it=-1;function qt(e){Cn(e)}function Cn(e){U.includes(e)||U.push(e),Tn()}function Ee(e){let t=U.indexOf(e);t!==-1&&t>it&&U.splice(t,1)}function Tn(){!nt&&!rt&&(rt=!0,queueMicrotask(Rn))}function Rn(){rt=!1,nt=!0;for(let e=0;e<U.length;e++)U[e](),it=e;U.length=0,it=-1,nt=!1}var R,D,L,st,ot=!0;function Ut(e){ot=!1,e(),ot=!0}function Wt(e){R=e.reactive,L=e.release,D=t=>e.effect(t,{scheduler:r=>{ot?qt(r):r()}}),st=e.raw}function at(e){D=e}function Gt(e){let t=()=>{};return[n=>{let i=D(n);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(o=>o())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),L(i))},i},()=>{t()}]}function ve(e,t){let r=!0,n,i=D(()=>{let o=e();JSON.stringify(o),r?n=o:queueMicrotask(()=>{t(o,n),n=o}),r=!1});return()=>L(i)}var Jt=[],Yt=[],Xt=[];function Zt(e){Xt.push(e)}function ee(e,t){typeof t==\"function\"?(e._x_cleanups||(e._x_cleanups=[]),e._x_cleanups.push(t)):(t=e,Yt.push(t))}function Ae(e){Jt.push(e)}function Oe(e,t,r){e._x_attributeCleanups||(e._x_attributeCleanups={}),e._x_attributeCleanups[t]||(e._x_attributeCleanups[t]=[]),e._x_attributeCleanups[t].push(r)}function ct(e,t){e._x_attributeCleanups&&Object.entries(e._x_attributeCleanups).forEach(([r,n])=>{(t===void 0||t.includes(r))&&(n.forEach(i=>i()),delete e._x_attributeCleanups[r])})}function Qt(e){if(e._x_cleanups)for(;e._x_cleanups.length;)e._x_cleanups.pop()()}var lt=new MutationObserver(pt),ut=!1;function le(){lt.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),ut=!0}function ft(){Mn(),lt.disconnect(),ut=!1}var ce=[];function Mn(){let e=lt.takeRecords();ce.push(()=>e.length>0&&pt(e));let t=ce.length;queueMicrotask(()=>{if(ce.length===t)for(;ce.length>0;)ce.shift()()})}function _(e){if(!ut)return e();ft();let t=e();return le(),t}var dt=!1,Se=[];function er(){dt=!0}function tr(){dt=!1,pt(Se),Se=[]}function pt(e){if(dt){Se=Se.concat(e);return}let t=new Set,r=new Set,n=new Map,i=new Map;for(let o=0;o<e.length;o++)if(!e[o].target._x_ignoreMutationObserver&&(e[o].type===\"childList\"&&(e[o].addedNodes.forEach(s=>s.nodeType===1&&t.add(s)),e[o].removedNodes.forEach(s=>s.nodeType===1&&r.add(s))),e[o].type===\"attributes\")){let s=e[o].target,a=e[o].attributeName,c=e[o].oldValue,l=()=>{n.has(s)||n.set(s,[]),n.get(s).push({name:a,value:s.getAttribute(a)})},u=()=>{i.has(s)||i.set(s,[]),i.get(s).push(a)};s.hasAttribute(a)&&c===null?l():s.hasAttribute(a)?(u(),l()):u()}i.forEach((o,s)=>{ct(s,o)}),n.forEach((o,s)=>{Jt.forEach(a=>a(s,o))});for(let o of r)t.has(o)||Yt.forEach(s=>s(o));t.forEach(o=>{o._x_ignoreSelf=!0,o._x_ignore=!0});for(let o of t)r.has(o)||o.isConnected&&(delete o._x_ignoreSelf,delete o._x_ignore,Xt.forEach(s=>s(o)),o._x_ignore=!0,o._x_ignoreSelf=!0);t.forEach(o=>{delete o._x_ignoreSelf,delete o._x_ignore}),t=null,r=null,n=null,i=null}function Ce(e){return F(j(e))}function P(e,t,r){return e._x_dataStack=[t,...j(r||e)],()=>{e._x_dataStack=e._x_dataStack.filter(n=>n!==t)}}function j(e){return e._x_dataStack?e._x_dataStack:typeof ShadowRoot==\"function\"&&e instanceof ShadowRoot?j(e.host):e.parentNode?j(e.parentNode):[]}function F(e){return new Proxy({objects:e},Nn)}var Nn={ownKeys({objects:e}){return Array.from(new Set(e.flatMap(t=>Object.keys(t))))},has({objects:e},t){return t==Symbol.unscopables?!1:e.some(r=>Object.prototype.hasOwnProperty.call(r,t)||Reflect.has(r,t))},get({objects:e},t,r){return t==\"toJSON\"?Dn:Reflect.get(e.find(n=>Reflect.has(n,t))||{},t,r)},set({objects:e},t,r,n){let i=e.find(s=>Object.prototype.hasOwnProperty.call(s,t))||e[e.length-1],o=Object.getOwnPropertyDescriptor(i,t);return o?.set&&o?.get?o.set.call(n,r)||!0:Reflect.set(i,t,r)}};function Dn(){return Reflect.ownKeys(this).reduce((t,r)=>(t[r]=Reflect.get(this,r),t),{})}function Te(e){let t=n=>typeof n==\"object\"&&!Array.isArray(n)&&n!==null,r=(n,i=\"\")=>{Object.entries(Object.getOwnPropertyDescriptors(n)).forEach(([o,{value:s,enumerable:a}])=>{if(a===!1||s===void 0||typeof s==\"object\"&&s!==null&&s.__v_skip)return;let c=i===\"\"?o:`${i}.${o}`;typeof s==\"object\"&&s!==null&&s._x_interceptor?n[o]=s.initialize(e,c,o):t(s)&&s!==n&&!(s instanceof Element)&&r(s,c)})};return r(e)}function Re(e,t=()=>{}){let r={initialValue:void 0,_x_interceptor:!0,initialize(n,i,o){return e(this.initialValue,()=>Pn(n,i),s=>mt(n,i,s),i,o)}};return t(r),n=>{if(typeof n==\"object\"&&n!==null&&n._x_interceptor){let i=r.initialize.bind(r);r.initialize=(o,s,a)=>{let c=n.initialize(o,s,a);return r.initialValue=c,i(o,s,a)}}else r.initialValue=n;return r}}function Pn(e,t){return t.split(\".\").reduce((r,n)=>r[n],e)}function mt(e,t,r){if(typeof t==\"string\"&&(t=t.split(\".\")),t.length===1)e[t[0]]=r;else{if(t.length===0)throw error;return e[t[0]]||(e[t[0]]={}),mt(e[t[0]],t.slice(1),r)}}var rr={};function y(e,t){rr[e]=t}function ue(e,t){return Object.entries(rr).forEach(([r,n])=>{let i=null;function o(){if(i)return i;{let[s,a]=_t(t);return i={interceptor:Re,...s},ee(t,a),i}}Object.defineProperty(e,`$${r}`,{get(){return n(t,o())},enumerable:!1})}),e}function nr(e,t,r,...n){try{return r(...n)}catch(i){te(i,e,t)}}function te(e,t,r=void 0){e=Object.assign(e??{message:\"No error message given.\"},{el:t,expression:r}),console.warn(`Alpine Expression Error: ${e.message}\n\n${r?'Expression: \"'+r+`\"\n\n`:\"\"}`,t),setTimeout(()=>{throw e},0)}var Me=!0;function De(e){let t=Me;Me=!1;let r=e();return Me=t,r}function M(e,t,r={}){let n;return x(e,t)(i=>n=i,r),n}function x(...e){return ir(...e)}var ir=gt;function or(e){ir=e}function gt(e,t){let r={};ue(r,e);let n=[r,...j(e)],i=typeof t==\"function\"?In(n,t):Ln(n,t,e);return nr.bind(null,e,t,i)}function In(e,t){return(r=()=>{},{scope:n={},params:i=[]}={})=>{let o=t.apply(F([n,...e]),i);Ne(r,o)}}var ht={};function kn(e,t){if(ht[e])return ht[e];let r=Object.getPrototypeOf(async function(){}).constructor,n=/^[\\n\\s]*if.*\\(.*\\)/.test(e.trim())||/^(let|const)\\s/.test(e.trim())?`(async()=>{ ${e} })()`:e,o=(()=>{try{let s=new r([\"__self\",\"scope\"],`with (scope) { __self.result = ${n} }; __self.finished = true; return __self.result;`);return Object.defineProperty(s,\"name\",{value:`[Alpine] ${e}`}),s}catch(s){return te(s,t,e),Promise.resolve()}})();return ht[e]=o,o}function Ln(e,t,r){let n=kn(t,r);return(i=()=>{},{scope:o={},params:s=[]}={})=>{n.result=void 0,n.finished=!1;let a=F([o,...e]);if(typeof n==\"function\"){let c=n(n,a).catch(l=>te(l,r,t));n.finished?(Ne(i,n.result,a,s,r),n.result=void 0):c.then(l=>{Ne(i,l,a,s,r)}).catch(l=>te(l,r,t)).finally(()=>n.result=void 0)}}}function Ne(e,t,r,n,i){if(Me&&typeof t==\"function\"){let o=t.apply(r,n);o instanceof Promise?o.then(s=>Ne(e,s,r,n)).catch(s=>te(s,i,t)):e(o)}else typeof t==\"object\"&&t instanceof Promise?t.then(o=>e(o)):e(t)}var bt=\"x-\";function C(e=\"\"){return bt+e}function sr(e){bt=e}var Pe={};function d(e,t){return Pe[e]=t,{before(r){if(!Pe[r]){console.warn(String.raw`Cannot find directive \\`${r}\\`. \\`${e}\\` will use the default order of execution`);return}let n=W.indexOf(r);W.splice(n>=0?n:W.indexOf(\"DEFAULT\"),0,e)}}}function ar(e){return Object.keys(Pe).includes(e)}function de(e,t,r){if(t=Array.from(t),e._x_virtualDirectives){let o=Object.entries(e._x_virtualDirectives).map(([a,c])=>({name:a,value:c})),s=wt(o);o=o.map(a=>s.find(c=>c.name===a.name)?{name:`x-bind:${a.name}`,value:`\"${a.value}\"`}:a),t=t.concat(o)}let n={};return t.map(ur((o,s)=>n[o]=s)).filter(dr).map(jn(n,r)).sort(Fn).map(o=>$n(e,o))}function wt(e){return Array.from(e).map(ur()).filter(t=>!dr(t))}var xt=!1,fe=new Map,cr=Symbol();function lr(e){xt=!0;let t=Symbol();cr=t,fe.set(t,[]);let r=()=>{for(;fe.get(t).length;)fe.get(t).shift()();fe.delete(t)},n=()=>{xt=!1,r()};e(r),n()}function _t(e){let t=[],r=a=>t.push(a),[n,i]=Gt(e);return t.push(i),[{Alpine:B,effect:n,cleanup:r,evaluateLater:x.bind(x,e),evaluate:M.bind(M,e)},()=>t.forEach(a=>a())]}function $n(e,t){let r=()=>{},n=Pe[t.type]||r,[i,o]=_t(e);Oe(e,t.original,o);let s=()=>{e._x_ignore||e._x_ignoreSelf||(n.inline&&n.inline(e,t,i),n=n.bind(n,e,t,i),xt?fe.get(cr).push(n):n())};return s.runCleanups=o,s}var Ie=(e,t)=>({name:r,value:n})=>(r.startsWith(e)&&(r=r.replace(e,t)),{name:r,value:n}),ke=e=>e;function ur(e=()=>{}){return({name:t,value:r})=>{let{name:n,value:i}=fr.reduce((o,s)=>s(o),{name:t,value:r});return n!==t&&e(n,t),{name:n,value:i}}}var fr=[];function re(e){fr.push(e)}function dr({name:e}){return pr().test(e)}var pr=()=>new RegExp(`^${bt}([^:^.]+)\\\\b`);function jn(e,t){return({name:r,value:n})=>{let i=r.match(pr()),o=r.match(/:([a-zA-Z0-9\\-_:]+)/),s=r.match(/\\.[^.\\]]+(?=[^\\]]*$)/g)||[],a=t||e[r]||r;return{type:i?i[1]:null,value:o?o[1]:null,modifiers:s.map(c=>c.replace(\".\",\"\")),expression:n,original:a}}}var yt=\"DEFAULT\",W=[\"ignore\",\"ref\",\"data\",\"id\",\"anchor\",\"bind\",\"init\",\"for\",\"model\",\"modelable\",\"transition\",\"show\",\"if\",yt,\"teleport\"];function Fn(e,t){let r=W.indexOf(e.type)===-1?yt:e.type,n=W.indexOf(t.type)===-1?yt:t.type;return W.indexOf(r)-W.indexOf(n)}function G(e,t,r={}){e.dispatchEvent(new CustomEvent(t,{detail:r,bubbles:!0,composed:!0,cancelable:!0}))}function T(e,t){if(typeof ShadowRoot==\"function\"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>T(i,t));return}let r=!1;if(t(e,()=>r=!0),r)return;let n=e.firstElementChild;for(;n;)T(n,t,!1),n=n.nextElementSibling}function E(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}var mr=!1;function _r(){mr&&E(\"Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems.\"),mr=!0,document.body||E(\"Unable to initialize. Trying to load Alpine before `<body>` is available. Did you forget to add `defer` in Alpine's `<script>` tag?\"),G(document,\"alpine:init\"),G(document,\"alpine:initializing\"),le(),Zt(t=>S(t,T)),ee(t=>vt(t)),Ae((t,r)=>{de(t,r).forEach(n=>n())});let e=t=>!J(t.parentElement,!0);Array.from(document.querySelectorAll(xr().join(\",\"))).filter(e).forEach(t=>{S(t)}),G(document,\"alpine:initialized\"),setTimeout(()=>{Bn()})}var Et=[],hr=[];function gr(){return Et.map(e=>e())}function xr(){return Et.concat(hr).map(e=>e())}function Le(e){Et.push(e)}function $e(e){hr.push(e)}function J(e,t=!1){return z(e,r=>{if((t?xr():gr()).some(i=>r.matches(i)))return!0})}function z(e,t){if(e){if(t(e))return e;if(e._x_teleportBack&&(e=e._x_teleportBack),!!e.parentElement)return z(e.parentElement,t)}}function yr(e){return gr().some(t=>e.matches(t))}var br=[];function wr(e){br.push(e)}function S(e,t=T,r=()=>{}){lr(()=>{t(e,(n,i)=>{r(n,i),br.forEach(o=>o(n,i)),de(n,n.attributes).forEach(o=>o()),n._x_ignore&&i()})})}function vt(e,t=T){t(e,r=>{ct(r),Qt(r)})}function Bn(){[[\"ui\",\"dialog\",[\"[x-dialog], [x-popover]\"]],[\"anchor\",\"anchor\",[\"[x-anchor]\"]],[\"sort\",\"sort\",[\"[x-sort]\"]]].forEach(([t,r,n])=>{ar(r)||n.some(i=>{if(document.querySelector(i))return E(`found \"${i}\", but missing ${t} plugin`),!0})})}var St=[],At=!1;function ne(e=()=>{}){return queueMicrotask(()=>{At||setTimeout(()=>{je()})}),new Promise(t=>{St.push(()=>{e(),t()})})}function je(){for(At=!1;St.length;)St.shift()()}function Er(){At=!0}function pe(e,t){return Array.isArray(t)?vr(e,t.join(\" \")):typeof t==\"object\"&&t!==null?zn(e,t):typeof t==\"function\"?pe(e,t()):vr(e,t)}function vr(e,t){let r=o=>o.split(\" \").filter(Boolean),n=o=>o.split(\" \").filter(s=>!e.classList.contains(s)).filter(Boolean),i=o=>(e.classList.add(...o),()=>{e.classList.remove(...o)});return t=t===!0?t=\"\":t||\"\",i(n(t))}function zn(e,t){let r=a=>a.split(\" \").filter(Boolean),n=Object.entries(t).flatMap(([a,c])=>c?r(a):!1).filter(Boolean),i=Object.entries(t).flatMap(([a,c])=>c?!1:r(a)).filter(Boolean),o=[],s=[];return i.forEach(a=>{e.classList.contains(a)&&(e.classList.remove(a),s.push(a))}),n.forEach(a=>{e.classList.contains(a)||(e.classList.add(a),o.push(a))}),()=>{s.forEach(a=>e.classList.add(a)),o.forEach(a=>e.classList.remove(a))}}function Y(e,t){return typeof t==\"object\"&&t!==null?Kn(e,t):Hn(e,t)}function Kn(e,t){let r={};return Object.entries(t).forEach(([n,i])=>{r[n]=e.style[n],n.startsWith(\"--\")||(n=Vn(n)),e.style.setProperty(n,i)}),setTimeout(()=>{e.style.length===0&&e.removeAttribute(\"style\")}),()=>{Y(e,r)}}function Hn(e,t){let r=e.getAttribute(\"style\",t);return e.setAttribute(\"style\",t),()=>{e.setAttribute(\"style\",r||\"\")}}function Vn(e){return e.replace(/([a-z])([A-Z])/g,\"$1-$2\").toLowerCase()}function me(e,t=()=>{}){let r=!1;return function(){r?t.apply(this,arguments):(r=!0,e.apply(this,arguments))}}d(\"transition\",(e,{value:t,modifiers:r,expression:n},{evaluate:i})=>{typeof n==\"function\"&&(n=i(n)),n!==!1&&(!n||typeof n==\"boolean\"?Un(e,r,t):qn(e,n,t))});function qn(e,t,r){Sr(e,pe,\"\"),{enter:i=>{e._x_transition.enter.during=i},\"enter-start\":i=>{e._x_transition.enter.start=i},\"enter-end\":i=>{e._x_transition.enter.end=i},leave:i=>{e._x_transition.leave.during=i},\"leave-start\":i=>{e._x_transition.leave.start=i},\"leave-end\":i=>{e._x_transition.leave.end=i}}[r](t)}function Un(e,t,r){Sr(e,Y);let n=!t.includes(\"in\")&&!t.includes(\"out\")&&!r,i=n||t.includes(\"in\")||[\"enter\"].includes(r),o=n||t.includes(\"out\")||[\"leave\"].includes(r);t.includes(\"in\")&&!n&&(t=t.filter((g,b)=>b<t.indexOf(\"out\"))),t.includes(\"out\")&&!n&&(t=t.filter((g,b)=>b>t.indexOf(\"out\")));let s=!t.includes(\"opacity\")&&!t.includes(\"scale\"),a=s||t.includes(\"opacity\"),c=s||t.includes(\"scale\"),l=a?0:1,u=c?_e(t,\"scale\",95)/100:1,p=_e(t,\"delay\",0)/1e3,m=_e(t,\"origin\",\"center\"),w=\"opacity, transform\",$=_e(t,\"duration\",150)/1e3,we=_e(t,\"duration\",75)/1e3,f=\"cubic-bezier(0.4, 0.0, 0.2, 1)\";i&&(e._x_transition.enter.during={transformOrigin:m,transitionDelay:`${p}s`,transitionProperty:w,transitionDuration:`${$}s`,transitionTimingFunction:f},e._x_transition.enter.start={opacity:l,transform:`scale(${u})`},e._x_transition.enter.end={opacity:1,transform:\"scale(1)\"}),o&&(e._x_transition.leave.during={transformOrigin:m,transitionDelay:`${p}s`,transitionProperty:w,transitionDuration:`${we}s`,transitionTimingFunction:f},e._x_transition.leave.start={opacity:1,transform:\"scale(1)\"},e._x_transition.leave.end={opacity:l,transform:`scale(${u})`})}function Sr(e,t,r={}){e._x_transition||(e._x_transition={enter:{during:r,start:r,end:r},leave:{during:r,start:r,end:r},in(n=()=>{},i=()=>{}){Fe(e,t,{during:this.enter.during,start:this.enter.start,end:this.enter.end},n,i)},out(n=()=>{},i=()=>{}){Fe(e,t,{during:this.leave.during,start:this.leave.start,end:this.leave.end},n,i)}})}window.Element.prototype._x_toggleAndCascadeWithTransitions=function(e,t,r,n){let i=document.visibilityState===\"visible\"?requestAnimationFrame:setTimeout,o=()=>i(r);if(t){e._x_transition&&(e._x_transition.enter||e._x_transition.leave)?e._x_transition.enter&&(Object.entries(e._x_transition.enter.during).length||Object.entries(e._x_transition.enter.start).length||Object.entries(e._x_transition.enter.end).length)?e._x_transition.in(r):o():e._x_transition?e._x_transition.in(r):o();return}e._x_hidePromise=e._x_transition?new Promise((s,a)=>{e._x_transition.out(()=>{},()=>s(n)),e._x_transitioning&&e._x_transitioning.beforeCancel(()=>a({isFromCancelledTransition:!0}))}):Promise.resolve(n),queueMicrotask(()=>{let s=Ar(e);s?(s._x_hideChildren||(s._x_hideChildren=[]),s._x_hideChildren.push(e)):i(()=>{let a=c=>{let l=Promise.all([c._x_hidePromise,...(c._x_hideChildren||[]).map(a)]).then(([u])=>u?.());return delete c._x_hidePromise,delete c._x_hideChildren,l};a(e).catch(c=>{if(!c.isFromCancelledTransition)throw c})})})};function Ar(e){let t=e.parentNode;if(t)return t._x_hidePromise?t:Ar(t)}function Fe(e,t,{during:r,start:n,end:i}={},o=()=>{},s=()=>{}){if(e._x_transitioning&&e._x_transitioning.cancel(),Object.keys(r).length===0&&Object.keys(n).length===0&&Object.keys(i).length===0){o(),s();return}let a,c,l;Wn(e,{start(){a=t(e,n)},during(){c=t(e,r)},before:o,end(){a(),l=t(e,i)},after:s,cleanup(){c(),l()}})}function Wn(e,t){let r,n,i,o=me(()=>{_(()=>{r=!0,n||t.before(),i||(t.end(),je()),t.after(),e.isConnected&&t.cleanup(),delete e._x_transitioning})});e._x_transitioning={beforeCancels:[],beforeCancel(s){this.beforeCancels.push(s)},cancel:me(function(){for(;this.beforeCancels.length;)this.beforeCancels.shift()();o()}),finish:o},_(()=>{t.start(),t.during()}),Er(),requestAnimationFrame(()=>{if(r)return;let s=Number(getComputedStyle(e).transitionDuration.replace(/,.*/,\"\").replace(\"s\",\"\"))*1e3,a=Number(getComputedStyle(e).transitionDelay.replace(/,.*/,\"\").replace(\"s\",\"\"))*1e3;s===0&&(s=Number(getComputedStyle(e).animationDuration.replace(\"s\",\"\"))*1e3),_(()=>{t.before()}),n=!0,requestAnimationFrame(()=>{r||(_(()=>{t.end()}),je(),setTimeout(e._x_transitioning.finish,s+a),i=!0)})})}function _e(e,t,r){if(e.indexOf(t)===-1)return r;let n=e[e.indexOf(t)+1];if(!n||t===\"scale\"&&isNaN(n))return r;if(t===\"duration\"||t===\"delay\"){let i=n.match(/([0-9]+)ms/);if(i)return i[1]}return t===\"origin\"&&[\"top\",\"right\",\"left\",\"center\",\"bottom\"].includes(e[e.indexOf(t)+2])?[n,e[e.indexOf(t)+2]].join(\" \"):n}var I=!1;function A(e,t=()=>{}){return(...r)=>I?t(...r):e(...r)}function Or(e){return(...t)=>I&&e(...t)}var Cr=[];function K(e){Cr.push(e)}function Tr(e,t){Cr.forEach(r=>r(e,t)),I=!0,Mr(()=>{S(t,(r,n)=>{n(r,()=>{})})}),I=!1}var Be=!1;function Rr(e,t){t._x_dataStack||(t._x_dataStack=e._x_dataStack),I=!0,Be=!0,Mr(()=>{Gn(t)}),I=!1,Be=!1}function Gn(e){let t=!1;S(e,(n,i)=>{T(n,(o,s)=>{if(t&&yr(o))return s();t=!0,i(o,s)})})}function Mr(e){let t=D;at((r,n)=>{let i=t(r);return L(i),()=>{}}),e(),at(t)}function he(e,t,r,n=[]){switch(e._x_bindings||(e._x_bindings=R({})),e._x_bindings[t]=r,t=n.includes(\"camel\")?ri(t):t,t){case\"value\":Jn(e,r);break;case\"style\":Xn(e,r);break;case\"class\":Yn(e,r);break;case\"selected\":case\"checked\":Zn(e,t,r);break;default:Dr(e,t,r);break}}function Jn(e,t){if(e.type===\"radio\")e.attributes.value===void 0&&(e.value=t),window.fromModel&&(typeof t==\"boolean\"?e.checked=ge(e.value)===t:e.checked=Nr(e.value,t));else if(e.type===\"checkbox\")Number.isInteger(t)?e.value=t:!Array.isArray(t)&&typeof t!=\"boolean\"&&![null,void 0].includes(t)?e.value=String(t):Array.isArray(t)?e.checked=t.some(r=>Nr(r,e.value)):e.checked=!!t;else if(e.tagName===\"SELECT\")ti(e,t);else{if(e.value===t)return;e.value=t===void 0?\"\":t}}function Yn(e,t){e._x_undoAddedClasses&&e._x_undoAddedClasses(),e._x_undoAddedClasses=pe(e,t)}function Xn(e,t){e._x_undoAddedStyles&&e._x_undoAddedStyles(),e._x_undoAddedStyles=Y(e,t)}function Zn(e,t,r){Dr(e,t,r),ei(e,t,r)}function Dr(e,t,r){[null,void 0,!1].includes(r)&&ni(t)?e.removeAttribute(t):(Pr(t)&&(r=t),Qn(e,t,r))}function Qn(e,t,r){e.getAttribute(t)!=r&&e.setAttribute(t,r)}function ei(e,t,r){e[t]!==r&&(e[t]=r)}function ti(e,t){let r=[].concat(t).map(n=>n+\"\");Array.from(e.options).forEach(n=>{n.selected=r.includes(n.value)})}function ri(e){return e.toLowerCase().replace(/-(\\w)/g,(t,r)=>r.toUpperCase())}function Nr(e,t){return e==t}function ge(e){return[1,\"1\",\"true\",\"on\",\"yes\",!0].includes(e)?!0:[0,\"0\",\"false\",\"off\",\"no\",!1].includes(e)?!1:e?Boolean(e):null}function Pr(e){return[\"disabled\",\"checked\",\"required\",\"readonly\",\"open\",\"selected\",\"autofocus\",\"itemscope\",\"multiple\",\"novalidate\",\"allowfullscreen\",\"allowpaymentrequest\",\"formnovalidate\",\"autoplay\",\"controls\",\"loop\",\"muted\",\"playsinline\",\"default\",\"ismap\",\"reversed\",\"async\",\"defer\",\"nomodule\"].includes(e)}function ni(e){return![\"aria-pressed\",\"aria-checked\",\"aria-expanded\",\"aria-selected\"].includes(e)}function Ir(e,t,r){return e._x_bindings&&e._x_bindings[t]!==void 0?e._x_bindings[t]:Lr(e,t,r)}function kr(e,t,r,n=!0){if(e._x_bindings&&e._x_bindings[t]!==void 0)return e._x_bindings[t];if(e._x_inlineBindings&&e._x_inlineBindings[t]!==void 0){let i=e._x_inlineBindings[t];return i.extract=n,De(()=>M(e,i.expression))}return Lr(e,t,r)}function Lr(e,t,r){let n=e.getAttribute(t);return n===null?typeof r==\"function\"?r():r:n===\"\"?!0:Pr(t)?!![t,\"true\"].includes(n):n}function ze(e,t){var r;return function(){var n=this,i=arguments,o=function(){r=null,e.apply(n,i)};clearTimeout(r),r=setTimeout(o,t)}}function Ke(e,t){let r;return function(){let n=this,i=arguments;r||(e.apply(n,i),r=!0,setTimeout(()=>r=!1,t))}}function He({get:e,set:t},{get:r,set:n}){let i=!0,o,s,a=D(()=>{let c=e(),l=r();if(i)n(Ot(c)),i=!1;else{let u=JSON.stringify(c),p=JSON.stringify(l);u!==o?n(Ot(c)):u!==p&&t(Ot(l))}o=JSON.stringify(e()),s=JSON.stringify(r())});return()=>{L(a)}}function Ot(e){return typeof e==\"object\"?JSON.parse(JSON.stringify(e)):e}function $r(e){(Array.isArray(e)?e:[e]).forEach(r=>r(B))}var X={},jr=!1;function Fr(e,t){if(jr||(X=R(X),jr=!0),t===void 0)return X[e];X[e]=t,typeof t==\"object\"&&t!==null&&t.hasOwnProperty(\"init\")&&typeof t.init==\"function\"&&X[e].init(),Te(X[e])}function Br(){return X}var zr={};function Kr(e,t){let r=typeof t!=\"function\"?()=>t:t;return e instanceof Element?Ct(e,r()):(zr[e]=r,()=>{})}function Hr(e){return Object.entries(zr).forEach(([t,r])=>{Object.defineProperty(e,t,{get(){return(...n)=>r(...n)}})}),e}function Ct(e,t,r){let n=[];for(;n.length;)n.pop()();let i=Object.entries(t).map(([s,a])=>({name:s,value:a})),o=wt(i);return i=i.map(s=>o.find(a=>a.name===s.name)?{name:`x-bind:${s.name}`,value:`\"${s.value}\"`}:s),de(e,i,r).map(s=>{n.push(s.runCleanups),s()}),()=>{for(;n.length;)n.pop()()}}var Vr={};function qr(e,t){Vr[e]=t}function Ur(e,t){return Object.entries(Vr).forEach(([r,n])=>{Object.defineProperty(e,r,{get(){return(...i)=>n.bind(t)(...i)},enumerable:!1})}),e}var ii={get reactive(){return R},get release(){return L},get effect(){return D},get raw(){return st},version:\"3.14.1\",flushAndStopDeferringMutations:tr,dontAutoEvaluateFunctions:De,disableEffectScheduling:Ut,startObservingMutations:le,stopObservingMutations:ft,setReactivityEngine:Wt,onAttributeRemoved:Oe,onAttributesAdded:Ae,closestDataStack:j,skipDuringClone:A,onlyDuringClone:Or,addRootSelector:Le,addInitSelector:$e,interceptClone:K,addScopeToNode:P,deferMutations:er,mapAttributes:re,evaluateLater:x,interceptInit:wr,setEvaluator:or,mergeProxies:F,extractProp:kr,findClosest:z,onElRemoved:ee,closestRoot:J,destroyTree:vt,interceptor:Re,transition:Fe,setStyles:Y,mutateDom:_,directive:d,entangle:He,throttle:Ke,debounce:ze,evaluate:M,initTree:S,nextTick:ne,prefixed:C,prefix:sr,plugin:$r,magic:y,store:Fr,start:_r,clone:Rr,cloneNode:Tr,bound:Ir,$data:Ce,watch:ve,walk:T,data:qr,bind:Kr},B=ii;function Tt(e,t){let r=Object.create(null),n=e.split(\",\");for(let i=0;i<n.length;i++)r[n[i]]=!0;return t?i=>!!r[i.toLowerCase()]:i=>!!r[i]}var oi=\"itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly\";var Ms=Tt(oi+\",async,autofocus,autoplay,controls,default,defer,disabled,hidden,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected\");var Wr=Object.freeze({}),Ns=Object.freeze([]);var si=Object.prototype.hasOwnProperty,xe=(e,t)=>si.call(e,t),H=Array.isArray,ie=e=>Gr(e)===\"[object Map]\";var ai=e=>typeof e==\"string\",Ve=e=>typeof e==\"symbol\",ye=e=>e!==null&&typeof e==\"object\";var ci=Object.prototype.toString,Gr=e=>ci.call(e),Rt=e=>Gr(e).slice(8,-1);var qe=e=>ai(e)&&e!==\"NaN\"&&e[0]!==\"-\"&&\"\"+parseInt(e,10)===e;var Ue=e=>{let t=Object.create(null);return r=>t[r]||(t[r]=e(r))},li=/-(\\w)/g,Ds=Ue(e=>e.replace(li,(t,r)=>r?r.toUpperCase():\"\")),ui=/\\B([A-Z])/g,Ps=Ue(e=>e.replace(ui,\"-$1\").toLowerCase()),Mt=Ue(e=>e.charAt(0).toUpperCase()+e.slice(1)),Is=Ue(e=>e?`on${Mt(e)}`:\"\"),Nt=(e,t)=>e!==t&&(e===e||t===t);var Dt=new WeakMap,be=[],k,Z=Symbol(\"iterate\"),Pt=Symbol(\"Map key iterate\");function fi(e){return e&&e._isEffect===!0}function en(e,t=Wr){fi(e)&&(e=e.raw);let r=pi(e,t);return t.lazy||r(),r}function tn(e){e.active&&(rn(e),e.options.onStop&&e.options.onStop(),e.active=!1)}var di=0;function pi(e,t){let r=function(){if(!r.active)return e();if(!be.includes(r)){rn(r);try{return _i(),be.push(r),k=r,e()}finally{be.pop(),nn(),k=be[be.length-1]}}};return r.id=di++,r.allowRecurse=!!t.allowRecurse,r._isEffect=!0,r.active=!0,r.raw=e,r.deps=[],r.options=t,r}function rn(e){let{deps:t}=e;if(t.length){for(let r=0;r<t.length;r++)t[r].delete(e);t.length=0}}var oe=!0,kt=[];function mi(){kt.push(oe),oe=!1}function _i(){kt.push(oe),oe=!0}function nn(){let e=kt.pop();oe=e===void 0?!0:e}function N(e,t,r){if(!oe||k===void 0)return;let n=Dt.get(e);n||Dt.set(e,n=new Map);let i=n.get(r);i||n.set(r,i=new Set),i.has(k)||(i.add(k),k.deps.push(i),k.options.onTrack&&k.options.onTrack({effect:k,target:e,type:t,key:r}))}function q(e,t,r,n,i,o){let s=Dt.get(e);if(!s)return;let a=new Set,c=u=>{u&&u.forEach(p=>{(p!==k||p.allowRecurse)&&a.add(p)})};if(t===\"clear\")s.forEach(c);else if(r===\"length\"&&H(e))s.forEach((u,p)=>{(p===\"length\"||p>=n)&&c(u)});else switch(r!==void 0&&c(s.get(r)),t){case\"add\":H(e)?qe(r)&&c(s.get(\"length\")):(c(s.get(Z)),ie(e)&&c(s.get(Pt)));break;case\"delete\":H(e)||(c(s.get(Z)),ie(e)&&c(s.get(Pt)));break;case\"set\":ie(e)&&c(s.get(Z));break}let l=u=>{u.options.onTrigger&&u.options.onTrigger({effect:u,target:e,key:r,type:t,newValue:n,oldValue:i,oldTarget:o}),u.options.scheduler?u.options.scheduler(u):u()};a.forEach(l)}var hi=Tt(\"__proto__,__v_isRef,__isVue\"),on=new Set(Object.getOwnPropertyNames(Symbol).map(e=>Symbol[e]).filter(Ve)),gi=sn();var xi=sn(!0);var Jr=yi();function yi(){let e={};return[\"includes\",\"indexOf\",\"lastIndexOf\"].forEach(t=>{e[t]=function(...r){let n=h(this);for(let o=0,s=this.length;o<s;o++)N(n,\"get\",o+\"\");let i=n[t](...r);return i===-1||i===!1?n[t](...r.map(h)):i}}),[\"push\",\"pop\",\"shift\",\"unshift\",\"splice\"].forEach(t=>{e[t]=function(...r){mi();let n=h(this)[t].apply(this,r);return nn(),n}}),e}function sn(e=!1,t=!1){return function(n,i,o){if(i===\"__v_isReactive\")return!e;if(i===\"__v_isReadonly\")return e;if(i===\"__v_raw\"&&o===(e?t?ki:un:t?Ii:ln).get(n))return n;let s=H(n);if(!e&&s&&xe(Jr,i))return Reflect.get(Jr,i,o);let a=Reflect.get(n,i,o);return(Ve(i)?on.has(i):hi(i))||(e||N(n,\"get\",i),t)?a:It(a)?!s||!qe(i)?a.value:a:ye(a)?e?fn(a):Qe(a):a}}var bi=wi();function wi(e=!1){return function(r,n,i,o){let s=r[n];if(!e&&(i=h(i),s=h(s),!H(r)&&It(s)&&!It(i)))return s.value=i,!0;let a=H(r)&&qe(n)?Number(n)<r.length:xe(r,n),c=Reflect.set(r,n,i,o);return r===h(o)&&(a?Nt(i,s)&&q(r,\"set\",n,i,s):q(r,\"add\",n,i)),c}}function Ei(e,t){let r=xe(e,t),n=e[t],i=Reflect.deleteProperty(e,t);return i&&r&&q(e,\"delete\",t,void 0,n),i}function vi(e,t){let r=Reflect.has(e,t);return(!Ve(t)||!on.has(t))&&N(e,\"has\",t),r}function Si(e){return N(e,\"iterate\",H(e)?\"length\":Z),Reflect.ownKeys(e)}var Ai={get:gi,set:bi,deleteProperty:Ei,has:vi,ownKeys:Si},Oi={get:xi,set(e,t){return console.warn(`Set operation on key \"${String(t)}\" failed: target is readonly.`,e),!0},deleteProperty(e,t){return console.warn(`Delete operation on key \"${String(t)}\" failed: target is readonly.`,e),!0}};var Lt=e=>ye(e)?Qe(e):e,$t=e=>ye(e)?fn(e):e,jt=e=>e,Ze=e=>Reflect.getPrototypeOf(e);function We(e,t,r=!1,n=!1){e=e.__v_raw;let i=h(e),o=h(t);t!==o&&!r&&N(i,\"get\",t),!r&&N(i,\"get\",o);let{has:s}=Ze(i),a=n?jt:r?$t:Lt;if(s.call(i,t))return a(e.get(t));if(s.call(i,o))return a(e.get(o));e!==i&&e.get(t)}function Ge(e,t=!1){let r=this.__v_raw,n=h(r),i=h(e);return e!==i&&!t&&N(n,\"has\",e),!t&&N(n,\"has\",i),e===i?r.has(e):r.has(e)||r.has(i)}function Je(e,t=!1){return e=e.__v_raw,!t&&N(h(e),\"iterate\",Z),Reflect.get(e,\"size\",e)}function Yr(e){e=h(e);let t=h(this);return Ze(t).has.call(t,e)||(t.add(e),q(t,\"add\",e,e)),this}function Xr(e,t){t=h(t);let r=h(this),{has:n,get:i}=Ze(r),o=n.call(r,e);o?cn(r,n,e):(e=h(e),o=n.call(r,e));let s=i.call(r,e);return r.set(e,t),o?Nt(t,s)&&q(r,\"set\",e,t,s):q(r,\"add\",e,t),this}function Zr(e){let t=h(this),{has:r,get:n}=Ze(t),i=r.call(t,e);i?cn(t,r,e):(e=h(e),i=r.call(t,e));let o=n?n.call(t,e):void 0,s=t.delete(e);return i&&q(t,\"delete\",e,void 0,o),s}function Qr(){let e=h(this),t=e.size!==0,r=ie(e)?new Map(e):new Set(e),n=e.clear();return t&&q(e,\"clear\",void 0,void 0,r),n}function Ye(e,t){return function(n,i){let o=this,s=o.__v_raw,a=h(s),c=t?jt:e?$t:Lt;return!e&&N(a,\"iterate\",Z),s.forEach((l,u)=>n.call(i,c(l),c(u),o))}}function Xe(e,t,r){return function(...n){let i=this.__v_raw,o=h(i),s=ie(o),a=e===\"entries\"||e===Symbol.iterator&&s,c=e===\"keys\"&&s,l=i[e](...n),u=r?jt:t?$t:Lt;return!t&&N(o,\"iterate\",c?Pt:Z),{next(){let{value:p,done:m}=l.next();return m?{value:p,done:m}:{value:a?[u(p[0]),u(p[1])]:u(p),done:m}},[Symbol.iterator](){return this}}}}function V(e){return function(...t){{let r=t[0]?`on key \"${t[0]}\" `:\"\";console.warn(`${Mt(e)} operation ${r}failed: target is readonly.`,h(this))}return e===\"delete\"?!1:this}}function Ci(){let e={get(o){return We(this,o)},get size(){return Je(this)},has:Ge,add:Yr,set:Xr,delete:Zr,clear:Qr,forEach:Ye(!1,!1)},t={get(o){return We(this,o,!1,!0)},get size(){return Je(this)},has:Ge,add:Yr,set:Xr,delete:Zr,clear:Qr,forEach:Ye(!1,!0)},r={get(o){return We(this,o,!0)},get size(){return Je(this,!0)},has(o){return Ge.call(this,o,!0)},add:V(\"add\"),set:V(\"set\"),delete:V(\"delete\"),clear:V(\"clear\"),forEach:Ye(!0,!1)},n={get(o){return We(this,o,!0,!0)},get size(){return Je(this,!0)},has(o){return Ge.call(this,o,!0)},add:V(\"add\"),set:V(\"set\"),delete:V(\"delete\"),clear:V(\"clear\"),forEach:Ye(!0,!0)};return[\"keys\",\"values\",\"entries\",Symbol.iterator].forEach(o=>{e[o]=Xe(o,!1,!1),r[o]=Xe(o,!0,!1),t[o]=Xe(o,!1,!0),n[o]=Xe(o,!0,!0)}),[e,r,t,n]}var[Ti,Ri,Mi,Ni]=Ci();function an(e,t){let r=t?e?Ni:Mi:e?Ri:Ti;return(n,i,o)=>i===\"__v_isReactive\"?!e:i===\"__v_isReadonly\"?e:i===\"__v_raw\"?n:Reflect.get(xe(r,i)&&i in n?r:n,i,o)}var Di={get:an(!1,!1)};var Pi={get:an(!0,!1)};function cn(e,t,r){let n=h(r);if(n!==r&&t.call(e,n)){let i=Rt(e);console.warn(`Reactive ${i} contains both the raw and reactive versions of the same object${i===\"Map\"?\" as keys\":\"\"}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`)}}var ln=new WeakMap,Ii=new WeakMap,un=new WeakMap,ki=new WeakMap;function Li(e){switch(e){case\"Object\":case\"Array\":return 1;case\"Map\":case\"Set\":case\"WeakMap\":case\"WeakSet\":return 2;default:return 0}}function $i(e){return e.__v_skip||!Object.isExtensible(e)?0:Li(Rt(e))}function Qe(e){return e&&e.__v_isReadonly?e:dn(e,!1,Ai,Di,ln)}function fn(e){return dn(e,!0,Oi,Pi,un)}function dn(e,t,r,n,i){if(!ye(e))return console.warn(`value cannot be made reactive: ${String(e)}`),e;if(e.__v_raw&&!(t&&e.__v_isReactive))return e;let o=i.get(e);if(o)return o;let s=$i(e);if(s===0)return e;let a=new Proxy(e,s===2?n:r);return i.set(e,a),a}function h(e){return e&&h(e.__v_raw)||e}function It(e){return Boolean(e&&e.__v_isRef===!0)}y(\"nextTick\",()=>ne);y(\"dispatch\",e=>G.bind(G,e));y(\"watch\",(e,{evaluateLater:t,cleanup:r})=>(n,i)=>{let o=t(n),a=ve(()=>{let c;return o(l=>c=l),c},i);r(a)});y(\"store\",Br);y(\"data\",e=>Ce(e));y(\"root\",e=>J(e));y(\"refs\",e=>(e._x_refs_proxy||(e._x_refs_proxy=F(ji(e))),e._x_refs_proxy));function ji(e){let t=[];return z(e,r=>{r._x_refs&&t.push(r._x_refs)}),t}var Ft={};function Bt(e){return Ft[e]||(Ft[e]=0),++Ft[e]}function pn(e,t){return z(e,r=>{if(r._x_ids&&r._x_ids[t])return!0})}function mn(e,t){e._x_ids||(e._x_ids={}),e._x_ids[t]||(e._x_ids[t]=Bt(t))}y(\"id\",(e,{cleanup:t})=>(r,n=null)=>{let i=`${r}${n?`-${n}`:\"\"}`;return Fi(e,i,t,()=>{let o=pn(e,r),s=o?o._x_ids[r]:Bt(r);return n?`${r}-${s}-${n}`:`${r}-${s}`})});K((e,t)=>{e._x_id&&(t._x_id=e._x_id)});function Fi(e,t,r,n){if(e._x_id||(e._x_id={}),e._x_id[t])return e._x_id[t];let i=n();return e._x_id[t]=i,r(()=>{delete e._x_id[t]}),i}y(\"el\",e=>e);_n(\"Focus\",\"focus\",\"focus\");_n(\"Persist\",\"persist\",\"persist\");function _n(e,t,r){y(t,n=>E(`You can't use [$${t}] without first installing the \"${e}\" plugin here: https://alpinejs.dev/plugins/${r}`,n))}d(\"modelable\",(e,{expression:t},{effect:r,evaluateLater:n,cleanup:i})=>{let o=n(t),s=()=>{let u;return o(p=>u=p),u},a=n(`${t} = __placeholder`),c=u=>a(()=>{},{scope:{__placeholder:u}}),l=s();c(l),queueMicrotask(()=>{if(!e._x_model)return;e._x_removeModelListeners.default();let u=e._x_model.get,p=e._x_model.set,m=He({get(){return u()},set(w){p(w)}},{get(){return s()},set(w){c(w)}});i(m)})});d(\"teleport\",(e,{modifiers:t,expression:r},{cleanup:n})=>{e.tagName.toLowerCase()!==\"template\"&&E(\"x-teleport can only be used on a <template> tag\",e);let i=hn(r),o=e.content.cloneNode(!0).firstElementChild;e._x_teleport=o,o._x_teleportBack=e,e.setAttribute(\"data-teleport-template\",!0),o.setAttribute(\"data-teleport-target\",!0),e._x_forwardEvents&&e._x_forwardEvents.forEach(a=>{o.addEventListener(a,c=>{c.stopPropagation(),e.dispatchEvent(new c.constructor(c.type,c))})}),P(o,{},e);let s=(a,c,l)=>{l.includes(\"prepend\")?c.parentNode.insertBefore(a,c):l.includes(\"append\")?c.parentNode.insertBefore(a,c.nextSibling):c.appendChild(a)};_(()=>{s(o,i,t),A(()=>{S(o),o._x_ignore=!0})()}),e._x_teleportPutBack=()=>{let a=hn(r);_(()=>{s(e._x_teleport,a,t)})},n(()=>o.remove())});var Bi=document.createElement(\"div\");function hn(e){let t=A(()=>document.querySelector(e),()=>Bi)();return t||E(`Cannot find x-teleport element for selector: \"${e}\"`),t}var gn=()=>{};gn.inline=(e,{modifiers:t},{cleanup:r})=>{t.includes(\"self\")?e._x_ignoreSelf=!0:e._x_ignore=!0,r(()=>{t.includes(\"self\")?delete e._x_ignoreSelf:delete e._x_ignore})};d(\"ignore\",gn);d(\"effect\",A((e,{expression:t},{effect:r})=>{r(x(e,t))}));function se(e,t,r,n){let i=e,o=c=>n(c),s={},a=(c,l)=>u=>l(c,u);if(r.includes(\"dot\")&&(t=zi(t)),r.includes(\"camel\")&&(t=Ki(t)),r.includes(\"passive\")&&(s.passive=!0),r.includes(\"capture\")&&(s.capture=!0),r.includes(\"window\")&&(i=window),r.includes(\"document\")&&(i=document),r.includes(\"debounce\")){let c=r[r.indexOf(\"debounce\")+1]||\"invalid-wait\",l=et(c.split(\"ms\")[0])?Number(c.split(\"ms\")[0]):250;o=ze(o,l)}if(r.includes(\"throttle\")){let c=r[r.indexOf(\"throttle\")+1]||\"invalid-wait\",l=et(c.split(\"ms\")[0])?Number(c.split(\"ms\")[0]):250;o=Ke(o,l)}return r.includes(\"prevent\")&&(o=a(o,(c,l)=>{l.preventDefault(),c(l)})),r.includes(\"stop\")&&(o=a(o,(c,l)=>{l.stopPropagation(),c(l)})),r.includes(\"once\")&&(o=a(o,(c,l)=>{c(l),i.removeEventListener(t,o,s)})),(r.includes(\"away\")||r.includes(\"outside\"))&&(i=document,o=a(o,(c,l)=>{e.contains(l.target)||l.target.isConnected!==!1&&(e.offsetWidth<1&&e.offsetHeight<1||e._x_isShown!==!1&&c(l))})),r.includes(\"self\")&&(o=a(o,(c,l)=>{l.target===e&&c(l)})),(Vi(t)||yn(t))&&(o=a(o,(c,l)=>{qi(l,r)||c(l)})),i.addEventListener(t,o,s),()=>{i.removeEventListener(t,o,s)}}function zi(e){return e.replace(/-/g,\".\")}function Ki(e){return e.toLowerCase().replace(/-(\\w)/g,(t,r)=>r.toUpperCase())}function et(e){return!Array.isArray(e)&&!isNaN(e)}function Hi(e){return[\" \",\"_\"].includes(e)?e:e.replace(/([a-z])([A-Z])/g,\"$1-$2\").replace(/[_\\s]/,\"-\").toLowerCase()}function Vi(e){return[\"keydown\",\"keyup\"].includes(e)}function yn(e){return[\"contextmenu\",\"click\",\"mouse\"].some(t=>e.includes(t))}function qi(e,t){let r=t.filter(o=>![\"window\",\"document\",\"prevent\",\"stop\",\"once\",\"capture\",\"self\",\"away\",\"outside\",\"passive\"].includes(o));if(r.includes(\"debounce\")){let o=r.indexOf(\"debounce\");r.splice(o,et((r[o+1]||\"invalid-wait\").split(\"ms\")[0])?2:1)}if(r.includes(\"throttle\")){let o=r.indexOf(\"throttle\");r.splice(o,et((r[o+1]||\"invalid-wait\").split(\"ms\")[0])?2:1)}if(r.length===0||r.length===1&&xn(e.key).includes(r[0]))return!1;let i=[\"ctrl\",\"shift\",\"alt\",\"meta\",\"cmd\",\"super\"].filter(o=>r.includes(o));return r=r.filter(o=>!i.includes(o)),!(i.length>0&&i.filter(s=>((s===\"cmd\"||s===\"super\")&&(s=\"meta\"),e[`${s}Key`])).length===i.length&&(yn(e.type)||xn(e.key).includes(r[0])))}function xn(e){if(!e)return[];e=Hi(e);let t={ctrl:\"control\",slash:\"/\",space:\" \",spacebar:\" \",cmd:\"meta\",esc:\"escape\",up:\"arrow-up\",down:\"arrow-down\",left:\"arrow-left\",right:\"arrow-right\",period:\".\",comma:\",\",equal:\"=\",minus:\"-\",underscore:\"_\"};return t[e]=e,Object.keys(t).map(r=>{if(t[r]===e)return r}).filter(r=>r)}d(\"model\",(e,{modifiers:t,expression:r},{effect:n,cleanup:i})=>{let o=e;t.includes(\"parent\")&&(o=e.parentNode);let s=x(o,r),a;typeof r==\"string\"?a=x(o,`${r} = __placeholder`):typeof r==\"function\"&&typeof r()==\"string\"?a=x(o,`${r()} = __placeholder`):a=()=>{};let c=()=>{let m;return s(w=>m=w),bn(m)?m.get():m},l=m=>{let w;s($=>w=$),bn(w)?w.set(m):a(()=>{},{scope:{__placeholder:m}})};typeof r==\"string\"&&e.type===\"radio\"&&_(()=>{e.hasAttribute(\"name\")||e.setAttribute(\"name\",r)});var u=e.tagName.toLowerCase()===\"select\"||[\"checkbox\",\"radio\"].includes(e.type)||t.includes(\"lazy\")?\"change\":\"input\";let p=I?()=>{}:se(e,u,t,m=>{l(zt(e,t,m,c()))});if(t.includes(\"fill\")&&([void 0,null,\"\"].includes(c())||e.type===\"checkbox\"&&Array.isArray(c())||e.tagName.toLowerCase()===\"select\"&&e.multiple)&&l(zt(e,t,{target:e},c())),e._x_removeModelListeners||(e._x_removeModelListeners={}),e._x_removeModelListeners.default=p,i(()=>e._x_removeModelListeners.default()),e.form){let m=se(e.form,\"reset\",[],w=>{ne(()=>e._x_model&&e._x_model.set(zt(e,t,{target:e},c())))});i(()=>m())}e._x_model={get(){return c()},set(m){l(m)}},e._x_forceModelUpdate=m=>{m===void 0&&typeof r==\"string\"&&r.match(/\\./)&&(m=\"\"),window.fromModel=!0,_(()=>he(e,\"value\",m)),delete window.fromModel},n(()=>{let m=c();t.includes(\"unintrusive\")&&document.activeElement.isSameNode(e)||e._x_forceModelUpdate(m)})});function zt(e,t,r,n){return _(()=>{if(r instanceof CustomEvent&&r.detail!==void 0)return r.detail!==null&&r.detail!==void 0?r.detail:r.target.value;if(e.type===\"checkbox\")if(Array.isArray(n)){let i=null;return t.includes(\"number\")?i=Kt(r.target.value):t.includes(\"boolean\")?i=ge(r.target.value):i=r.target.value,r.target.checked?n.includes(i)?n:n.concat([i]):n.filter(o=>!Ui(o,i))}else return r.target.checked;else{if(e.tagName.toLowerCase()===\"select\"&&e.multiple)return t.includes(\"number\")?Array.from(r.target.selectedOptions).map(i=>{let o=i.value||i.text;return Kt(o)}):t.includes(\"boolean\")?Array.from(r.target.selectedOptions).map(i=>{let o=i.value||i.text;return ge(o)}):Array.from(r.target.selectedOptions).map(i=>i.value||i.text);{let i;return e.type===\"radio\"?r.target.checked?i=r.target.value:i=n:i=r.target.value,t.includes(\"number\")?Kt(i):t.includes(\"boolean\")?ge(i):t.includes(\"trim\")?i.trim():i}}})}function Kt(e){let t=e?parseFloat(e):null;return Wi(t)?t:e}function Ui(e,t){return e==t}function Wi(e){return!Array.isArray(e)&&!isNaN(e)}function bn(e){return e!==null&&typeof e==\"object\"&&typeof e.get==\"function\"&&typeof e.set==\"function\"}d(\"cloak\",e=>queueMicrotask(()=>_(()=>e.removeAttribute(C(\"cloak\")))));$e(()=>`[${C(\"init\")}]`);d(\"init\",A((e,{expression:t},{evaluate:r})=>typeof t==\"string\"?!!t.trim()&&r(t,{},!1):r(t,{},!1)));d(\"text\",(e,{expression:t},{effect:r,evaluateLater:n})=>{let i=n(t);r(()=>{i(o=>{_(()=>{e.textContent=o})})})});d(\"html\",(e,{expression:t},{effect:r,evaluateLater:n})=>{let i=n(t);r(()=>{i(o=>{_(()=>{e.innerHTML=o,e._x_ignoreSelf=!0,S(e),delete e._x_ignoreSelf})})})});re(Ie(\":\",ke(C(\"bind:\"))));var wn=(e,{value:t,modifiers:r,expression:n,original:i},{effect:o,cleanup:s})=>{if(!t){let c={};Hr(c),x(e,n)(u=>{Ct(e,u,i)},{scope:c});return}if(t===\"key\")return Gi(e,n);if(e._x_inlineBindings&&e._x_inlineBindings[t]&&e._x_inlineBindings[t].extract)return;let a=x(e,n);o(()=>a(c=>{c===void 0&&typeof n==\"string\"&&n.match(/\\./)&&(c=\"\"),_(()=>he(e,t,c,r))})),s(()=>{e._x_undoAddedClasses&&e._x_undoAddedClasses(),e._x_undoAddedStyles&&e._x_undoAddedStyles()})};wn.inline=(e,{value:t,modifiers:r,expression:n})=>{t&&(e._x_inlineBindings||(e._x_inlineBindings={}),e._x_inlineBindings[t]={expression:n,extract:!1})};d(\"bind\",wn);function Gi(e,t){e._x_keyExpression=t}Le(()=>`[${C(\"data\")}]`);d(\"data\",(e,{expression:t},{cleanup:r})=>{if(Ji(e))return;t=t===\"\"?\"{}\":t;let n={};ue(n,e);let i={};Ur(i,n);let o=M(e,t,{scope:i});(o===void 0||o===!0)&&(o={}),ue(o,e);let s=R(o);Te(s);let a=P(e,s);s.init&&M(e,s.init),r(()=>{s.destroy&&M(e,s.destroy),a()})});K((e,t)=>{e._x_dataStack&&(t._x_dataStack=e._x_dataStack,t.setAttribute(\"data-has-alpine-state\",!0))});function Ji(e){return I?Be?!0:e.hasAttribute(\"data-has-alpine-state\"):!1}d(\"show\",(e,{modifiers:t,expression:r},{effect:n})=>{let i=x(e,r);e._x_doHide||(e._x_doHide=()=>{_(()=>{e.style.setProperty(\"display\",\"none\",t.includes(\"important\")?\"important\":void 0)})}),e._x_doShow||(e._x_doShow=()=>{_(()=>{e.style.length===1&&e.style.display===\"none\"?e.removeAttribute(\"style\"):e.style.removeProperty(\"display\")})});let o=()=>{e._x_doHide(),e._x_isShown=!1},s=()=>{e._x_doShow(),e._x_isShown=!0},a=()=>setTimeout(s),c=me(p=>p?s():o(),p=>{typeof e._x_toggleAndCascadeWithTransitions==\"function\"?e._x_toggleAndCascadeWithTransitions(e,p,s,o):p?a():o()}),l,u=!0;n(()=>i(p=>{!u&&p===l||(t.includes(\"immediate\")&&(p?a():o()),c(p),l=p,u=!1)}))});d(\"for\",(e,{expression:t},{effect:r,cleanup:n})=>{let i=Xi(t),o=x(e,i.items),s=x(e,e._x_keyExpression||\"index\");e._x_prevKeys=[],e._x_lookup={},r(()=>Yi(e,i,o,s)),n(()=>{Object.values(e._x_lookup).forEach(a=>a.remove()),delete e._x_prevKeys,delete e._x_lookup})});function Yi(e,t,r,n){let i=s=>typeof s==\"object\"&&!Array.isArray(s),o=e;r(s=>{Zi(s)&&s>=0&&(s=Array.from(Array(s).keys(),f=>f+1)),s===void 0&&(s=[]);let a=e._x_lookup,c=e._x_prevKeys,l=[],u=[];if(i(s))s=Object.entries(s).map(([f,g])=>{let b=En(t,g,f,s);n(v=>{u.includes(v)&&E(\"Duplicate key on x-for\",e),u.push(v)},{scope:{index:f,...b}}),l.push(b)});else for(let f=0;f<s.length;f++){let g=En(t,s[f],f,s);n(b=>{u.includes(b)&&E(\"Duplicate key on x-for\",e),u.push(b)},{scope:{index:f,...g}}),l.push(g)}let p=[],m=[],w=[],$=[];for(let f=0;f<c.length;f++){let g=c[f];u.indexOf(g)===-1&&w.push(g)}c=c.filter(f=>!w.includes(f));let we=\"template\";for(let f=0;f<u.length;f++){let g=u[f],b=c.indexOf(g);if(b===-1)c.splice(f,0,g),p.push([we,f]);else if(b!==f){let v=c.splice(f,1)[0],O=c.splice(b-1,1)[0];c.splice(f,0,O),c.splice(b,0,v),m.push([v,O])}else $.push(g);we=g}for(let f=0;f<w.length;f++){let g=w[f];a[g]._x_effects&&a[g]._x_effects.forEach(Ee),a[g].remove(),a[g]=null,delete a[g]}for(let f=0;f<m.length;f++){let[g,b]=m[f],v=a[g],O=a[b],Q=document.createElement(\"div\");_(()=>{O||E('x-for \":key\" is undefined or invalid',o,b,a),O.after(Q),v.after(O),O._x_currentIfEl&&O.after(O._x_currentIfEl),Q.before(v),v._x_currentIfEl&&v.after(v._x_currentIfEl),Q.remove()}),O._x_refreshXForScope(l[u.indexOf(b)])}for(let f=0;f<p.length;f++){let[g,b]=p[f],v=g===\"template\"?o:a[g];v._x_currentIfEl&&(v=v._x_currentIfEl);let O=l[b],Q=u[b],ae=document.importNode(o.content,!0).firstElementChild,Vt=R(O);P(ae,Vt,o),ae._x_refreshXForScope=Sn=>{Object.entries(Sn).forEach(([An,On])=>{Vt[An]=On})},_(()=>{v.after(ae),A(()=>S(ae))()}),typeof Q==\"object\"&&E(\"x-for key cannot be an object, it must be a string or an integer\",o),a[Q]=ae}for(let f=0;f<$.length;f++)a[$[f]]._x_refreshXForScope(l[u.indexOf($[f])]);o._x_prevKeys=u})}function Xi(e){let t=/,([^,\\}\\]]*)(?:,([^,\\}\\]]*))?$/,r=/^\\s*\\(|\\)\\s*$/g,n=/([\\s\\S]*?)\\s+(?:in|of)\\s+([\\s\\S]*)/,i=e.match(n);if(!i)return;let o={};o.items=i[2].trim();let s=i[1].replace(r,\"\").trim(),a=s.match(t);return a?(o.item=s.replace(t,\"\").trim(),o.index=a[1].trim(),a[2]&&(o.collection=a[2].trim())):o.item=s,o}function En(e,t,r,n){let i={};return/^\\[.*\\]$/.test(e.item)&&Array.isArray(t)?e.item.replace(\"[\",\"\").replace(\"]\",\"\").split(\",\").map(s=>s.trim()).forEach((s,a)=>{i[s]=t[a]}):/^\\{.*\\}$/.test(e.item)&&!Array.isArray(t)&&typeof t==\"object\"?e.item.replace(\"{\",\"\").replace(\"}\",\"\").split(\",\").map(s=>s.trim()).forEach(s=>{i[s]=t[s]}):i[e.item]=t,e.index&&(i[e.index]=r),e.collection&&(i[e.collection]=n),i}function Zi(e){return!Array.isArray(e)&&!isNaN(e)}function vn(){}vn.inline=(e,{expression:t},{cleanup:r})=>{let n=J(e);n._x_refs||(n._x_refs={}),n._x_refs[t]=e,r(()=>delete n._x_refs[t])};d(\"ref\",vn);d(\"if\",(e,{expression:t},{effect:r,cleanup:n})=>{e.tagName.toLowerCase()!==\"template\"&&E(\"x-if can only be used on a <template> tag\",e);let i=x(e,t),o=()=>{if(e._x_currentIfEl)return e._x_currentIfEl;let a=e.content.cloneNode(!0).firstElementChild;return P(a,{},e),_(()=>{e.after(a),A(()=>S(a))()}),e._x_currentIfEl=a,e._x_undoIf=()=>{T(a,c=>{c._x_effects&&c._x_effects.forEach(Ee)}),a.remove(),delete e._x_currentIfEl},a},s=()=>{e._x_undoIf&&(e._x_undoIf(),delete e._x_undoIf)};r(()=>i(a=>{a?o():s()})),n(()=>e._x_undoIf&&e._x_undoIf())});d(\"id\",(e,{expression:t},{evaluate:r})=>{r(t).forEach(i=>mn(e,i))});K((e,t)=>{e._x_ids&&(t._x_ids=e._x_ids)});re(Ie(\"@\",ke(C(\"on:\"))));d(\"on\",A((e,{value:t,modifiers:r,expression:n},{cleanup:i})=>{let o=n?x(e,n):()=>{};e.tagName.toLowerCase()===\"template\"&&(e._x_forwardEvents||(e._x_forwardEvents=[]),e._x_forwardEvents.includes(t)||e._x_forwardEvents.push(t));let s=se(e,t,r,a=>{o(()=>{},{scope:{$event:a},params:[a]})});i(()=>s())}));tt(\"Collapse\",\"collapse\",\"collapse\");tt(\"Intersect\",\"intersect\",\"intersect\");tt(\"Focus\",\"trap\",\"focus\");tt(\"Mask\",\"mask\",\"mask\");function tt(e,t,r){d(t,n=>E(`You can't use [x-${t}] without first installing the \"${e}\" plugin here: https://alpinejs.dev/plugins/${r}`,n))}B.setEvaluator(gt);B.setReactivityEngine({reactive:Qe,effect:en,release:tn,raw:h});var Ht=B;window.Alpine=Ht;queueMicrotask(()=>{Ht.start()});})();\n"
  },
  {
    "path": "app/assets/javascripts/solid_queue_dashboard/application.js",
    "content": "document.addEventListener('DOMContentLoaded', function() {\n  // Handle clickable rows\n  document.body.addEventListener('mouseup', function(event) {\n    const target = event.target.closest('[data-href]');\n\n    if (target) {\n      event.preventDefault();\n      const href = target.getAttribute('data-href');\n\n      if (event.metaKey || event.ctrlKey || event.button === 1) {\n        window.open(href, '_blank', 'noopener, noreferrer');\n      } else if (event.button === 0) {\n        window.location.href = href;\n      }\n    }\n  });\n\n  // Format dates\n  document.querySelectorAll('[data-date]').forEach(function (element) {\n    const dateString = element.textContent.trim();\n    const date = new Date(dateString);\n\n    if (isNaN(date.getTime())) return;\n\n    const formattedDate = new Intl.DateTimeFormat('en-US', {\n      year: undefined,\n      month: 'short',\n      day: 'numeric',\n      hour: '2-digit',\n      minute: '2-digit',\n      second: '2-digit',\n      hour12: false\n    }).format(date);\n\n    element.textContent = formattedDate;\n    element.setAttribute('title', dateString); // Add original date as title\n  });\n\n  // Handle auto-submit elements\n  document.querySelectorAll('[data-auto-submit]').forEach(function (element) {\n    element.addEventListener('change', function () {\n      const form = element.closest('form');\n      if (form) form.submit();\n    });\n  });\n\n\n  // Auto-refresh functionality for dashboard page\n  const searchParams = new URLSearchParams(window.location.search);\n  const refreshInterval = parseInt(searchParams.get('auto_refresh_period'));\n\n  if (refreshInterval) {\n    setInterval(refreshHomePage, refreshInterval * 1000);\n  }\n\n  function refreshHomePage() {\n    // TODO: Implement a smart refresh strategy using Fetch or Turbo\n    window.location.reload();\n  }\n});\n"
  },
  {
    "path": "app/assets/stylesheets/solid_queue_dashboard/application.css",
    "content": "*, ::before, ::after {\n  --tw-border-spacing-x: 0;\n  --tw-border-spacing-y: 0;\n  --tw-translate-x: 0;\n  --tw-translate-y: 0;\n  --tw-rotate: 0;\n  --tw-skew-x: 0;\n  --tw-skew-y: 0;\n  --tw-scale-x: 1;\n  --tw-scale-y: 1;\n  --tw-pan-x:  ;\n  --tw-pan-y:  ;\n  --tw-pinch-zoom:  ;\n  --tw-scroll-snap-strictness: proximity;\n  --tw-gradient-from-position:  ;\n  --tw-gradient-via-position:  ;\n  --tw-gradient-to-position:  ;\n  --tw-ordinal:  ;\n  --tw-slashed-zero:  ;\n  --tw-numeric-figure:  ;\n  --tw-numeric-spacing:  ;\n  --tw-numeric-fraction:  ;\n  --tw-ring-inset:  ;\n  --tw-ring-offset-width: 0px;\n  --tw-ring-offset-color: #fff;\n  --tw-ring-color: rgb(59 130 246 / 0.5);\n  --tw-ring-offset-shadow: 0 0 #0000;\n  --tw-ring-shadow: 0 0 #0000;\n  --tw-shadow: 0 0 #0000;\n  --tw-shadow-colored: 0 0 #0000;\n  --tw-blur:  ;\n  --tw-brightness:  ;\n  --tw-contrast:  ;\n  --tw-grayscale:  ;\n  --tw-hue-rotate:  ;\n  --tw-invert:  ;\n  --tw-saturate:  ;\n  --tw-sepia:  ;\n  --tw-drop-shadow:  ;\n  --tw-backdrop-blur:  ;\n  --tw-backdrop-brightness:  ;\n  --tw-backdrop-contrast:  ;\n  --tw-backdrop-grayscale:  ;\n  --tw-backdrop-hue-rotate:  ;\n  --tw-backdrop-invert:  ;\n  --tw-backdrop-opacity:  ;\n  --tw-backdrop-saturate:  ;\n  --tw-backdrop-sepia:  ;\n  --tw-contain-size:  ;\n  --tw-contain-layout:  ;\n  --tw-contain-paint:  ;\n  --tw-contain-style:  ;\n}\n\n::backdrop {\n  --tw-border-spacing-x: 0;\n  --tw-border-spacing-y: 0;\n  --tw-translate-x: 0;\n  --tw-translate-y: 0;\n  --tw-rotate: 0;\n  --tw-skew-x: 0;\n  --tw-skew-y: 0;\n  --tw-scale-x: 1;\n  --tw-scale-y: 1;\n  --tw-pan-x:  ;\n  --tw-pan-y:  ;\n  --tw-pinch-zoom:  ;\n  --tw-scroll-snap-strictness: proximity;\n  --tw-gradient-from-position:  ;\n  --tw-gradient-via-position:  ;\n  --tw-gradient-to-position:  ;\n  --tw-ordinal:  ;\n  --tw-slashed-zero:  ;\n  --tw-numeric-figure:  ;\n  --tw-numeric-spacing:  ;\n  --tw-numeric-fraction:  ;\n  --tw-ring-inset:  ;\n  --tw-ring-offset-width: 0px;\n  --tw-ring-offset-color: #fff;\n  --tw-ring-color: rgb(59 130 246 / 0.5);\n  --tw-ring-offset-shadow: 0 0 #0000;\n  --tw-ring-shadow: 0 0 #0000;\n  --tw-shadow: 0 0 #0000;\n  --tw-shadow-colored: 0 0 #0000;\n  --tw-blur:  ;\n  --tw-brightness:  ;\n  --tw-contrast:  ;\n  --tw-grayscale:  ;\n  --tw-hue-rotate:  ;\n  --tw-invert:  ;\n  --tw-saturate:  ;\n  --tw-sepia:  ;\n  --tw-drop-shadow:  ;\n  --tw-backdrop-blur:  ;\n  --tw-backdrop-brightness:  ;\n  --tw-backdrop-contrast:  ;\n  --tw-backdrop-grayscale:  ;\n  --tw-backdrop-hue-rotate:  ;\n  --tw-backdrop-invert:  ;\n  --tw-backdrop-opacity:  ;\n  --tw-backdrop-saturate:  ;\n  --tw-backdrop-sepia:  ;\n  --tw-contain-size:  ;\n  --tw-contain-layout:  ;\n  --tw-contain-paint:  ;\n  --tw-contain-style:  ;\n}\n\n/*\n! tailwindcss v3.4.13 | MIT License | https://tailwindcss.com\n*/\n\n/*\n1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)\n2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)\n*/\n\n*,\n::before,\n::after {\n  box-sizing: border-box;\n  /* 1 */\n  border-width: 0;\n  /* 2 */\n  border-style: solid;\n  /* 2 */\n  border-color: #e5e7eb;\n  /* 2 */\n}\n\n::before,\n::after {\n  --tw-content: '';\n}\n\n/*\n1. Use a consistent sensible line-height in all browsers.\n2. Prevent adjustments of font size after orientation changes in iOS.\n3. Use a more readable tab size.\n4. Use the user's configured `sans` font-family by default.\n5. Use the user's configured `sans` font-feature-settings by default.\n6. Use the user's configured `sans` font-variation-settings by default.\n7. Disable tap highlights on iOS\n*/\n\nhtml,\n:host {\n  line-height: 1.5;\n  /* 1 */\n  -webkit-text-size-adjust: 100%;\n  /* 2 */\n  -moz-tab-size: 4;\n  /* 3 */\n  -o-tab-size: 4;\n     tab-size: 4;\n  /* 3 */\n  font-family: ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\";\n  /* 4 */\n  font-feature-settings: normal;\n  /* 5 */\n  font-variation-settings: normal;\n  /* 6 */\n  -webkit-tap-highlight-color: transparent;\n  /* 7 */\n}\n\n/*\n1. Remove the margin in all browsers.\n2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.\n*/\n\nbody {\n  margin: 0;\n  /* 1 */\n  line-height: inherit;\n  /* 2 */\n}\n\n/*\n1. Add the correct height in Firefox.\n2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)\n3. Ensure horizontal rules are visible by default.\n*/\n\nhr {\n  height: 0;\n  /* 1 */\n  color: inherit;\n  /* 2 */\n  border-top-width: 1px;\n  /* 3 */\n}\n\n/*\nAdd the correct text decoration in Chrome, Edge, and Safari.\n*/\n\nabbr:where([title]) {\n  -webkit-text-decoration: underline dotted;\n          text-decoration: underline dotted;\n}\n\n/*\nRemove the default font size and weight for headings.\n*/\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  font-size: inherit;\n  font-weight: inherit;\n}\n\n/*\nReset links to optimize for opt-in styling instead of opt-out.\n*/\n\na {\n  color: inherit;\n  text-decoration: inherit;\n}\n\n/*\nAdd the correct font weight in Edge and Safari.\n*/\n\nb,\nstrong {\n  font-weight: bolder;\n}\n\n/*\n1. Use the user's configured `mono` font-family by default.\n2. Use the user's configured `mono` font-feature-settings by default.\n3. Use the user's configured `mono` font-variation-settings by default.\n4. Correct the odd `em` font sizing in all browsers.\n*/\n\ncode,\nkbd,\nsamp,\npre {\n  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n  /* 1 */\n  font-feature-settings: normal;\n  /* 2 */\n  font-variation-settings: normal;\n  /* 3 */\n  font-size: 1em;\n  /* 4 */\n}\n\n/*\nAdd the correct font size in all browsers.\n*/\n\nsmall {\n  font-size: 80%;\n}\n\n/*\nPrevent `sub` and `sup` elements from affecting the line height in all browsers.\n*/\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nsup {\n  top: -0.5em;\n}\n\n/*\n1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)\n2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)\n3. Remove gaps between table borders by default.\n*/\n\ntable {\n  text-indent: 0;\n  /* 1 */\n  border-color: inherit;\n  /* 2 */\n  border-collapse: collapse;\n  /* 3 */\n}\n\n/*\n1. Change the font styles in all browsers.\n2. Remove the margin in Firefox and Safari.\n3. Remove default padding in all browsers.\n*/\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  font-family: inherit;\n  /* 1 */\n  font-feature-settings: inherit;\n  /* 1 */\n  font-variation-settings: inherit;\n  /* 1 */\n  font-size: 100%;\n  /* 1 */\n  font-weight: inherit;\n  /* 1 */\n  line-height: inherit;\n  /* 1 */\n  letter-spacing: inherit;\n  /* 1 */\n  color: inherit;\n  /* 1 */\n  margin: 0;\n  /* 2 */\n  padding: 0;\n  /* 3 */\n}\n\n/*\nRemove the inheritance of text transform in Edge and Firefox.\n*/\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Remove default button styles.\n*/\n\nbutton,\ninput:where([type='button']),\ninput:where([type='reset']),\ninput:where([type='submit']) {\n  -webkit-appearance: button;\n  /* 1 */\n  background-color: transparent;\n  /* 2 */\n  background-image: none;\n  /* 2 */\n}\n\n/*\nUse the modern Firefox focus style for all focusable elements.\n*/\n\n:-moz-focusring {\n  outline: auto;\n}\n\n/*\nRemove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)\n*/\n\n:-moz-ui-invalid {\n  box-shadow: none;\n}\n\n/*\nAdd the correct vertical alignment in Chrome and Firefox.\n*/\n\nprogress {\n  vertical-align: baseline;\n}\n\n/*\nCorrect the cursor style of increment and decrement buttons in Safari.\n*/\n\n::-webkit-inner-spin-button,\n::-webkit-outer-spin-button {\n  height: auto;\n}\n\n/*\n1. Correct the odd appearance in Chrome and Safari.\n2. Correct the outline style in Safari.\n*/\n\n[type='search'] {\n  -webkit-appearance: textfield;\n  /* 1 */\n  outline-offset: -2px;\n  /* 2 */\n}\n\n/*\nRemove the inner padding in Chrome and Safari on macOS.\n*/\n\n::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Change font properties to `inherit` in Safari.\n*/\n\n::-webkit-file-upload-button {\n  -webkit-appearance: button;\n  /* 1 */\n  font: inherit;\n  /* 2 */\n}\n\n/*\nAdd the correct display in Chrome and Safari.\n*/\n\nsummary {\n  display: list-item;\n}\n\n/*\nRemoves the default spacing and border for appropriate elements.\n*/\n\nblockquote,\ndl,\ndd,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\nhr,\nfigure,\np,\npre {\n  margin: 0;\n}\n\nfieldset {\n  margin: 0;\n  padding: 0;\n}\n\nlegend {\n  padding: 0;\n}\n\nol,\nul,\nmenu {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n}\n\n/*\nReset default styling for dialogs.\n*/\n\ndialog {\n  padding: 0;\n}\n\n/*\nPrevent resizing textareas horizontally by default.\n*/\n\ntextarea {\n  resize: vertical;\n}\n\n/*\n1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)\n2. Set the default placeholder color to the user's configured gray 400 color.\n*/\n\ninput::-moz-placeholder, textarea::-moz-placeholder {\n  opacity: 1;\n  /* 1 */\n  color: #9ca3af;\n  /* 2 */\n}\n\ninput::placeholder,\ntextarea::placeholder {\n  opacity: 1;\n  /* 1 */\n  color: #9ca3af;\n  /* 2 */\n}\n\n/*\nSet the default cursor for buttons.\n*/\n\nbutton,\n[role=\"button\"] {\n  cursor: pointer;\n}\n\n/*\nMake sure disabled buttons don't get the pointer cursor.\n*/\n\n:disabled {\n  cursor: default;\n}\n\n/*\n1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)\n2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)\n   This can trigger a poorly considered lint error in some tools but is included by design.\n*/\n\nimg,\nsvg,\nvideo,\ncanvas,\naudio,\niframe,\nembed,\nobject {\n  display: block;\n  /* 1 */\n  vertical-align: middle;\n  /* 2 */\n}\n\n/*\nConstrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)\n*/\n\nimg,\nvideo {\n  max-width: 100%;\n  height: auto;\n}\n\n/* Make elements with the HTML hidden attribute stay hidden by default */\n\n[hidden] {\n  display: none;\n}\n\n:root {\n  --background: 0 0% 98%;\n  --foreground: 240 10% 3.9%;\n  --card: 0 0% 100%;\n  --card-foreground: 240 10% 3.9%;\n  --popover: 0 0% 100%;\n  --popover-foreground: 240 10% 3.9%;\n  --primary: 240 5.9% 10%;\n  --primary-foreground: 0 0% 98%;\n  --secondary: 240 4.8% 95.9%;\n  --secondary-foreground: 240 5.9% 10%;\n  --muted: 240 4.8% 95.9%;\n  --muted-foreground: 240 3.8% 46.1%;\n  --accent: 240 4.8% 93.8%;\n  --accent-foreground: 240 5.9% 10%;\n  --destructive: 0 84.2% 60.2%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 5.9% 90%;\n  --input: 240 5.9% 90%;\n  --ring: 240 5.9% 10%;\n  --radius: 0.65rem;\n  --chart-1: 12 76% 61%;\n  --chart-2: 173 58% 39%;\n  --chart-3: 197 37% 24%;\n  --chart-4: 43 74% 66%;\n  --chart-5: 27 87% 67%;\n}\n\n.dark {\n  --background: 240 10% 5.4%;\n  --foreground: 0 0% 92%;\n  --card: 240 10% 3.9%;\n  --card-foreground: 0 0% 92%;\n  --popover: 240 10% 3.9%;\n  --popover-foreground: 0 0% 98%;\n  --primary: 0 0% 95%;\n  --primary-foreground: 240 5.9% 10%;\n  --secondary: 240 3.7% 15.9%;\n  --secondary-foreground: 0 0% 98%;\n  --muted: 240 3.7% 15.9%;\n  --muted-foreground: 240 5% 64.9%;\n  --accent: 240 3.7% 15.9%;\n  --accent-foreground: 0 0% 98%;\n  --destructive: 0 62.8% 30.6%;\n  --destructive-foreground: 0 0% 98%;\n  --border: 240 3.7% 11%;\n  --input: 240 3.7% 15.9%;\n  --ring: 240 4.9% 83.9%;\n  --chart-1: 220 70% 50%;\n  --chart-2: 160 60% 45%;\n  --chart-3: 30 80% 55%;\n  --chart-4: 280 65% 60%;\n  --chart-5: 340 75% 55%;\n}\n\n* {\n  border-color: hsl(var(--border));\n}\n\nbody {\n  background-color: hsl(var(--background));\n  color: hsl(var(--foreground));\n  font-feature-settings: \"rlig\" 1, \"calt\" 1;\n}\n\n[data-href] {\n  cursor: pointer;\n}\n\n.link {\n  text-decoration-line: underline;\n}\n\n.link:hover {\n  opacity: 0.75;\n}\n\n/*\n    Label\n  */\n\n.label {\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n  font-weight: 500;\n  line-height: 1;\n}\n\n.peer:disabled ~ .label {\n  cursor: not-allowed;\n  opacity: 0.7;\n}\n\n/*\n    Select\n  */\n\n.select {\n  -webkit-appearance: none;\n     -moz-appearance: none;\n          appearance: none;\n  background-color: #fff;\n  border-color: #6b7280;\n  border-width: 1px;\n  border-radius: 0px;\n  padding-top: 0.5rem;\n  padding-right: 0.75rem;\n  padding-bottom: 0.5rem;\n  padding-left: 0.75rem;\n  font-size: 1rem;\n  line-height: 1.5rem;\n  --tw-shadow: 0 0 #0000;\n}\n\n.select:focus {\n  outline: 2px solid transparent;\n  outline-offset: 2px;\n  --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/);\n  --tw-ring-offset-width: 0px;\n  --tw-ring-offset-color: #fff;\n  --tw-ring-color: #2563eb;\n  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n  border-color: #2563eb;\n}\n\n.select {\n  background-image: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e\");\n  background-position: right 0.5rem center;\n  background-repeat: no-repeat;\n  background-size: 1.5em 1.5em;\n  padding-right: 2.5rem;\n  -webkit-print-color-adjust: exact;\n          print-color-adjust: exact;\n}\n\n.select:where([size]:not([size=\"1\"])) {\n  background-image: initial;\n  background-position: initial;\n  background-repeat: unset;\n  background-size: initial;\n  padding-right: 0.75rem;\n  -webkit-print-color-adjust: unset;\n          print-color-adjust: unset;\n}\n\n.select {\n  height: 2.5rem;\n  width: 12rem;\n  border-radius: calc(var(--radius) - 2px);\n  border-width: 1px;\n  border-color: hsl(var(--input));\n  --tw-bg-opacity: 1;\n  background-color: rgb(255 255 255 / var(--tw-bg-opacity));\n  padding-left: 0.75rem;\n  padding-right: 0.75rem;\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n  color: hsl(var(--foreground));\n  --tw-ring-offset-color: hsl(var(--background));\n}\n\n.select::file-selector-button {\n  border-width: 0px;\n  background-color: transparent;\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n  font-weight: 500;\n}\n\n.select::-moz-placeholder {\n  color: hsl(var(--muted-foreground));\n}\n\n.select::placeholder {\n  color: hsl(var(--muted-foreground));\n}\n\n.select:focus-visible {\n  outline: 2px solid transparent;\n  outline-offset: 2px;\n  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);\n  --tw-ring-color: hsl(var(--ring));\n  --tw-ring-offset-width: 2px;\n}\n\n.select:disabled {\n  cursor: not-allowed;\n  opacity: 0.5;\n}\n\n.select:is(.dark *) {\n  --tw-bg-opacity: 1;\n  background-color: rgb(0 0 0 / var(--tw-bg-opacity));\n}\n\n/*\n    Badge\n  */\n\n.badge {\n  display: inline-flex;\n  align-items: center;\n  -moz-column-gap: 0.375rem;\n       column-gap: 0.375rem;\n  border-radius: calc(var(--radius) - 2px);\n  border-width: 1px;\n  padding-left: 0.375rem;\n  padding-right: 0.375rem;\n  padding-top: 0.125rem;\n  padding-bottom: 0.125rem;\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n  font-weight: 500;\n}\n\n@media (min-width: 640px) {\n  .badge {\n    font-size: 0.75rem;\n    line-height: 1.25rem;\n  }\n}\n\n@media (forced-colors: active) {\n  .badge {\n    outline-style: solid;\n  }\n}\n\n.badge-primary {\n  border-color: transparent;\n  background-color: hsl(var(--primary));\n  color: hsl(var(--primary-foreground));\n}\n\n.badge-primary:hover {\n  background-color: hsl(var(--primary) / 0.8);\n}\n\n.badge-secondary {\n  border-color: transparent;\n  background-color: hsl(var(--secondary));\n  color: hsl(var(--secondary-foreground));\n}\n\n.badge-secondary:hover {\n  background-color: hsl(var(--secondary) / 0.8);\n}\n\n.badge-destructive {\n  border-color: transparent;\n  background-color: hsl(var(--destructive) / 0.15);\n  color: hsl(var(--destructive));\n}\n\n.badge-destructive:is(.dark *) {\n  background-color: hsl(var(--destructive) / 0.1);\n  color: hsl(var(--destructive-foreground));\n}\n\n.badge-outline {\n  color: hsl(var(--foreground));\n}\n\n.badge-red {\n  border-color: transparent;\n  background-color: rgb(239 68 68 / 0.15);\n  --tw-text-opacity: 1;\n  color: rgb(185 28 28 / var(--tw-text-opacity));\n}\n\n.badge-red:is(.dark *) {\n  background-color: rgb(239 68 68 / 0.1);\n  --tw-text-opacity: 1;\n  color: rgb(248 113 113 / var(--tw-text-opacity));\n}\n\n.badge-amber {\n  border-color: transparent;\n  background-color: rgb(251 191 36 / 0.2);\n  --tw-text-opacity: 1;\n  color: rgb(180 83 9 / var(--tw-text-opacity));\n}\n\n.badge-amber:is(.dark *) {\n  background-color: rgb(251 191 36 / 0.1);\n  --tw-text-opacity: 1;\n  color: rgb(251 191 36 / var(--tw-text-opacity));\n}\n\n.badge-yellow {\n  border-color: transparent;\n  background-color: rgb(250 204 21 / 0.2);\n  --tw-text-opacity: 1;\n  color: rgb(161 98 7 / var(--tw-text-opacity));\n}\n\n.badge-yellow:is(.dark *) {\n  background-color: rgb(250 204 21 / 0.1);\n  --tw-text-opacity: 1;\n  color: rgb(253 224 71 / var(--tw-text-opacity));\n}\n\n.badge-green {\n  border-color: transparent;\n  background-color: rgb(34 197 94 / 0.15);\n  --tw-text-opacity: 1;\n  color: rgb(21 128 61 / var(--tw-text-opacity));\n}\n\n.badge-green:is(.dark *) {\n  background-color: rgb(34 197 94 / 0.1);\n  --tw-text-opacity: 1;\n  color: rgb(74 222 128 / var(--tw-text-opacity));\n}\n\n.badge-emerald {\n  border-color: transparent;\n  background-color: rgb(16 185 129 / 0.15);\n  --tw-text-opacity: 1;\n  color: rgb(4 120 87 / var(--tw-text-opacity));\n}\n\n.badge-emerald:is(.dark *) {\n  background-color: rgb(16 185 129 / 0.1);\n  --tw-text-opacity: 1;\n  color: rgb(52 211 153 / var(--tw-text-opacity));\n}\n\n.badge-sky {\n  border-color: transparent;\n  background-color: rgb(14 165 233 / 0.15);\n  --tw-text-opacity: 1;\n  color: rgb(3 105 161 / var(--tw-text-opacity));\n}\n\n.badge-sky:is(.dark *) {\n  background-color: rgb(14 165 233 / 0.1);\n  --tw-text-opacity: 1;\n  color: rgb(125 211 252 / var(--tw-text-opacity));\n}\n\n.badge-blue {\n  border-color: transparent;\n  background-color: rgb(59 130 246 / 0.15);\n  --tw-text-opacity: 1;\n  color: rgb(29 78 216 / var(--tw-text-opacity));\n}\n\n.badge-blue:is(.dark *) {\n  --tw-text-opacity: 1;\n  color: rgb(96 165 250 / var(--tw-text-opacity));\n}\n\n.badge-indigo {\n  border-color: transparent;\n  background-color: rgb(99 102 241 / 0.15);\n  --tw-text-opacity: 1;\n  color: rgb(67 56 202 / var(--tw-text-opacity));\n}\n\n.badge-indigo:is(.dark *) {\n  --tw-text-opacity: 1;\n  color: rgb(129 140 248 / var(--tw-text-opacity));\n}\n\n.badge-purple {\n  border-color: transparent;\n  background-color: rgb(168 85 247 / 0.15);\n  --tw-text-opacity: 1;\n  color: rgb(126 34 206 / var(--tw-text-opacity));\n}\n\n.badge-purple:is(.dark *) {\n  --tw-text-opacity: 1;\n  color: rgb(192 132 252 / var(--tw-text-opacity));\n}\n\n.badge-zinc {\n  border-color: transparent;\n  background-color: rgb(82 82 91 / 0.075);\n  --tw-text-opacity: 1;\n  color: rgb(63 63 70 / var(--tw-text-opacity));\n}\n\n.badge-zinc:is(.dark *) {\n  background-color: rgb(255 255 255 / 0.05);\n  --tw-text-opacity: 1;\n  color: rgb(161 161 170 / var(--tw-text-opacity));\n}\n\n/*\n    Circle\n  */\n\n.circle {\n  display: inline-flex;\n  width: 0.5rem;\n  height: 0.5rem;\n  align-items: center;\n  justify-content: center;\n  border-radius: 9999px;\n}\n\n.circle-red {\n  --tw-bg-opacity: 1;\n  background-color: rgb(239 68 68 / var(--tw-bg-opacity));\n}\n\n.circle-amber {\n  --tw-bg-opacity: 1;\n  background-color: rgb(251 191 36 / var(--tw-bg-opacity));\n}\n\n.circle-yellow {\n  --tw-bg-opacity: 1;\n  background-color: rgb(250 204 21 / var(--tw-bg-opacity));\n}\n\n.circle-green {\n  --tw-bg-opacity: 1;\n  background-color: rgb(34 197 94 / var(--tw-bg-opacity));\n}\n\n.circle-sky {\n  --tw-bg-opacity: 1;\n  background-color: rgb(14 165 233 / var(--tw-bg-opacity));\n}\n\n.circle-blue {\n  --tw-bg-opacity: 1;\n  background-color: rgb(59 130 246 / var(--tw-bg-opacity));\n}\n\n.circle-indigo {\n  --tw-bg-opacity: 1;\n  background-color: rgb(99 102 241 / var(--tw-bg-opacity));\n}\n\n.circle-purple {\n  --tw-bg-opacity: 1;\n  background-color: rgb(168 85 247 / var(--tw-bg-opacity));\n}\n\n.circle-zinc {\n  --tw-bg-opacity: 1;\n  background-color: rgb(161 161 170 / var(--tw-bg-opacity));\n}\n\n/*\n    Alert\n  */\n\n.alert {\n  position: relative;\n  width: 100%;\n  border-radius: var(--radius);\n  border-width: 1px;\n  padding: 1rem;\n}\n\n.alert>svg+div {\n  --tw-translate-y: -3px;\n  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n\n.alert>svg {\n  position: absolute;\n  left: 1rem;\n  top: 1rem;\n  color: hsl(var(--foreground));\n}\n\n.alert>svg~* {\n  padding-left: 1.75rem;\n}\n\n.alert-default {\n  background-color: hsl(var(--background));\n  color: hsl(var(--foreground));\n}\n\n.alert-red {\n  border-color: rgb(239 68 68 / 0.5);\n  --tw-text-opacity: 1;\n  color: rgb(185 28 28 / var(--tw-text-opacity));\n}\n\n.alert-red:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-color: rgb(239 68 68 / var(--tw-border-opacity));\n  --tw-text-opacity: 1;\n  color: rgb(252 165 165 / var(--tw-text-opacity));\n}\n\n.alert-red>svg {\n  --tw-text-opacity: 1;\n  color: rgb(239 68 68 / var(--tw-text-opacity));\n}\n\n.alert-green {\n  border-color: rgb(34 197 94 / 0.5);\n  --tw-text-opacity: 1;\n  color: rgb(21 128 61 / var(--tw-text-opacity));\n}\n\n.alert-green:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-color: rgb(34 197 94 / var(--tw-border-opacity));\n  --tw-text-opacity: 1;\n  color: rgb(134 239 172 / var(--tw-text-opacity));\n}\n\n.alert-green>svg {\n  --tw-text-opacity: 1;\n  color: rgb(34 197 94 / var(--tw-text-opacity));\n}\n\n.alert-yellow {\n  border-color: rgb(234 179 8 / 0.5);\n  --tw-text-opacity: 1;\n  color: rgb(161 98 7 / var(--tw-text-opacity));\n}\n\n.alert-yellow:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-color: rgb(234 179 8 / var(--tw-border-opacity));\n  --tw-text-opacity: 1;\n  color: rgb(253 224 71 / var(--tw-text-opacity));\n}\n\n.alert-yellow>svg {\n  --tw-text-opacity: 1;\n  color: rgb(234 179 8 / var(--tw-text-opacity));\n}\n\n.alert-blue {\n  border-color: rgb(59 130 246 / 0.5);\n  --tw-text-opacity: 1;\n  color: rgb(29 78 216 / var(--tw-text-opacity));\n}\n\n.alert-blue:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-color: rgb(59 130 246 / var(--tw-border-opacity));\n  --tw-text-opacity: 1;\n  color: rgb(147 197 253 / var(--tw-text-opacity));\n}\n\n.alert-blue>svg {\n  --tw-text-opacity: 1;\n  color: rgb(59 130 246 / var(--tw-text-opacity));\n}\n\n.alert-title {\n  margin-bottom: 0.25rem;\n  font-weight: 500;\n  line-height: 1;\n  letter-spacing: -0.025em;\n}\n\n.alert-description {\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n}\n\n.alert-description p {\n  line-height: 1.625;\n}\n\n/*\n    Button\n  */\n\n.btn {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  border-radius: calc(var(--radius) - 2px);\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n  font-weight: 500;\n  --tw-ring-offset-color: hsl(var(--background));\n  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n  transition-duration: 150ms;\n}\n\n.btn:focus-visible {\n  outline: 2px solid transparent;\n  outline-offset: 2px;\n  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);\n  --tw-ring-color: hsl(var(--ring));\n  --tw-ring-offset-width: 2px;\n}\n\n.btn:disabled {\n  pointer-events: none;\n  opacity: 0.5;\n}\n\n.btn-outline {\n  border-width: 1px;\n  border-color: hsl(var(--input));\n  background-color: hsl(var(--background));\n}\n\n.btn-outline:hover {\n  background-color: hsl(var(--accent));\n  color: hsl(var(--accent-foreground));\n}\n\n.btn-secondary {\n  background-color: hsl(var(--secondary));\n  color: hsl(var(--secondary-foreground));\n}\n\n.btn-secondary:hover {\n  background-color: hsl(var(--secondary) / 0.8);\n}\n\n.btn-xs {\n  height: 1.75rem;\n  gap: 0.25rem;\n  border-radius: calc(var(--radius) - 2px);\n  padding-left: 0.5rem;\n  padding-right: 0.5rem;\n}\n\n.btn-sm {\n  height: 2.25rem;\n  gap: 0.375rem;\n  border-radius: calc(var(--radius) - 2px);\n  padding-left: 0.75rem;\n  padding-right: 0.75rem;\n}\n\n.btn-md {\n  height: 2.5rem;\n  gap: 0.375rem;\n  padding-left: 1rem;\n  padding-right: 1rem;\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n}\n\n.btn-icon {\n  height: 2.5rem;\n  width: 2.5rem;\n}\n\n/*\n    Info Line\n  */\n\n.info-line {\n  display: flex;\n  align-items: center;\n  gap: 1rem;\n}\n\n.info-line-label {\n  white-space: nowrap;\n  --tw-text-opacity: 1;\n  color: rgb(113 113 122 / var(--tw-text-opacity));\n}\n\n.info-line-separator {\n  height: 1px;\n  flex: 1 1 0%;\n  --tw-translate-y: 1px;\n  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n  background-color: rgb(9 9 11 / 0.1);\n}\n\n.info-line-separator:is(.dark *) {\n  border-color: rgb(255 255 255 / 0.1);\n}\n\n.info-line-value {\n  text-align: right;\n  font-weight: 500;\n  --tw-text-opacity: 1;\n  color: rgb(9 9 11 / var(--tw-text-opacity));\n}\n\n.info-line-value:is(.dark *) {\n  --tw-text-opacity: 1;\n  color: rgb(255 255 255 / var(--tw-text-opacity));\n}\n\n/*\n    Card\n  */\n\n.card {\n  border-radius: var(--radius);\n  border-width: 1px;\n  background-color: hsl(var(--card));\n  color: hsl(var(--card-foreground));\n  --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);\n  --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);\n  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n\n.card-header {\n  display: flex;\n  flex-direction: column;\n}\n\n.card-header > :not([hidden]) ~ :not([hidden]) {\n  --tw-space-y-reverse: 0;\n  margin-top: calc(0.375rem * calc(1 - var(--tw-space-y-reverse)));\n  margin-bottom: calc(0.375rem * var(--tw-space-y-reverse));\n}\n\n.card-header {\n  padding: 1.5rem;\n}\n\n.card-title {\n  font-size: 1.5rem;\n  line-height: 2rem;\n  font-weight: 600;\n  line-height: 1;\n  letter-spacing: -0.025em;\n}\n\n.card-description {\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n  color: hsl(var(--muted-foreground));\n}\n\n.card-content {\n  padding: 1.5rem;\n  padding-top: 0px;\n}\n\n.card-footer {\n  display: flex;\n  align-items: center;\n  padding: 1.5rem;\n  padding-top: 0px;\n}\n\n/*\n    Navbar\n  */\n\n.navbar {\n  display: flex;\n  align-items: center;\n  gap: 1rem;\n  background-color: hsl(var(--background));\n  padding-top: 1rem;\n  padding-bottom: 1rem;\n}\n\n.navbar-section {\n  display: flex;\n  gap: 0.375rem;\n}\n\n.navbar-item {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  border-radius: calc(var(--radius) - 2px);\n  padding-left: 0.75rem;\n  padding-right: 0.75rem;\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n  font-weight: 500;\n  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n  transition-duration: 150ms;\n}\n\n.navbar-item:focus-visible {\n  outline: 2px solid transparent;\n  outline-offset: 2px;\n  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);\n  --tw-ring-color: hsl(var(--ring));\n  --tw-ring-offset-width: 2px;\n}\n\n.navbar-item-default {\n  color: hsl(var(--foreground));\n}\n\n.navbar-item-default:hover {\n  background-color: hsl(var(--accent));\n  color: hsl(var(--accent-foreground));\n}\n\n.navbar-item-current {\n  background-color: hsl(var(--primary));\n  color: hsl(var(--primary-foreground));\n}\n\n/*\n    Table\n  */\n\n.table-wrapper {\n  position: relative;\n  width: 100%;\n  overflow: auto;\n}\n\n.table {\n  width: 100%;\n  caption-side: bottom;\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n}\n\n.table-header tr {\n  border-bottom-width: 1px;\n}\n\n.table-body tr:last-child {\n  border-width: 0px;\n}\n\n.table-row {\n  border-bottom-width: 1px;\n  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n  transition-duration: 150ms;\n}\n\n.table-row:hover {\n  background-color: hsl(var(--muted) / 0.5);\n}\n\n.table-row[data-state=\"selected\"] {\n  background-color: hsl(var(--muted));\n}\n\n.table-head {\n  height: 3rem;\n  white-space: nowrap;\n  padding-left: 1rem;\n  padding-right: 1rem;\n  text-align: left;\n  vertical-align: middle;\n  font-weight: 500;\n  color: hsl(var(--muted-foreground));\n}\n\n.table-head:has([role=checkbox]) {\n  padding-right: 0px;\n}\n\n.table-cell {\n  padding: 1rem;\n  vertical-align: middle;\n}\n\n.table-cell:has([role=checkbox]) {\n  padding-right: 0px;\n}\n\n/*\n    Pagination\n  */\n\n.pagination {\n  display: flex;\n  justify-content: center;\n}\n\n.pagination-content {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  gap: 0.25rem;\n}\n\n.pagination-item {\n  display: inline-block;\n}\n\n.pagination-link {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  border-radius: calc(var(--radius) - 2px);\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n  font-weight: 500;\n  --tw-ring-offset-color: hsl(var(--background));\n  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n  transition-duration: 150ms;\n}\n\n.pagination-link:focus-visible {\n  outline: 2px solid transparent;\n  outline-offset: 2px;\n  --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n  --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n  box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);\n  --tw-ring-color: hsl(var(--ring));\n  --tw-ring-offset-width: 2px;\n}\n\n.pagination-link:disabled {\n  pointer-events: none;\n  opacity: 0.5;\n}\n\n.pagination-link-active {\n  border-width: 1px;\n  border-color: hsl(var(--input));\n  background-color: hsl(var(--background));\n}\n\n.pagination-link-active:hover {\n  background-color: hsl(var(--accent));\n  color: hsl(var(--accent-foreground));\n}\n\n.pagination-link-inactive:hover {\n  background-color: hsl(var(--accent));\n  color: hsl(var(--accent-foreground));\n}\n\n.pagination-link-default {\n  height: 2.5rem;\n  padding-left: 1rem;\n  padding-right: 1rem;\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n}\n\n.pagination-previous,\n  .pagination-next {\n  height: 2.5rem;\n  gap: 0.25rem;\n  padding-left: 1rem;\n  padding-right: 1rem;\n  padding-top: 0.5rem;\n  padding-bottom: 0.5rem;\n}\n\n.pagination-previous {\n  padding-left: 0.625rem;\n}\n\n.pagination-next {\n  padding-right: 0.625rem;\n}\n\n.pagination-ellipsis {\n  display: flex;\n  height: 2.25rem;\n  width: 2.25rem;\n  align-items: center;\n  justify-content: center;\n}\n\n.static {\n  position: static;\n}\n\n.absolute {\n  position: absolute;\n}\n\n.relative {\n  position: relative;\n}\n\n.right-6 {\n  right: 1.5rem;\n}\n\n.top-6 {\n  top: 1.5rem;\n}\n\n.mx-auto {\n  margin-left: auto;\n  margin-right: auto;\n}\n\n.\\!mt-4 {\n  margin-top: 1rem !important;\n}\n\n.-ml-0\\.5 {\n  margin-left: -0.125rem;\n}\n\n.mb-6 {\n  margin-bottom: 1.5rem;\n}\n\n.mb-8 {\n  margin-bottom: 2rem;\n}\n\n.ml-0\\.5 {\n  margin-left: 0.125rem;\n}\n\n.ml-1 {\n  margin-left: 0.25rem;\n}\n\n.ml-1\\.5 {\n  margin-left: 0.375rem;\n}\n\n.ml-2 {\n  margin-left: 0.5rem;\n}\n\n.ml-4 {\n  margin-left: 1rem;\n}\n\n.ml-8 {\n  margin-left: 2rem;\n}\n\n.ml-auto {\n  margin-left: auto;\n}\n\n.mr-0\\.5 {\n  margin-right: 0.125rem;\n}\n\n.mr-1 {\n  margin-right: 0.25rem;\n}\n\n.mr-1\\.5 {\n  margin-right: 0.375rem;\n}\n\n.mt-0\\.5 {\n  margin-top: 0.125rem;\n}\n\n.mt-1 {\n  margin-top: 0.25rem;\n}\n\n.mt-2 {\n  margin-top: 0.5rem;\n}\n\n.mt-4 {\n  margin-top: 1rem;\n}\n\n.mt-6 {\n  margin-top: 1.5rem;\n}\n\n.mt-8 {\n  margin-top: 2rem;\n}\n\n.inline-block {\n  display: inline-block;\n}\n\n.flex {\n  display: flex;\n}\n\n.inline-flex {\n  display: inline-flex;\n}\n\n.table {\n  display: table;\n}\n\n.table-cell {\n  display: table-cell;\n}\n\n.table-row {\n  display: table-row;\n}\n\n.grid {\n  display: grid;\n}\n\n.\\!size-4 {\n  width: 1rem !important;\n  height: 1rem !important;\n}\n\n.size-3 {\n  width: 0.75rem;\n  height: 0.75rem;\n}\n\n.size-3\\.5 {\n  width: 0.875rem;\n  height: 0.875rem;\n}\n\n.size-4 {\n  width: 1rem;\n  height: 1rem;\n}\n\n.h-5 {\n  height: 1.25rem;\n}\n\n.w-24 {\n  width: 6rem;\n}\n\n.w-40 {\n  width: 10rem;\n}\n\n.w-5 {\n  width: 1.25rem;\n}\n\n.max-w-\\[1920px\\] {\n  max-width: 1920px;\n}\n\n.-translate-y-px {\n  --tw-translate-y: -1px;\n  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n\n.translate-y-px {\n  --tw-translate-y: 1px;\n  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n\n.list-decimal {\n  list-style-type: decimal;\n}\n\n.grid-cols-1 {\n  grid-template-columns: repeat(1, minmax(0, 1fr));\n}\n\n.grid-cols-6 {\n  grid-template-columns: repeat(6, minmax(0, 1fr));\n}\n\n.\\!flex-row {\n  flex-direction: row !important;\n}\n\n.flex-row {\n  flex-direction: row;\n}\n\n.flex-wrap {\n  flex-wrap: wrap;\n}\n\n.items-start {\n  align-items: flex-start;\n}\n\n.items-center {\n  align-items: center;\n}\n\n.justify-center {\n  justify-content: center;\n}\n\n.justify-between {\n  justify-content: space-between;\n}\n\n.gap-0\\.5 {\n  gap: 0.125rem;\n}\n\n.gap-1 {\n  gap: 0.25rem;\n}\n\n.gap-1\\.5 {\n  gap: 0.375rem;\n}\n\n.gap-2 {\n  gap: 0.5rem;\n}\n\n.gap-4 {\n  gap: 1rem;\n}\n\n.space-y-1 > :not([hidden]) ~ :not([hidden]) {\n  --tw-space-y-reverse: 0;\n  margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));\n  margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));\n}\n\n.space-y-1\\.5 > :not([hidden]) ~ :not([hidden]) {\n  --tw-space-y-reverse: 0;\n  margin-top: calc(0.375rem * calc(1 - var(--tw-space-y-reverse)));\n  margin-bottom: calc(0.375rem * var(--tw-space-y-reverse));\n}\n\n.space-y-3 > :not([hidden]) ~ :not([hidden]) {\n  --tw-space-y-reverse: 0;\n  margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));\n  margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));\n}\n\n.space-y-4 > :not([hidden]) ~ :not([hidden]) {\n  --tw-space-y-reverse: 0;\n  margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));\n  margin-bottom: calc(1rem * var(--tw-space-y-reverse));\n}\n\n.overflow-hidden {\n  overflow: hidden;\n}\n\n.truncate {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.whitespace-nowrap {\n  white-space: nowrap;\n}\n\n.text-balance {\n  text-wrap: balance;\n}\n\n.border-b {\n  border-bottom-width: 1px;\n}\n\n.border-t {\n  border-top-width: 1px;\n}\n\n.border-t-4 {\n  border-top-width: 4px;\n}\n\n.border-t-amber-500 {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(245 158 11 / var(--tw-border-opacity));\n}\n\n.border-t-blue-500 {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(59 130 246 / var(--tw-border-opacity));\n}\n\n.border-t-purple-500 {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(168 85 247 / var(--tw-border-opacity));\n}\n\n.border-t-red-500 {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(239 68 68 / var(--tw-border-opacity));\n}\n\n.border-t-sky-500 {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(14 165 233 / var(--tw-border-opacity));\n}\n\n.border-t-zinc-500 {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(113 113 122 / var(--tw-border-opacity));\n}\n\n.bg-primary\\/7\\.5 {\n  background-color: hsl(var(--primary) / 0.075);\n}\n\n.\\!p-0 {\n  padding: 0px !important;\n}\n\n.p-0 {\n  padding: 0px;\n}\n\n.p-6 {\n  padding: 1.5rem;\n}\n\n.px-2 {\n  padding-left: 0.5rem;\n  padding-right: 0.5rem;\n}\n\n.px-4 {\n  padding-left: 1rem;\n  padding-right: 1rem;\n}\n\n.px-6 {\n  padding-left: 1.5rem;\n  padding-right: 1.5rem;\n}\n\n.py-12 {\n  padding-top: 3rem;\n  padding-bottom: 3rem;\n}\n\n.pb-\\[15vh\\] {\n  padding-bottom: 15vh;\n}\n\n.pl-1 {\n  padding-left: 0.25rem;\n}\n\n.pl-6 {\n  padding-left: 1.5rem;\n}\n\n.pt-5 {\n  padding-top: 1.25rem;\n}\n\n.pt-6 {\n  padding-top: 1.5rem;\n}\n\n.text-center {\n  text-align: center;\n}\n\n.font-mono {\n  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n}\n\n.text-4xl {\n  font-size: 2.25rem;\n  line-height: 2.5rem;\n}\n\n.text-lg {\n  font-size: 1.125rem;\n  line-height: 1.75rem;\n}\n\n.text-sm {\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n}\n\n.text-xl {\n  font-size: 1.25rem;\n  line-height: 1.75rem;\n}\n\n.text-xs {\n  font-size: 0.75rem;\n  line-height: 1rem;\n}\n\n.font-bold {\n  font-weight: 700;\n}\n\n.font-medium {\n  font-weight: 500;\n}\n\n.font-normal {\n  font-weight: 400;\n}\n\n.capitalize {\n  text-transform: capitalize;\n}\n\n.tracking-tight {\n  letter-spacing: -0.025em;\n}\n\n.tracking-tighter {\n  letter-spacing: -0.05em;\n}\n\n.text-amber-500 {\n  --tw-text-opacity: 1;\n  color: rgb(245 158 11 / var(--tw-text-opacity));\n}\n\n.text-amber-600 {\n  --tw-text-opacity: 1;\n  color: rgb(217 119 6 / var(--tw-text-opacity));\n}\n\n.text-black {\n  --tw-text-opacity: 1;\n  color: rgb(0 0 0 / var(--tw-text-opacity));\n}\n\n.text-foreground {\n  color: hsl(var(--foreground));\n}\n\n.text-muted-foreground {\n  color: hsl(var(--muted-foreground));\n}\n\n.text-muted-foreground\\/30 {\n  color: hsl(var(--muted-foreground) / 0.3);\n}\n\n.text-red-500 {\n  --tw-text-opacity: 1;\n  color: rgb(239 68 68 / var(--tw-text-opacity));\n}\n\n.text-red-600 {\n  --tw-text-opacity: 1;\n  color: rgb(220 38 38 / var(--tw-text-opacity));\n}\n\n.text-zinc-900 {\n  --tw-text-opacity: 1;\n  color: rgb(24 24 27 / var(--tw-text-opacity));\n}\n\n.opacity-50 {\n  opacity: 0.5;\n}\n\n@keyframes enter {\n  from {\n    opacity: var(--tw-enter-opacity, 1);\n    transform: translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0));\n  }\n}\n\n@keyframes exit {\n  to {\n    opacity: var(--tw-exit-opacity, 1);\n    transform: translate3d(var(--tw-exit-translate-x, 0), var(--tw-exit-translate-y, 0), 0) scale3d(var(--tw-exit-scale, 1), var(--tw-exit-scale, 1), var(--tw-exit-scale, 1)) rotate(var(--tw-exit-rotate, 0));\n  }\n}\n\n.running {\n  animation-play-state: running;\n}\n\n.marker\\:text-sm *::marker {\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n}\n\n.marker\\:text-muted-foreground *::marker {\n  color: hsl(var(--muted-foreground));\n}\n\n.marker\\:text-sm::marker {\n  font-size: 0.875rem;\n  line-height: 1.25rem;\n}\n\n.marker\\:text-muted-foreground::marker {\n  color: hsl(var(--muted-foreground));\n}\n\n.hover\\:bg-primary\\/10:hover {\n  background-color: hsl(var(--primary) / 0.1);\n}\n\n.hover\\:text-foreground:hover {\n  color: hsl(var(--foreground));\n}\n\n.hover\\:underline:hover {\n  text-decoration-line: underline;\n}\n\n.dark\\:border-t-amber-600:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(217 119 6 / var(--tw-border-opacity));\n}\n\n.dark\\:border-t-blue-600:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(37 99 235 / var(--tw-border-opacity));\n}\n\n.dark\\:border-t-purple-600:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(147 51 234 / var(--tw-border-opacity));\n}\n\n.dark\\:border-t-sky-600:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(2 132 199 / var(--tw-border-opacity));\n}\n\n.dark\\:border-t-zinc-600:is(.dark *) {\n  --tw-border-opacity: 1;\n  border-top-color: rgb(82 82 91 / var(--tw-border-opacity));\n}\n\n.dark\\:text-red-500:is(.dark *) {\n  --tw-text-opacity: 1;\n  color: rgb(239 68 68 / var(--tw-text-opacity));\n}\n\n.dark\\:text-white:is(.dark *) {\n  --tw-text-opacity: 1;\n  color: rgb(255 255 255 / var(--tw-text-opacity));\n}\n\n.dark\\:text-zinc-100:is(.dark *) {\n  --tw-text-opacity: 1;\n  color: rgb(244 244 245 / var(--tw-text-opacity));\n}\n\n@media (min-width: 640px) {\n  .sm\\:grid-cols-2 {\n    grid-template-columns: repeat(2, minmax(0, 1fr));\n  }\n\n  .sm\\:gap-16 {\n    gap: 4rem;\n  }\n\n  .sm\\:px-6 {\n    padding-left: 1.5rem;\n    padding-right: 1.5rem;\n  }\n\n  .sm\\:pb-\\[25vh\\] {\n    padding-bottom: 25vh;\n  }\n}\n\n@media (min-width: 768px) {\n  .md\\:gap-20 {\n    gap: 5rem;\n  }\n}\n\n@media (min-width: 1024px) {\n  .lg\\:px-8 {\n    padding-left: 2rem;\n    padding-right: 2rem;\n  }\n}\n"
  },
  {
    "path": "app/assets/stylesheets/solid_queue_dashboard/tailwind.css",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n  :root {\n    --background: 0 0% 98%;\n    --foreground: 240 10% 3.9%;\n    --card: 0 0% 100%;\n    --card-foreground: 240 10% 3.9%;\n    --popover: 0 0% 100%;\n    --popover-foreground: 240 10% 3.9%;\n    --primary: 240 5.9% 10%;\n    --primary-foreground: 0 0% 98%;\n    --secondary: 240 4.8% 95.9%;\n    --secondary-foreground: 240 5.9% 10%;\n    --muted: 240 4.8% 95.9%;\n    --muted-foreground: 240 3.8% 46.1%;\n    --accent: 240 4.8% 93.8%;\n    --accent-foreground: 240 5.9% 10%;\n    --destructive: 0 84.2% 60.2%;\n    --destructive-foreground: 0 0% 98%;\n    --border: 240 5.9% 90%;\n    --input: 240 5.9% 90%;\n    --ring: 240 5.9% 10%;\n    --radius: 0.65rem;\n    --chart-1: 12 76% 61%;\n    --chart-2: 173 58% 39%;\n    --chart-3: 197 37% 24%;\n    --chart-4: 43 74% 66%;\n    --chart-5: 27 87% 67%;\n  }\n\n  .dark {\n    --background: 240 10% 5.4%;\n    --foreground: 0 0% 92%;\n    --card: 240 10% 3.9%;\n    --card-foreground: 0 0% 92%;\n    --popover: 240 10% 3.9%;\n    --popover-foreground: 0 0% 98%;\n    --primary: 0 0% 95%;\n    --primary-foreground: 240 5.9% 10%;\n    --secondary: 240 3.7% 15.9%;\n    --secondary-foreground: 0 0% 98%;\n    --muted: 240 3.7% 15.9%;\n    --muted-foreground: 240 5% 64.9%;\n    --accent: 240 3.7% 15.9%;\n    --accent-foreground: 0 0% 98%;\n    --destructive: 0 62.8% 30.6%;\n    --destructive-foreground: 0 0% 98%;\n    --border: 240 3.7% 11%;\n    --input: 240 3.7% 15.9%;\n    --ring: 240 4.9% 83.9%;\n    --chart-1: 220 70% 50%;\n    --chart-2: 160 60% 45%;\n    --chart-3: 30 80% 55%;\n    --chart-4: 280 65% 60%;\n    --chart-5: 340 75% 55%;\n  }\n}\n\n@layer base {\n  * {\n    @apply border-border;\n  }\n\n  body {\n    @apply bg-background text-foreground;\n    font-feature-settings: \"rlig\" 1, \"calt\" 1;\n  }\n\n  [data-href] {\n    @apply cursor-pointer;\n  }\n\n  .link {\n    @apply underline hover:opacity-75;\n  }\n}\n\n@layer components {\n  /*\n    Label\n  */\n\n  .label {\n    @apply text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70;\n  }\n\n  /*\n    Select\n  */\n\n  .select {\n    @apply form-select w-48 border border-input bg-white dark:bg-black text-foreground rounded-md h-10 px-3 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50;\n  }\n\n  /*\n    Badge\n  */\n\n  .badge {\n    @apply border inline-flex items-center gap-x-1.5 rounded-md px-1.5 py-0.5 text-sm/5 font-medium sm:text-xs/5 forced-colors:outline;\n  }\n\n  .badge-primary {\n    @apply border-transparent bg-primary text-primary-foreground hover:bg-primary/80;\n  }\n\n  .badge-secondary {\n    @apply border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80;\n  }\n\n  .badge-destructive {\n    @apply border-transparent bg-destructive/15 text-destructive dark:bg-destructive/10 dark:text-destructive-foreground;\n  }\n\n  .badge-outline {\n    @apply text-foreground;\n  }\n\n  .badge-red {\n    @apply border-transparent bg-red-500/15 text-red-700 dark:bg-red-500/10 dark:text-red-400;\n  }\n\n  .badge-orange {\n    @apply border-transparent bg-orange-500/15 text-orange-700 dark:bg-orange-500/10 dark:text-orange-400;\n  }\n\n  .badge-amber {\n    @apply border-transparent bg-amber-400/20 text-amber-700 dark:bg-amber-400/10 dark:text-amber-400;\n  }\n\n  .badge-yellow {\n    @apply border-transparent bg-yellow-400/20 text-yellow-700 dark:bg-yellow-400/10 dark:text-yellow-300;\n  }\n\n  .badge-lime {\n    @apply border-transparent bg-lime-400/20 text-lime-700 dark:bg-lime-400/10 dark:text-lime-300;\n  }\n\n  .badge-green {\n    @apply border-transparent bg-green-500/15 text-green-700 dark:bg-green-500/10 dark:text-green-400;\n  }\n\n  .badge-emerald {\n    @apply border-transparent bg-emerald-500/15 text-emerald-700 dark:bg-emerald-500/10 dark:text-emerald-400;\n  }\n\n  .badge-teal {\n    @apply border-transparent bg-teal-500/15 text-teal-700 dark:bg-teal-500/10 dark:text-teal-300;\n  }\n\n  .badge-cyan {\n    @apply border-transparent bg-cyan-400/20 text-cyan-700 dark:bg-cyan-400/10 dark:text-cyan-300;\n  }\n\n  .badge-sky {\n    @apply border-transparent bg-sky-500/15 text-sky-700 dark:bg-sky-500/10 dark:text-sky-300;\n  }\n\n  .badge-blue {\n    @apply border-transparent bg-blue-500/15 text-blue-700 dark:text-blue-400;\n  }\n\n  .badge-indigo {\n    @apply border-transparent bg-indigo-500/15 text-indigo-700 dark:text-indigo-400;\n  }\n\n  .badge-violet {\n    @apply border-transparent bg-violet-500/15 text-violet-700 dark:text-violet-400;\n  }\n\n  .badge-purple {\n    @apply border-transparent bg-purple-500/15 text-purple-700 dark:text-purple-400;\n  }\n\n  .badge-fuchsia {\n    @apply border-transparent bg-fuchsia-400/15 text-fuchsia-700 dark:bg-fuchsia-400/10 dark:text-fuchsia-400;\n  }\n\n  .badge-pink {\n    @apply border-transparent bg-pink-400/15 text-pink-700 dark:bg-pink-400/10 dark:text-pink-400;\n  }\n\n  .badge-rose {\n    @apply border-transparent bg-rose-400/15 text-rose-700 dark:bg-rose-400/10 dark:text-rose-400;\n  }\n\n  .badge-zinc {\n    @apply border-transparent bg-zinc-600/7.5 text-zinc-700 dark:bg-white/5 dark:text-zinc-400;\n  }\n\n  /*\n    Circle\n  */\n\n  .circle {\n    @apply size-2 inline-flex items-center justify-center rounded-full;\n  }\n\n  .circle-primary {\n    @apply bg-primary;\n  }\n\n  .circle-secondary {\n    @apply bg-secondary;\n  }\n\n  .circle-destructive {\n    @apply bg-destructive;\n  }\n\n  .circle-outline {\n    @apply border border-current bg-background;\n  }\n\n  .circle-red {\n    @apply bg-red-500;\n  }\n\n  .circle-orange {\n    @apply bg-orange-500;\n  }\n\n  .circle-amber {\n    @apply bg-amber-400;\n  }\n\n  .circle-yellow {\n    @apply bg-yellow-400;\n  }\n\n  .circle-lime {\n    @apply bg-lime-400;\n  }\n\n  .circle-green {\n    @apply bg-green-500;\n  }\n\n  .circle-emerald {\n    @apply bg-emerald-500;\n  }\n\n  .circle-teal {\n    @apply bg-teal-500;\n  }\n\n  .circle-cyan {\n    @apply bg-cyan-400;\n  }\n\n  .circle-sky {\n    @apply bg-sky-500;\n  }\n\n  .circle-blue {\n    @apply bg-blue-500;\n  }\n\n  .circle-indigo {\n    @apply bg-indigo-500;\n  }\n\n  .circle-violet {\n    @apply bg-violet-500;\n  }\n\n  .circle-purple {\n    @apply bg-purple-500;\n  }\n\n  .circle-fuchsia {\n    @apply bg-fuchsia-400;\n  }\n\n  .circle-pink {\n    @apply bg-pink-400;\n  }\n\n  .circle-rose {\n    @apply bg-rose-400;\n  }\n\n  .circle-zinc {\n    @apply bg-zinc-400;\n  }\n\n  /*\n    Alert\n  */\n\n  .alert {\n    @apply relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground;\n  }\n\n  .alert-default {\n    @apply bg-background text-foreground;\n  }\n\n  .alert-destructive {\n    @apply border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive;\n  }\n\n  .alert-red {\n    @apply border-red-500/50 text-red-700 dark:border-red-500 dark:text-red-300 [&>svg]:text-red-500;\n  }\n\n  .alert-green {\n    @apply border-green-500/50 text-green-700 dark:border-green-500 dark:text-green-300 [&>svg]:text-green-500;\n  }\n\n  .alert-yellow {\n    @apply border-yellow-500/50 text-yellow-700 dark:border-yellow-500 dark:text-yellow-300 [&>svg]:text-yellow-500;\n  }\n\n  .alert-blue {\n    @apply border-blue-500/50 text-blue-700 dark:border-blue-500 dark:text-blue-300 [&>svg]:text-blue-500;\n  }\n\n  .alert-purple {\n    @apply border-purple-500/50 text-purple-700 dark:border-purple-500 dark:text-purple-300 [&>svg]:text-purple-500;\n  }\n\n  .alert-pink {\n    @apply border-pink-500/50 text-pink-700 dark:border-pink-500 dark:text-pink-300 [&>svg]:text-pink-500;\n  }\n\n  .alert-title {\n    @apply mb-1 font-medium leading-none tracking-tight;\n  }\n\n  .alert-description {\n    @apply text-sm [&_p]:leading-relaxed;\n  }\n\n  /*\n    Button\n  */\n\n  .btn {\n    @apply inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50;\n  }\n\n  .btn-default {\n    @apply bg-primary text-primary-foreground hover:bg-primary/90;\n  }\n\n  .btn-destructive {\n    @apply bg-destructive text-destructive-foreground hover:bg-destructive/90;\n  }\n\n  .btn-outline {\n    @apply border border-input bg-background hover:bg-accent hover:text-accent-foreground;\n  }\n\n  .btn-secondary {\n    @apply bg-secondary text-secondary-foreground hover:bg-secondary/80;\n  }\n\n  .btn-ghost {\n    @apply hover:bg-accent hover:text-accent-foreground;\n  }\n\n  .btn-link {\n    @apply text-primary underline-offset-4 hover:underline;\n  }\n\n  .btn-xs {\n    @apply h-7 rounded-md px-2 gap-1;\n  }\n\n  .btn-sm {\n    @apply h-9 rounded-md px-3 gap-1.5;\n  }\n\n  .btn-md {\n    @apply h-10 px-4 py-2 gap-1.5;\n  }\n\n  .btn-lg {\n    @apply h-11 rounded-md px-8 gap-2;\n  }\n\n  .btn-icon {\n    @apply h-10 w-10;\n  }\n\n  /*\n    Info Line\n  */\n\n  .info-line {\n    @apply flex items-center gap-4;\n  }\n\n  .info-line-label {\n    @apply text-zinc-500 whitespace-nowrap;\n  }\n\n  .info-line-separator {\n    @apply h-px flex-1 bg-zinc-950/10 dark:border-white/10 translate-y-px;\n  }\n\n  .info-line-value {\n    @apply font-medium text-right text-zinc-950 dark:text-white;\n  }\n\n  /*\n    Card\n  */\n\n  .card {\n    @apply rounded-lg border bg-card text-card-foreground shadow-sm;\n  }\n\n  .card-header {\n    @apply flex flex-col space-y-1.5 p-6;\n  }\n\n  .card-title {\n    @apply text-2xl font-semibold leading-none tracking-tight;\n  }\n\n  .card-description {\n    @apply text-sm text-muted-foreground;\n  }\n\n  .card-content {\n    @apply p-6 pt-0;\n  }\n\n  .card-footer {\n    @apply flex items-center p-6 pt-0;\n  }\n\n  /*\n    Navbar\n  */\n\n  .navbar {\n    @apply flex items-center gap-4 bg-background py-4;\n  }\n\n  .navbar-section {\n    @apply flex gap-1.5;\n  }\n\n  .navbar-item {\n    @apply inline-flex items-center rounded-md justify-center px-3 py-2 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2;\n  }\n\n  .navbar-item-default {\n    @apply text-foreground hover:bg-accent hover:text-accent-foreground;\n  }\n\n  .navbar-item-current {\n    @apply bg-primary text-primary-foreground;\n  }\n\n  /*\n    Table\n  */\n\n  .table-wrapper {\n    @apply relative w-full overflow-auto;\n  }\n\n  .table {\n    @apply w-full caption-bottom text-sm;\n  }\n\n  .table-header {\n    @apply [&_tr]:border-b;\n  }\n\n  .table-body {\n    @apply [&_tr:last-child]:border-0;\n  }\n\n  .table-footer {\n    @apply border-t bg-muted/50 font-medium [&>tr]:last:border-b-0;\n  }\n\n  .table-row {\n    @apply border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted;\n  }\n\n  .table-head {\n    @apply h-12 px-4 text-left align-middle font-medium text-muted-foreground whitespace-nowrap [&:has([role=checkbox])]:pr-0;\n  }\n\n  .table-cell {\n    @apply p-4 align-middle [&:has([role=checkbox])]:pr-0;\n  }\n\n  .table-caption {\n    @apply mt-4 text-sm text-muted-foreground;\n  }\n\n  /*\n    Pagination\n  */\n\n  .pagination {\n    @apply flex justify-center;\n  }\n\n  .pagination-content {\n    @apply flex flex-row items-center gap-1;\n  }\n\n  .pagination-item {\n    @apply inline-block;\n  }\n\n  .pagination-link {\n    @apply inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50;\n  }\n\n  .pagination-link-active {\n    @apply border border-input bg-background hover:bg-accent hover:text-accent-foreground;\n  }\n\n  .pagination-link-inactive {\n    @apply hover:bg-accent hover:text-accent-foreground;\n  }\n\n  .pagination-link-icon {\n    @apply h-9 w-9;\n  }\n\n  .pagination-link-default {\n    @apply h-10 px-4 py-2;\n  }\n\n  .pagination-previous,\n  .pagination-next {\n    @apply h-10 px-4 py-2 gap-1;\n  }\n\n  .pagination-previous {\n    @apply pl-2.5;\n  }\n\n  .pagination-next {\n    @apply pr-2.5;\n  }\n\n  .pagination-ellipsis {\n    @apply flex h-9 w-9 items-center justify-center;\n  }\n}\n"
  },
  {
    "path": "app/controllers/solid_queue_dashboard/appearance_controller.rb",
    "content": "module SolidQueueDashboard\n  class AppearanceController < ApplicationController\n    def toggle\n      cookies[:dark_mode] = cookies[:dark_mode] == \"true\" ? \"false\" : \"true\"\n      redirect_to request.referer\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/solid_queue_dashboard/application_controller.rb",
    "content": "module SolidQueueDashboard\n  class ApplicationController < ActionController::Base\n    include SolidQueueDashboard::PaginationHelper\n\n    layout \"solid_queue_dashboard/application\"\n  end\nend\n"
  },
  {
    "path": "app/controllers/solid_queue_dashboard/dashboard_controller.rb",
    "content": "module SolidQueueDashboard\n  class DashboardController < ApplicationController\n    def index\n      @jobs = SolidQueueDashboard.decorate(SolidQueue::Job.all)\n      load_charts\n    end\n\n    private\n\n    def load_charts\n      case params[:chart_period] || \"30m\"\n      when \"15m\"\n        n = 1\n        last = 15\n      when \"30m\"\n        n = 1\n        last = 30\n      when \"1h\"\n        n = 2\n        last = 30\n      when \"3h\"\n        n = 6\n        last = 30\n      when \"6h\"\n        n = 12\n        last = 30\n      when \"12h\"\n        n = 20\n        last = 36\n      when \"1d\"\n        n = 30\n        last = 48\n      when \"3d\"\n        n = 90 # 1.5 hours\n        last = 48\n      when \"1w\"\n        n = 180 # 3 hours\n        last = 56\n      else\n        n = 1\n        last = 30\n      end\n\n      @charts = [\n        {\n          name: \"Enqueued\",\n          data: SolidQueue::Job.group_by_minute(:created_at, last: last, n: n).count,\n          color: \"#A1A1AB\"\n        },\n        {\n          name: \"Finished\",\n          data: @jobs.finished.group_by_minute(:finished_at, last: last, n: n).count,\n          color: \"#23C55E\"\n        },\n        {\n          name: \"Retried\",\n          data: @jobs.retried.group_by_minute(:finished_at, last: last, n: n).count,\n          color: \"#FBBF26\"\n        },\n        {\n          name: \"Failed\",\n          data: SolidQueue::FailedExecution.group_by_minute(:created_at, last: last, n: n).count,\n          color: \"#F04444\"\n        }\n      ]\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/solid_queue_dashboard/jobs_controller.rb",
    "content": "module SolidQueueDashboard\n  class JobsController < ApplicationController\n    before_action :set_jobs, only: [ :index ]\n    before_action :set_job, only: [ :show, :retry ]\n\n    def index\n      @job_queue_names = SolidQueueDashboard.job_queue_names\n      @job_class_names = SolidQueueDashboard.job_class_names\n    end\n\n    def show\n      @job_history = SolidQueueDashboard.decorate(\n        SolidQueue::Job\n          .where.not(id: @job.id)\n          .where(class_name: @job.class_name)\n          .order(id: :desc)\n          .limit(10)\n      )\n    end\n\n    def retry\n      @job.retry\n      redirect_to @job, notice: \"Job has been scheduled for retry\"\n    end\n\n    private\n\n    def set_jobs\n      jobs = SolidQueue::Job.order(id: :desc)\n      jobs = SolidQueueDashboard.decorate(jobs).with_status(params[:status]) if params[:status].present?\n      jobs = jobs.where(class_name: params[:class_name]) if params[:class_name].present?\n      jobs = jobs.where(queue_name: params[:queue_name]) if params[:queue_name].present?\n\n      @pagination = paginate(jobs, page: params[:page].to_i, per_page: params[:per_page].to_i)\n      @jobs = SolidQueueDashboard.decorate(@pagination[:records])\n    end\n\n    def set_job\n      @job = SolidQueueDashboard.decorate(SolidQueue::Job.find(params[:id]))\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/solid_queue_dashboard/processes_controller.rb",
    "content": "module SolidQueueDashboard\n  class ProcessesController < ApplicationController\n    before_action :set_processes, only: [ :index ]\n    before_action :set_process, only: [ :show ]\n\n    def index\n      @process_kinds = SolidQueue::Process.distinct.pluck(:kind)\n      @process_hostnames = SolidQueue::Process.distinct.pluck(:hostname)\n    end\n\n    def show\n    end\n\n    private\n\n    def set_processes\n      @processes = SolidQueue::Process.all\n      @processes = @processes.where(kind: params[:kind]) if params[:kind].present?\n      @processes = @processes.where(hostname: params[:hostname]) if params[:hostname].present?\n      @processes = @processes.order(id: :desc)\n      @processes = SolidQueueDashboard.decorate(@processes)\n    end\n\n    def set_process\n      @process = SolidQueueDashboard.decorate(SolidQueue::Process.find(params[:id]))\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/solid_queue_dashboard/recurring_tasks_controller.rb",
    "content": "module SolidQueueDashboard\n  class RecurringTasksController < ApplicationController\n    before_action :set_recurring_tasks, only: [ :index ]\n    before_action :set_recurring_task, only: [ :show, :enqueue ]\n\n    def index\n    end\n\n    def show\n    end\n\n    def enqueue\n      @recurring_task.enqueue(at: Time.current)\n      redirect_to recurring_tasks_path, notice: \"Recurring task enqueued\"\n    end\n\n    private\n\n    def set_recurring_tasks\n      @recurring_tasks = SolidQueueDashboard.decorate(SolidQueue::RecurringTask.all)\n      @recurring_tasks = @recurring_tasks.with_type(params[:type]) if params[:type].present?\n      @recurring_tasks = @recurring_tasks.order(id: :desc)\n      @recurring_tasks = SolidQueueDashboard.decorate(@recurring_tasks)\n    end\n\n    def set_recurring_task\n      @recurring_task = SolidQueueDashboard.decorate(SolidQueue::RecurringTask.find(params[:id]))\n    end\n  end\nend\n"
  },
  {
    "path": "app/controllers/solid_queue_dashboard/stats_controller.rb",
    "content": "module SolidQueueDashboard\n  class StatsController < ApplicationController\n    def index\n      @jobs = SolidQueueDashboard.decorate(SolidQueue::Job.all)\n      @job_class_names = SolidQueueDashboard.job_class_names\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/solid_queue_dashboard/appearance_helper.rb",
    "content": "module SolidQueueDashboard\n  module AppearanceHelper\n    def dark_mode?\n      cookies[:dark_mode] == \"true\"\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/solid_queue_dashboard/application_helper.rb",
    "content": "module SolidQueueDashboard\n  module ApplicationHelper\n    def empty_value\n      tag.span(\"—\", class: \"text-muted-foreground/30\")\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/solid_queue_dashboard/icons_helper.rb",
    "content": "module SolidQueueDashboard\n  module IconsHelper\n    def icon_refresh_cw(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.path(d: \"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8\")\n        concat tag.path(d: \"M21 3v5h-5\")\n        concat tag.path(d: \"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16\")\n        concat tag.path(d: \"M8 16H3v5\")\n      end\n    end\n\n    def icon_triangle_alert(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.path(d: \"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\")\n        concat tag.path(d: \"M12 9v4\")\n        concat tag.path(d: \"M12 17h.01\")\n      end\n    end\n\n    def icon_server(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.rect(width: \"20\", height: \"8\", x: \"2\", y: \"2\", rx: \"2\", ry: \"2\")\n        concat tag.rect(width: \"20\", height: \"8\", x: \"2\", y: \"14\", rx: \"2\", ry: \"2\")\n        concat tag.line(x1: \"6\", x2: \"6.01\", y1: \"6\", y2: \"6\")\n        concat tag.line(x1: \"6\", x2: \"6.01\", y1: \"18\", y2: \"18\")\n      end\n    end\n\n    def icon_layout_dashboard(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.rect(width: \"7\", height: \"9\", x: \"3\", y: \"3\", rx: \"1\")\n        concat tag.rect(width: \"7\", height: \"5\", x: \"14\", y: \"3\", rx: \"1\")\n        concat tag.rect(width: \"7\", height: \"9\", x: \"14\", y: \"12\", rx: \"1\")\n        concat tag.rect(width: \"7\", height: \"5\", x: \"3\", y: \"16\", rx: \"1\")\n      end\n    end\n\n    def icon_logs(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.path(d: \"M13 12h8\")\n        concat tag.path(d: \"M13 18h8\")\n        concat tag.path(d: \"M13 6h8\")\n        concat tag.path(d: \"M3 12h1\")\n        concat tag.path(d: \"M3 18h1\")\n        concat tag.path(d: \"M3 6h1\")\n        concat tag.path(d: \"M8 12h1\")\n        concat tag.path(d: \"M8 18h1\")\n        concat tag.path(d: \"M8 6h1\")\n      end\n    end\n\n    def icon_clock(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.circle(cx: \"12\", cy: \"12\", r: \"10\")\n        concat tag.polyline(points: \"12 6 12 12 16 14\")\n      end\n    end\n\n    def icon_github(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.path(d: \"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4\")\n        concat tag.path(d: \"M9 18c-4.51 2-5-2-7-2\")\n      end\n    end\n\n    def icon_x(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.path(d: \"M18 6 6 18\")\n        concat tag.path(d: \"m6 6 12 12\")\n      end\n    end\n\n    def icon_moon(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.path(d: \"M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z\")\n      end\n    end\n\n    def icon_sun(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.circle(cx: \"12\", cy: \"12\", r: \"4\")\n        concat tag.path(d: \"M12 2v2\")\n        concat tag.path(d: \"M12 20v2\")\n        concat tag.path(d: \"m4.93 4.93 1.41 1.41\")\n        concat tag.path(d: \"m17.66 17.66 1.41 1.41\")\n        concat tag.path(d: \"M2 12h2\")\n        concat tag.path(d: \"M20 12h2\")\n        concat tag.path(d: \"m6.34 17.66-1.41 1.41\")\n        concat tag.path(d: \"m19.07 4.93-1.41 1.41\")\n      end\n    end\n\n    def icon_play(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.polygon(points: \"6 3 20 12 6 21 6 3\")\n      end\n    end\n\n    def icon_chart_scatter(options = {})\n      svg_options = {\n        xmlns: \"http://www.w3.org/2000/svg\",\n        width: \"24\",\n        height: \"24\",\n        viewBox: \"0 0 24 24\",\n        fill: \"none\",\n        stroke: \"currentColor\",\n        \"stroke-width\": \"2\",\n        \"stroke-linecap\": \"round\",\n        \"stroke-linejoin\": \"round\"\n      }.merge(options)\n\n      tag.svg(**svg_options) do\n        concat tag.circle(cx: \"7.5\", cy: \"7.5\", r: \".5\", fill: \"currentColor\")\n        concat tag.circle(cx: \"18.5\", cy: \"5.5\", r: \".5\", fill: \"currentColor\")\n        concat tag.circle(cx: \"11.5\", cy: \"11.5\", r: \".5\", fill: \"currentColor\")\n        concat tag.circle(cx: \"7.5\", cy: \"16.5\", r: \".5\", fill: \"currentColor\")\n        concat tag.circle(cx: \"17.5\", cy: \"14.5\", r: \".5\", fill: \"currentColor\")\n        concat tag.path(d: \"M3 3v16a2 2 0 0 0 2 2h16\")\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/solid_queue_dashboard/jobs_helper.rb",
    "content": "module SolidQueueDashboard\n  module JobsHelper\n    def job_status_circle(status, options = {})\n      options[:class] = [ \"circle\", job_status_circle_class(status), options[:class] ].compact_blank.join(\" \")\n      tag.span(\"\", **options)\n    end\n\n    def job_status_circle_class(status)\n      {\n        \"green\": \"circle-green\",\n        \"amber\": \"circle-amber\",\n        \"red\": \"circle-red\",\n        \"blue\": \"circle-blue\",\n        \"sky\": \"circle-sky\",\n        \"zinc\": \"circle-zinc\",\n        \"indigo\": \"circle-indigo\",\n        \"purple\": \"circle-purple\"\n      }[Job::STATUS_COLORS[status]&.to_sym || :zinc]\n    end\n\n    def job_status_badge(status, options = {})\n      options[:class] = [ \"badge\", job_status_badge_class(status), options[:class] ].compact_blank.join(\" \")\n      tag.span(status.to_s.titleize, **options)\n    end\n\n    def job_status_badge_class(status)\n      {\n        \"green\": \"badge-green\",\n        \"amber\": \"badge-amber\",\n        \"red\": \"badge-red\",\n        \"blue\": \"badge-blue\",\n        \"sky\": \"badge-sky\",\n        \"zinc\": \"badge-zinc\",\n        \"indigo\": \"badge-indigo\",\n        \"purple\": \"badge-purple\"\n      }[Job::STATUS_COLORS[status]&.to_sym || :zinc]\n    end\n\n    def format_failure_rate(failure_rate, options = {})\n      badge_variant = case failure_rate\n      when 0..1\n        \"badge-emerald\"\n      when 1..5\n        \"badge-amber\"\n      else\n        \"badge-red\"\n      end\n\n      options[:class] = [ \"badge\", badge_variant, options[:class] ].compact_blank.join(\" \")\n      tag.span(number_to_percentage(failure_rate, precision: 2, strip_insignificant_zeros: true), **options)\n    end\n\n    def any_jobs_filters?\n      params[:class_name].present? || params[:status].present? || params[:queue_name].present?\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/solid_queue_dashboard/pagination_helper.rb",
    "content": "module SolidQueueDashboard\n  module PaginationHelper\n    def paginate(scope, page:, per_page:)\n      page = [ page.to_i, 1 ].max\n      per_page = per_page.zero? ? 25 : [ per_page.to_i, 1 ].max\n\n      offset = (page - 1) * per_page\n\n      records = scope.offset(offset).limit(per_page)\n      total_count = scope.count\n      total_pages = (total_count.to_f / per_page).ceil\n\n      {\n        records: records,\n        current_page: page,\n        per_page: per_page,\n        total_pages: total_pages,\n        total_count: total_count\n      }\n    end\n\n    def page_range(current_page, total_pages, window: 2)\n      if total_pages <= 7\n        (1..total_pages).to_a\n      else\n        [\n          1,\n          (current_page - window..current_page + window).to_a,\n          total_pages\n        ].flatten.uniq.sort.reject { |p| p < 1 || p > total_pages }.tap do |range|\n          range.each_cons(2) do |a, b|\n            range.insert(range.index(b), :gap) if b - a > 1\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/solid_queue_dashboard/processes_helper.rb",
    "content": "module SolidQueueDashboard\n  module ProcessesHelper\n    def process_kind_circle(kind, options = {})\n      options[:class] = [ \"circle\", process_kind_circle_class(kind), options[:class] ].compact_blank.join(\" \")\n      tag.span(\"\", **options)\n    end\n\n    def process_kind_circle_class(kind)\n      {\n        \"blue\": \"circle-blue\",\n        \"green\": \"circle-green\",\n        \"yellow\": \"circle-yellow\",\n        \"purple\": \"circle-purple\",\n        \"sky\": \"circle-sky\"\n      }[Process::KIND_COLORS[kind]&.to_sym || :zinc]\n    end\n\n    def process_kind_badge(kind, options = {})\n      options[:class] = [ \"badge\", process_kind_badge_class(kind), options[:class] ].compact_blank.join(\" \")\n      tag.span(kind.to_s.titleize, **options)\n    end\n\n    def process_kind_badge_class(kind)\n      {\n        \"blue\": \"badge-blue\",\n        \"green\": \"badge-green\",\n        \"yellow\": \"badge-yellow\",\n        \"purple\": \"badge-purple\",\n        \"sky\": \"badge-sky\"\n      }[Process::KIND_COLORS[kind]&.to_sym || :zinc]\n    end\n\n    def any_processes_filters?\n      params[:kind].present? || params[:hostname].present?\n    end\n  end\nend\n"
  },
  {
    "path": "app/helpers/solid_queue_dashboard/recurring_tasks_helper.rb",
    "content": "module SolidQueueDashboard\n  module RecurringTasksHelper\n    def recurring_task_circle(type, options = {})\n      options[:class] = [ \"circle\", recurring_task_circle_class(type), options[:class] ].compact_blank.join(\" \")\n      tag.span(\"\", **options)\n    end\n\n    def recurring_task_circle_class(type)\n      {\n        \"amber\": \"circle-amber\",\n        \"sky\": \"circle-sky\",\n        \"zinc\": \"circle-zinc\"\n      }[RecurringTask::TYPE_COLORS[type]&.to_sym || :zinc]\n    end\n\n    def recurring_task_type_badge(type, options = {})\n      options[:class] = [ \"badge\", recurring_task_type_badge_class(type), options[:class] ].compact_blank.join(\" \")\n      tag.span(type.to_s.titleize, **options)\n    end\n\n    def recurring_task_type_badge_class(type)\n      {\n        \"amber\": \"badge-amber\",\n        \"sky\": \"badge-sky\",\n        \"zinc\": \"badge-zinc\"\n      }[RecurringTask::TYPE_COLORS[type]&.to_sym || :zinc]\n    end\n\n    def any_recurring_tasks_filters?\n      params[:class_name].present? || params[:queue_name].present?\n    end\n  end\nend\n"
  },
  {
    "path": "app/views/layouts/solid_queue_dashboard/application.html.erb",
    "content": "<!DOCTYPE html>\n<html class=\"<%= dark_mode? ? \"dark\" : \"\" %>\" lang=\"en\">\n<head>\n  <title>Solid Queue Dashboard</title>\n\n  <%= csrf_meta_tags %>\n  <%= csp_meta_tag %>\n\n  <%= stylesheet_link_tag \"solid_queue_dashboard/application\", media: \"all\" %>\n  <%= javascript_include_tag \"solid_queue_dashboard/application\" %>\n  <%= javascript_include_tag \"chartkick\" %>\n  <%= javascript_include_tag \"Chart.bundle\" %>\n  <%= javascript_include_tag \"solid_queue_dashboard/alpine\", defer: true %>\n</head>\n<body class=\"pb-[15vh] sm:pb-[25vh]\">\n  <div class=\"max-w-[1920px] mx-auto px-4 sm:px-6 lg:px-8\">\n    <%= render \"navbar\" %>\n    <%= render \"flash_messages\" %>\n    <%= yield %>\n    <%= render \"footer\" %>\n  </div>\n</body>\n</html>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/application/_flash_messages.html.erb",
    "content": "<% if flash.any? %>\n  <div class=\"space-y-4 mb-8\">\n    <% flash.each do |type, message| %>\n      <% alert_class = case type\n                       when \"notice\" then \"alert alert-blue\"\n                       when \"success\" then \"alert alert-green\"\n                       when \"error\" then \"alert alert-red\"\n                       when \"alert\" then \"alert alert-yellow\"\n                       else \"alert alert-default\"\n                       end %>\n\n      <div class=\"<%= alert_class %>\" role=\"alert\">\n        <% if type == \"notice\" %>\n          <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n            <path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\" />\n          </svg>\n        <% elsif type == \"success\" %>\n          <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n            <path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\" />\n          </svg>\n        <% elsif type == \"error\" %>\n          <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n            <path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />\n          </svg>\n        <% elsif type == \"alert\" %>\n          <svg xmlns=\"http://www.w3.org/2000/svg\" class=\"h-5 w-5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n            <path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\" />\n          </svg>\n        <% end %>\n\n        <h3 class=\"alert-title\"><%= type.capitalize %></h3>\n        <div class=\"alert-description\">\n          <%= message %>\n        </div>\n      </div>\n    <% end %>\n  </div>\n<% end %>"
  },
  {
    "path": "app/views/solid_queue_dashboard/application/_footer.html.erb",
    "content": "<footer class=\"mt-6\">\n  <p class=\"text-xs text-center text-muted-foreground\">\n    <a\n      href=\"https://github.com/akodkod/solid_queue_dashboard\"\n      target=\"_blank\"\n      class=\"hover:underline hover:text-foreground\"\n    >\n      <%= icon_github class: \"inline-block size-3 mr-0.5 -translate-y-px\" %>GitHub\n    </a>\n  </p>\n</footer>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/application/_navbar.html.erb",
    "content": "<nav class=\"navbar mb-6\">\n  <%= link_to root_path, class: \"inline-flex items-center gap-0.5 text-xl font-bold tracking-tight translate-y-px pl-1\" do %>\n    <span class=\"circle circle-blue\"></span>\n    <span class=\"circle circle-green\"></span>\n    <span class=\"circle circle-yellow\"></span>\n    <span class=\"circle circle-red\"></span>\n    <span class=\"ml-1.5 -translate-y-px\">Solid Queue</span>\n  <% end %>\n\n  <div class=\"navbar-section\">\n    <%= link_to root_path, class: \"navbar-item #{current_page?(controller: 'dashboard', action: 'index') ? 'navbar-item-current' : 'navbar-item-default'}\" do %>\n      <%= icon_layout_dashboard class: \"size-4 mr-1.5\" %>\n      Dashboard\n    <% end %>\n\n    <%= link_to jobs_path, class: \"navbar-item #{current_page?(jobs_path) ? 'navbar-item-current' : 'navbar-item-default'}\" do %>\n      <%= icon_logs class: \"size-4 mr-1.5\" %>\n      Jobs\n    <% end %>\n\n    <%= link_to processes_path, class: \"navbar-item #{current_page?(processes_path) ? 'navbar-item-current' : 'navbar-item-default'}\" do %>\n      <%= icon_server class: \"size-4 mr-1.5\" %>\n      Processes\n\n      <span class=\"badge <%= current_page?(processes_path) ? 'badge-secondary' : 'badge-primary' %> ml-1 text-xs\">\n        <%= SolidQueue::Process.count %>\n      </span>\n    <% end %>\n\n    <%= link_to recurring_tasks_path, class: \"navbar-item #{current_page?(recurring_tasks_path) ? 'navbar-item-current' : 'navbar-item-default'}\" do %>\n      <%= icon_clock class: \"size-4 mr-1.5\" %>\n      Recurring Tasks\n\n      <span class=\"badge <%= current_page?(recurring_tasks_path) ? 'badge-secondary' : 'badge-primary' %> ml-1 text-xs\">\n        <%= SolidQueue::RecurringTask.count %>\n      </span>\n    <% end %>\n\n    <%= link_to stats_path, class: \"navbar-item #{current_page?(stats_path) ? 'navbar-item-current' : 'navbar-item-default'}\" do %>\n      <%= icon_chart_scatter class: \"size-4 mr-1.5\" %>\n      Stats\n    <% end %>\n  </div>\n\n  <div class=\"ml-auto flex gap-4\">\n    <% if current_page?(controller: 'dashboard', action: 'index') %>\n      <%= form_with url: root_path, method: :get, class: \"flex gap-1.5 items-center\" do |form| %>\n        <%= form.hidden_field :chart_period %>\n\n        <%= icon_refresh_cw class: \"size-4 text-muted-foreground\" %>\n        <%= form.select :auto_refresh_period,\n          [[\"Auto-Refresh Off\", \"off\"], [\"15 seconds\", \"15\"], [\"30 seconds\", \"30\"], [\"1 minute\", \"60\"], [\"3 minutes\", \"180\"], [\"5 minutes\", \"300\"], [\"10 minutes\", \"600\"], [\"15 minutes\", \"900\"], [\"30 minutes\", \"1800\"], [\"1 hour\", \"3600\"]],\n          { selected: params[:auto_refresh_period].presence || \"off\" },\n          class: \"select w-40\",\n          data: { auto_submit: true }\n        %>\n      <% end %>\n    <% end %>\n\n    <%= form_with url: toggle_appearance_path, method: :post do |f| %>\n      <button\n        type=\"submit\"\n        class=\"btn btn-icon btn-secondary\"\n      >\n        <% if dark_mode?%>\n          <%= icon_sun class: \"size-4\" %>\n        <% else %>\n          <%= icon_moon class: \"size-4\" %>\n        <% end %>\n      </button>\n    <% end %>\n  </div>\n</nav>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/application/_pagination.html.erb",
    "content": "<% if total_pages > 1 %>\n  <nav class=\"pagination\" role=\"navigation\" aria-label=\"pagination\">\n    <div class=\"pagination-content\">\n      <%= link_to raw('&laquo; Previous'), url_for(page: current_page - 1, per_page: per_page), class: \"pagination-link pagination-previous #{current_page > 1 ? 'pagination-link-active' : 'pagination-link-inactive'}\", rel: \"prev\" unless current_page == 1 %>\n\n      <% page_range(current_page, total_pages).each do |page| %>\n        <% if page.is_a?(Integer) %>\n          <span class=\"pagination-item\">\n            <%= link_to page, url_for(page: page, per_page: per_page), class: \"pagination-link pagination-link-default #{page == current_page ? 'pagination-link-active' : 'pagination-link-inactive'}\" %>\n          </span>\n        <% else %>\n          <span class=\"pagination-ellipsis\">&hellip;</span>\n        <% end %>\n      <% end %>\n\n      <%= link_to raw('Next &raquo;'), url_for(page: current_page + 1, per_page: per_page), class: \"pagination-link pagination-next #{current_page < total_pages ? 'pagination-link-active' : 'pagination-link-inactive'}\", rel: \"next\" unless current_page == total_pages %>\n    </div>\n  </nav>\n<% end %>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/dashboard/index.html.erb",
    "content": "<div class=\"card card-content p-6 relative\">\n  <%= form_with url: root_path, method: :get, class: \"absolute top-6 right-6\" do |form| %>\n    <%= form.hidden_field :auto_refresh_period %>\n    <%= form.select :chart_period,\n      [[\"15 minutes\", \"15m\"], [\"30 minutes\", \"30m\"], [\"1 hour\", \"1h\"], [\"3 hours\", \"3h\"], [\"6 hours\", \"6h\"], [\"12 hours\", \"12h\"], [\"1 day\", \"1d\"], [\"3 days\", \"3d\"], [\"1 week\", \"1w\"]],\n      { selected: params[:chart_period].presence || \"30m\" },\n      class: \"select\",\n      data: { auto_submit: true }\n    %>\n  <% end %>\n\n  <%= line_chart @charts, points: false, thousands: \",\" %>\n</div>\n\n<div class=\"grid grid-cols-6 gap-4 mt-4\">\n  <% SolidQueueDashboard::Job::STATUSES.each do |status| %>\n    <div class=\"card\" data-href=\"<%= jobs_path(status:) %>\">\n      <div class=\"card-content pt-5\">\n        <h4 class=\"font-medium\">\n          <%= status.to_s.titleize %>\n          <span class=\"ml-0.5 -translate-y-px circle <%= job_status_circle_class(status) %>\"></span>\n        </h4>\n        <p class=\"text-4xl font-bold mt-1 text-black dark:text-white\">\n          <%= number_with_delimiter(@jobs.with_status(status).count) %>\n        </p>\n      </div>\n    </div>\n  <% end %>\n</div>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/jobs/_filters.html.erb",
    "content": "<%= form_with url: jobs_path, method: :get, class: \"space-y-3\" do |form| %>\n  <div>\n    <label class=\"label\">Status</label>\n    <div class=\"flex flex-wrap gap-1 mt-1\">\n      <% SolidQueueDashboard::Job::STATUSES.each do |status| %>\n        <%= button_tag type: :submit,\n          name: :status,\n          value: status,\n          class: \"px-2 badge #{params[:status] == status.to_s ? 'badge-primary' : 'badge-outline'}\" do\n        %>\n          <span class=\"circle <%= job_status_circle_class(status) %>\"></span>\n          <%= status.to_s.titleize %>\n          <span class=\"opacity-50 -ml-0.5\">\n            <%= SolidQueueDashboard.decorate(SolidQueue::Job.all).with_status(status).count %>\n          </span>\n        <% end %>\n      <% end %>\n\n      <% if params[:status].present? %>\n        <%= button_tag type: :submit, name: :status, value: nil, class: \"badge badge-destructive gap-1\" do %>\n          <%= icon_x class: \"size-3.5 text-red-500\" %>\n          Clear\n        <% end %>\n      <% end %>\n    </div>\n  </div>\n\n  <div>\n    <label class=\"label\">Job Class</label>\n    <div class=\"flex flex-wrap gap-1 mt-1\">\n      <% @job_class_names.each do |class_name| %>\n        <%= button_tag type: :submit,\n          name: :class_name,\n          value: class_name,\n          class: \"px-2 badge #{params[:class_name] == class_name ? 'badge-primary' : 'badge-outline'}\" do\n        %>\n          <%= class_name.to_s.titleize %>\n          <span class=\"opacity-50 -ml-0.5\">\n            <%= SolidQueue::Job.where(class_name:).count %>\n          </span>\n        <% end %>\n      <% end %>\n\n      <% if params[:class_name].present? %>\n        <%= button_tag type: :submit, name: :class_name, value: nil, class: \"badge badge-destructive gap-1\" do %>\n          <%= icon_x class: \"size-3.5 text-red-500\" %>\n          Clear\n        <% end %>\n      <% end %>\n    </div>\n  </div>\n\n  <% if @job_queue_names.size > 1 %>\n    <div>\n      <label class=\"label\">Queue</label>\n      <div class=\"flex flex-wrap gap-1 mt-1\">\n        <% @job_queue_names.each do |queue_name| %>\n          <%= button_tag type: :submit,\n            name: :queue_name,\n            value: queue_name,\n            class: \"px-2 badge #{params[:queue_name] == queue_name ? 'badge-primary' : 'badge-outline'}\" do\n          %>\n            <%= queue_name.to_s.titleize %>\n            <span class=\"opacity-50 -ml-0.5\">\n              <%= SolidQueue::Job.where(queue_name:).count %>\n            </span>\n          <% end %>\n        <% end %>\n\n        <% if params[:queue_name].present? %>\n          <%= button_tag type: :submit, name: :queue_name, value: nil, class: \"badge badge-destructive gap-1\" do %>\n            <%= icon_x class: \"size-3.5 text-red-500\" %>\n            Clear\n          <% end %>\n        <% end %>\n      </div>\n    </div>\n  <% end %>\n\n  <% if any_jobs_filters? %>\n    <hr>\n    <%= link_to jobs_path, class: \"btn btn-outline btn-xs\" do %>\n      <%= icon_x class: \"size-4 text-red-500\" %>\n      Clear All Filters\n    <% end %>\n  <% end %>\n<% end %>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/jobs/_table.html.erb",
    "content": "<% highlight_ids = local_assigns[:highlight_ids] || [] %>\n\n<div class=\"table-wrapper\">\n  <table class=\"table\">\n    <thead class=\"table-header\">\n      <tr class=\"table-row\">\n        <th class=\"table-head pl-6\">ID</th>\n        <th class=\"table-head\">Status</th>\n        <th class=\"table-head\">Class</th>\n        <th class=\"table-head\">Queue</th>\n        <th class=\"table-head\">Scheduled At</th>\n        <th class=\"table-head\"></th>\n      </tr>\n    </thead>\n    <tbody class=\"table-body\">\n      <%= render partial: \"solid_queue_dashboard/jobs/table_row\", collection: jobs, as: :job, locals: { highlight_ids: highlight_ids } %>\n    </tbody>\n  </table>\n</div>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/jobs/_table_row.html.erb",
    "content": "<% highlight = local_assigns[:highlight] || local_assigns[:highlight_ids]&.include?(job.id) %>\n\n<tr class=\"table-row <%= highlight ? \"bg-primary/7.5 hover:bg-primary/10\" : \"\" %>\" data-href=\"<%= job_path(job) %>\">\n  <td class=\"table-cell pl-6 font-medium text-zinc-900 dark:text-zinc-100 whitespace-nowrap\">\n    <span class=\"mr-1 <%= job_status_circle_class(job.status) %>\"></span>\n    <%= job.id %>\n\n    <% if job.arguments[\"executions\"] > 0 %>\n      <span class=\"text-xs text-muted-foreground\">\n        (x<%= job.arguments[\"executions\"] + 1 %>)\n      </span>\n    <% end %>\n  </td>\n\n  <td class=\"table-cell\">\n    <%= job_status_badge(job.status) %>\n    <% if job.running? %>\n      <br />\n      <span class=\"text-xs text-muted-foreground\">\n        <%= time_ago_in_words(job.claimed_execution.created_at, include_seconds: true) %>\n      </span>\n    <% end %>\n  </td>\n\n  <td class=\"table-cell\">\n    <% if job.class_name == SolidQueueDashboard::Job::COMMAND_CLASS_NAME %>\n      <span class=\"font-medium\">\n        <%= truncate(job.arguments[\"arguments\"][0], length: 50) %>\n      </span>\n      <br>\n      <span class=\"text-xs text-muted-foreground\">\n        Recurring Command\n      </span>\n    <% else %>\n      <p class=\"font-medium\"><%= job.class_name %></p>\n\n      <% if job.arguments[\"arguments\"].present? %>\n        <p class=\"inline-flex flex-wrap gap-0.5 items-start mt-0.5\">\n          <% job.arguments[\"arguments\"].each do |argument| %>\n            <span class=\"badge badge-zinc text-xs\"><%= truncate(JSON.pretty_generate(argument), length: 60) %></span>\n          <% end %>\n        </p>\n      <% end %>\n    <% end %>\n  </td>\n\n  <td class=\"table-cell\">\n    <%= job.queue_name.titleize %>\n  </td>\n\n  <td class=\"table-cell\">\n    <%= tag.span job.scheduled_at, data: { date: true }, class: \"font-medium\" %>\n    <br />\n    <span class=\"text-xs text-muted-foreground\">\n      <%= time_ago_in_words(job.scheduled_at, include_seconds: true) %> ago\n    </span>\n  </td>\n\n  <td class=\"table-cell\">\n    <% if job.running? %>\n      <p class=\"text-sm text-muted-foreground\">\n        Running for <strong class=\"font-medium text-foreground\"><%= time_ago_in_words(job.claimed_execution.created_at, include_seconds: true) %></strong>\n        <% if job.claimed_execution.process %>\n          by <strong class=\"font-medium text-foreground\">\n            <%= process_kind_badge(job.claimed_execution.process.kind) %>\n            <%= link_to \"##{job.claimed_execution.process.id}\", process_path(job.claimed_execution.process), class: \"link\" %>\n          </strong>\n        <% end %>\n      </p>\n    <% elsif job.success? || job.retried? %>\n      <p class=\"text-sm text-muted-foreground\">\n        <%= job.retried? ? \"Failed\" : \"Finished\" %> at <strong class=\"font-medium text-foreground\" data-date=\"<%= job.finished_at.to_fs(:database) %>\"><%= job.finished_at %></strong><br />\n        <span class=\"text-xs\"><%= time_ago_in_words(job.scheduled_at, include_seconds: true) %> ago</span>\n      </p>\n    <% elsif job.failed? %>\n      <div class=\"flex items-center justify-between\">\n        <p class=\"text-sm text-balance font-medium\">\n          <%= icon_triangle_alert class: \"inline-block size-4 text-red-600 dark:text-red-500 -translate-y-px mr-0.5\" %>\n          <%= job.error_message %>\n        </p>\n\n        <%= form_with url: retry_job_path(job), method: :post do %>\n          <button\n            type=\"submit\"\n            class=\"btn btn-icon btn-outline\"\n            title=\"Retry\"\n          >\n            <%= icon_refresh_cw class: \"size-4 text-amber-500\" %>\n          </button>\n        <% end %>\n      </div>\n    <% elsif job.pending? %>\n      <p class=\"text-sm text-muted-foreground\">\n        Pending for <strong class=\"font-medium text-foreground\"><%= time_ago_in_words(job.scheduled_at, include_seconds: true) %></strong>\n      </p>\n    <% end %>\n  </td>\n</tr>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/jobs/index.html.erb",
    "content": "<div class=\"card\">\n  <div class=\"card-header border-b\">\n    <h2 class=\"card-title\">Jobs</h2>\n\n    <div class=\"!mt-4\">\n      <%= render \"filters\" %>\n    </div>\n  </div>\n\n  <div class=\"card-content !p-0\">\n    <% if @jobs.any? %>\n      <%= render \"solid_queue_dashboard/jobs/table\", jobs: @jobs %>\n    <% else %>\n      <div class=\"px-6 py-12\">\n        <p class=\"text-muted-foreground text-center\">\n          No jobs found\n        </p>\n\n        <% if any_jobs_filters? %>\n          <div class=\"flex justify-center mt-2\">\n            <%= link_to \"Clear Filters\", jobs_path, class: \"btn btn-outline\" %>\n          </div>\n        <% end %>\n      </div>\n    <% end %>\n  </div>\n\n  <% if @pagination[:total_pages] > 1 %>\n    <div class=\"card-footer pt-6 border-t flex justify-between\">\n      <%= render partial: 'solid_queue_dashboard/application/pagination', locals: {\n        current_page: @pagination[:current_page],\n        total_pages: @pagination[:total_pages],\n        per_page: @pagination[:per_page]\n      } %>\n\n      <div class=\"flex items-center gap-2\">\n        <span class=\"text-muted-foreground text-sm whitespace-nowrap\">\n          Show\n        </span>\n\n        <%= form_with url: jobs_path, method: :get do |f| %>\n          <%= f.hidden_field :page, value: 1 %>\n          <%= f.select :per_page,\n            [10, 25, 50, 100],\n            { selected: @pagination[:per_page] },\n            class: \"select w-24\",\n            data: { auto_submit: true }\n          %>\n        <% end %>\n\n        <span class=\"text-muted-foreground text-sm whitespace-nowrap\">\n          per page\n        </span>\n      </div>\n    </div>\n  <% end %>\n</div>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/jobs/show.html.erb",
    "content": "<div class=\"flex items-center justify-between gap-4\">\n  <h1 class=\"text-4xl flex items-center gap-2\">\n    <%= job_status_circle(@job.status, class: \"size-4\") %>\n\n    <span class=\"tracking-tighter font-bold\">\n      Job #<%= @job.id %>\n    </span>\n\n    <% if @job.arguments[\"executions\"] > 0 %>\n      <span class=\"ml-2 badge badge-zinc\">\n        <%= (@job.arguments[\"executions\"] + 1).ordinalize %> attempt\n      </span>\n    <% end %>\n  </h1>\n\n  <div class=\"flex gap-2\">\n    <% if @job.failed? %>\n      <%= form_with url: retry_job_path(@job) do %>\n        <button class=\"btn btn-outline btn-md\">\n          <%= icon_refresh_cw class: \"size-4 text-amber-600\" %>\n          <span>Retry Job</span>\n        </button>\n      <% end %>\n    <% end %>\n  </div>\n</div>\n\n<div class=\"card mt-6\">\n  <div class=\"card-content pt-6 grid grid-cols-1 sm:grid-cols-2 sm:gap-16 md:gap-20\">\n    <div class=\"space-y-4\">\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Status</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\"><%= job_status_badge(@job.status) %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Queue</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\">\n          <%= link_to @job.queue_name.titleize, jobs_path(queue_name: @job.queue_name), class: \"link\" %>\n        </span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Class</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\">\n          <%= link_to @job.class_name, jobs_path(class_name: @job.class_name), class: \"link\" %>\n        </span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Active Job ID</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\"><%= @job.active_job_id %></span>\n      </div>\n    </div>\n\n    <div class=\"space-y-4\">\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Created At</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\" data-date><%= @job.created_at %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Scheduled At</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\" data-date><%= @job.scheduled_at %></span>\n      </div>\n\n      <% if @job.success? || @job.retried? %>\n        <div class=\"info-line\">\n          <span class=\"info-line-label\">Finished At</span>\n          <span class=\"info-line-separator\"></span>\n          <span class=\"text-sm text-muted-foreground font-normal\">\n            <%= time_ago_in_words(@job.finished_at, include_seconds: true) %> ago\n          </span>\n          <span class=\"info-line-value\" data-date><%= @job.finished_at.to_fs(:database) %></span>\n        </div>\n\n        <div class=\"info-line\">\n          <span class=\"info-line-label\">Time Taken</span>\n          <span class=\"info-line-separator\"></span>\n          <span class=\"info-line-value\"><%= distance_of_time_in_words(@job.scheduled_at, @job.finished_at, include_seconds: true) %></span>\n        </div>\n      <% end %>\n\n      <% if @job.failed? %>\n        <div class=\"info-line\">\n          <span class=\"info-line-label\">Failed At</span>\n          <span class=\"info-line-separator\"></span>\n          <span class=\"info-line-value\" data-date><%= @job.failed_execution.created_at.to_fs(:database) %></span>\n        </div>\n\n        <div class=\"info-line\">\n          <span class=\"info-line-label\">Time Taken</span>\n          <span class=\"info-line-separator\"></span>\n          <span class=\"info-line-value\"><%= distance_of_time_in_words(@job.scheduled_at, @job.failed_execution.created_at, include_seconds: true) %></span>\n        </div>\n      <% end %>\n    </div>\n  </div>\n</div>\n\n<% if @job.arguments[\"arguments\"].present? %>\n  <div x-data=\"{ showAll: false }\" class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-blue-500 dark:border-t-blue-600 flex flex-row justify-between gap-4\">\n      <div class=\"space-y-1.5\">\n        <% if @job.class_name === SolidQueueDashboard::Job::COMMAND_CLASS_NAME %>\n          <h3 class=\"card-title\">Command</h3>\n          <p class=\"card-description\">The command that was executed</p>\n        <% else %>\n          <h3 class=\"card-title\">Arguments</h3>\n          <p class=\"card-description\">The arguments that were passed to this job</p>\n        <% end %>\n      </div>\n\n      <button x-on:click=\"showAll = !showAll\" class=\"btn btn-sm btn-outline\">\n        <span x-show=\"!showAll\">Show All Metadata</span>\n        <span x-show=\"showAll\">Hide All Metadata</span>\n      </button>\n    </div>\n    <div class=\"card-content pt-6\">\n      <% if @job.class_name === SolidQueueDashboard::Job::COMMAND_CLASS_NAME %>\n        <pre x-show=\"!showAll\"><%= @job.arguments[\"arguments\"][0] %></pre>\n      <% else %>\n        <div x-show=\"!showAll\">\n          <% @job.arguments[\"arguments\"].each do |argument| %>\n            <span class=\"badge badge-zinc text-sm\"><%= JSON.pretty_generate(argument) %></span>\n          <% end %>\n        </div>\n      <% end %>\n\n      <pre x-show=\"showAll\"><%= JSON.pretty_generate(@job.arguments) %></pre>\n    </div>\n  </div>\n<% end %>\n\n<% if @job.failed? %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-content pt-5 border-t-4 border-t-red-500\">\n      <h4 class=\"text-lg font-bold\">\n        <%= @job.error_message %>\n      </h4>\n\n      <% backtrace = Rails.backtrace_cleaner.clean(@job.failed_execution.error[\"backtrace\"]) %>\n      <% if backtrace.any? %>\n        <ul class=\"list-decimal marker:text-sm marker:text-muted-foreground mt-1 ml-8 space-y-1\">\n          <% backtrace.each do |line| %>\n            <li class=\"font-mono\"><%= line %></li>\n          <% end %>\n        </ul>\n      <% end %>\n    </div>\n  </div>\n<% end %>\n\n<% if @job.execution_history.size > 1 %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-zinc-500 dark:border-t-zinc-600\">\n      <h3 class=\"card-title\">Execution History</h3>\n      <p class=\"card-description\">The history of executions of this exact job</p>\n    </div>\n\n    <div class=\"card-content !p-0\">\n      <%= render \"table\", jobs: SolidQueueDashboard.decorate(@job.execution_history.order(id: :desc)), highlight_ids: [@job.id] %>\n    </div>\n  </div>\n<% end %>\n\n<% if @job_history.size > 1 %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-zinc-500 dark:border-t-zinc-600 flex !flex-row justify-between items-center\">\n      <div class=\"space-y-1.5\">\n        <h3 class=\"card-title\">Similar Jobs</h3>\n        <p class=\"card-description\">The history of executions of the same job class</p>\n      </div>\n\n      <%= link_to \"View All\", jobs_path(class_name: @job.class_name), class: \"btn btn-outline btn-sm\" %>\n    </div>\n\n    <div class=\"card-content !p-0\">\n      <%= render \"table\", jobs: @job_history %>\n    </div>\n\n    <div class=\"card-footer border-t pt-6\">\n      <p class=\"text-sm text-muted-foreground\">\n        Showing the last 10 executions of this job\n      </p>\n    </div>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/processes/_filters.html.erb",
    "content": "<%= form_with url: processes_path, method: :get, class: \"space-y-3\" do |form| %>\n  <% if @process_kinds.any? %>\n    <div>\n      <label class=\"label\">Kind</label>\n      <div class=\"flex flex-wrap gap-1 mt-1\">\n        <% @process_kinds.each do |kind| %>\n          <%= button_tag type: :submit,\n            name: :kind,\n            value: kind,\n            class: \"px-2 badge #{params[:kind] == kind.to_s ? 'badge-primary' : 'badge-outline'}\" do\n          %>\n            <%= process_kind_circle(kind) %>\n            <%= kind.to_s.titleize %>\n            <span class=\"opacity-50 -ml-0.5\">\n              <%= SolidQueue::Process.where(kind:).count %>\n            </span>\n          <% end %>\n        <% end %>\n\n        <% if params[:kind].present? %>\n          <%= button_tag type: :submit, name: :kind, value: nil, class: \"badge badge-destructive gap-1\" do %>\n            <%= icon_x class: \"size-3.5 text-red-500\" %>\n            Clear\n          <% end %>\n        <% end %>\n      </div>\n    </div>\n  <% end %>\n\n  <% if @process_hostnames.any? %>\n    <div>\n      <label class=\"label\">Hostname</label>\n      <div class=\"flex flex-wrap gap-1 mt-1\">\n        <% @process_hostnames.each do |hostname| %>\n          <%= button_tag type: :submit,\n            name: :hostname,\n            value: hostname,\n            class: \"px-2 badge #{params[:hostname] == hostname ? 'badge-primary' : 'badge-outline'}\" do\n          %>\n            <%= hostname %>\n            <span class=\"opacity-50 -ml-0.5\">\n              <%= SolidQueue::Process.where(hostname:).count %>\n            </span>\n          <% end %>\n        <% end %>\n\n        <% if params[:hostname].present? %>\n          <%= button_tag type: :submit, name: :hostname, value: nil, class: \"badge badge-destructive gap-1\" do %>\n            <%= icon_x class: \"size-3.5 text-red-500\" %>\n            Clear\n          <% end %>\n        <% end %>\n      </div>\n    </div>\n  <% end %>\n\n  <% if any_processes_filters? %>\n    <hr>\n    <%= link_to processes_path, class: \"btn btn-outline btn-xs\" do %>\n      <%= icon_x class: \"size-4 text-red-500\" %>\n      Clear All Filters\n    <% end %>\n  <% end %>\n<% end %>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/processes/_table.html.erb",
    "content": "<div class=\"table-wrapper\">\n  <table class=\"table\">\n    <thead class=\"table-header\">\n      <tr class=\"table-row\">\n        <th class=\"table-head pl-6\">ID</th>\n        <th class=\"table-head\">Kind</th>\n        <th class=\"table-head\">Hostname</th>\n        <th class=\"table-head\">PID</th>\n        <th class=\"table-head\">Launched At</th>\n        <th class=\"table-head\">Last Heartbeat</th>\n        <th class=\"table-head\"></th>\n      </tr>\n    </thead>\n    <tbody class=\"table-body\">\n      <%= render partial: 'solid_queue_dashboard/processes/table_row', collection: processes, as: :process %>\n    </tbody>\n  </table>\n</div>"
  },
  {
    "path": "app/views/solid_queue_dashboard/processes/_table_row.html.erb",
    "content": "<tr class=\"table-row\" data-href=\"<%= process_path(process) %>\">\n  <td class=\"table-cell pl-6 font-medium text-zinc-900 dark:text-zinc-100\">\n    <%= process.id %>\n  </td>\n\n  <td class=\"table-cell\">\n    <%= process_kind_badge(process.kind) %>\n\n    <% if process.claimed_executions.any? %>\n      <span class=\"ml-0.5 text-xs text-muted-foreground\">\n        Running <%= pluralize(process.claimed_executions.count, \"job\") %>\n      </span>\n    <% end %>\n  </td>\n\n  <td class=\"table-cell\"><%= process.hostname %></td>\n  <td class=\"table-cell\"><%= process.pid %></td>\n\n  <td class=\"table-cell\">\n    <span data-date=\"true\"><%= process.created_at.to_fs(:database) %></span><br />\n    <span class=\"text-xs text-muted-foreground\">\n      <%= time_ago_in_words(process.created_at, include_seconds: true) %> ago\n    </span>\n  </td>\n\n  <td class=\"table-cell\" title=\"<%= process.last_heartbeat_at %>\">\n    <span data-date=\"true\"><%= process.last_heartbeat_at.to_fs(:database) %></span><br />\n    <span class=\"text-xs text-muted-foreground\">\n      <%= time_ago_in_words(process.last_heartbeat_at, include_seconds: true) %> ago\n    </span>\n  </td>\n\n  <td class=\"table-cell\">\n    <% if process.dead? %>\n      <span class=\"badge badge-red\">Dead?</span>\n    <% end %>\n  </td>\n</tr>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/processes/index.html.erb",
    "content": "<div class=\"card\">\n  <div class=\"card-header border-b\">\n    <h2 class=\"card-title\">Processes</h2>\n\n    <div class=\"!mt-4\">\n      <%= render \"filters\" %>\n    </div>\n  </div>\n\n  <div class=\"card-content !p-0\">\n    <% if @processes.any? %>\n      <%= render \"solid_queue_dashboard/processes/table\", processes: @processes %>\n    <% else %>\n      <div class=\"px-6 py-12\">\n        <p class=\"text-muted-foreground text-center\">\n          No processes found\n        </p>\n\n        <% if any_processes_filters? %>\n          <div class=\"flex justify-center mt-2\">\n            <%= link_to \"Clear Filters\", processes_path, class: \"btn btn-outline btn-md\" %>\n          </div>\n        <% end %>\n      </div>\n    <% end %>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/processes/show.html.erb",
    "content": "<h1 class=\"text-4xl flex items-center gap-2\">\n  <%= process_kind_circle(@process.kind, class: \"!size-4\") %>\n\n  <span class=\"tracking-tighter font-bold\">\n    Process #<%= @process.id %>\n  </span>\n\n  <% if @process.dead? %>\n    <span class=\"badge badge-red\">Dead?</span>\n  <% end %>\n</h1>\n\n<div class=\"card mt-6\">\n  <div class=\"card-content pt-6 grid grid-cols-1 sm:grid-cols-2 sm:gap-16\">\n    <div class=\"space-y-4\">\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Kind</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\"><%= process_kind_badge(@process.kind) %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Hostname</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\"><%= @process.hostname %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">PID</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\"><%= @process.pid %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Name</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\"><%= @process.name %></span>\n      </div>\n    </div>\n\n    <div class=\"space-y-4\">\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Last Heartbeat</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"text-sm text-muted-foreground font-normal\">\n          <%= time_ago_in_words(@process.last_heartbeat_at, include_seconds: true) %> ago\n        </span>\n        <span class=\"info-line-value\" data-date><%= @process.last_heartbeat_at.to_fs(:database) %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Created At</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"text-sm text-muted-foreground font-normal\">\n          <%= time_ago_in_words(@process.created_at, include_seconds: true) %> ago\n        </span>\n        <span class=\"info-line-value\" data-date><%= @process.created_at.to_fs(:database) %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Time Running</span>\n        <span class=\"info-line-separator\"></span>\n        <span class=\"info-line-value\"><%= distance_of_time_in_words(@process.created_at, Time.current, include_seconds: true) %></span>\n      </div>\n    </div>\n  </div>\n</div>\n\n<% if @process.claimed_executions.any? %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-sky-500 dark:border-t-sky-600\">\n      <h2 class=\"card-title\">Running Jobs</h2>\n      <p class=\"card-description\">Jobs that this process is currently running</p>\n    </div>\n\n    <div class=\"card-content p-0\">\n      <%= render partial: 'solid_queue_dashboard/jobs/table', locals: { jobs: @process.claimed_executions.map { |execution| SolidQueueDashboard::Decorators::JobDecorator.new(execution.job) } } %>\n    </div>\n  </div>\n<% end %>\n\n<% if @process.metadata.present? %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-amber-500 dark:border-t-amber-600\">\n      <h2 class=\"card-title\">Metadata</h2>\n      <p class=\"card-description\">Additional information about this process</p>\n    </div>\n    <div class=\"card-content pt-6\">\n      <pre><%= JSON.pretty_generate(@process.metadata) %></pre>\n    </div>\n  </div>\n<% end %>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/recurring_tasks/_filters.html.erb",
    "content": "<%= form_with url: recurring_tasks_path, method: :get, class: \"space-y-3\" do |form| %>\n  <div>\n    <div class=\"flex flex-wrap gap-1 mt-1\">\n      <% SolidQueueDashboard::RecurringTask::TYPES.each do |type| %>\n        <%= button_tag type: :submit,\n          name: :type,\n          value: type,\n          class: \"px-2 badge #{params[:type] == type.to_s ? 'badge-primary' : 'badge-outline'}\" do\n        %>\n          <%= recurring_task_circle(type) %>\n          <%= type.to_s.titleize %>\n          <span class=\"opacity-50 -ml-0.5\">\n            <%= SolidQueueDashboard.decorate(SolidQueue::RecurringTask.all).with_type(type).count %>\n          </span>\n        <% end %>\n      <% end %>\n\n      <% if params[:type].present? %>\n        <%= button_tag type: :submit, name: :type, value: nil, class: \"badge badge-destructive gap-1\" do %>\n          <%= icon_x class: \"size-3.5 text-red-500\" %>\n          Clear\n        <% end %>\n      <% end %>\n    </div>\n  </div>\n<% end %>"
  },
  {
    "path": "app/views/solid_queue_dashboard/recurring_tasks/_table.html.erb",
    "content": "<div class=\"table-wrapper\">\n  <table class=\"table\">\n    <thead class=\"table-header\">\n      <tr class=\"table-row\">\n        <th class=\"table-head pl-6\">ID</th>\n        <th class=\"table-head\">Type</th>\n        <th class=\"table-head\"></th>\n        <th class=\"table-head\">Schedule</th>\n        <th class=\"table-head\">Queue Name</th>\n        <th class=\"table-head\">Priority</th>\n        <th class=\"table-head\">Key</th>\n        <th class=\"table-head\"></th>\n      </tr>\n    </thead>\n    <tbody class=\"table-body\">\n      <%= render partial: 'solid_queue_dashboard/recurring_tasks/table_row', collection: recurring_tasks, as: :recurring_task %>\n    </tbody>\n  </table>\n</div>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/recurring_tasks/_table_row.html.erb",
    "content": "<tr class=\"table-row\" data-href=\"<%= recurring_task_path(recurring_task) %>\">\n  <td class=\"table-cell pl-6 font-medium text-zinc-900 dark:text-zinc-100\">\n    <%= recurring_task.id %>\n  </td>\n\n  <td class=\"table-cell\">\n    <%= recurring_task_type_badge(recurring_task.type) %>\n  </td>\n\n  <td class=\"table-cell\">\n    <span class=\"font-medium\">\n      <%= recurring_task.class_name || recurring_task.command %>\n    </span>\n  </td>\n\n  <td class=\"table-cell\"><%= recurring_task.schedule %></td>\n  <td class=\"table-cell\"><%= recurring_task.queue_name&.titleize || empty_value %></td>\n  <td class=\"table-cell\"><%= recurring_task.priority || empty_value %></td>\n  <td class=\"table-cell\"><%= recurring_task.key %></td>\n  <td class=\"table-cell\">\n    <%= form_with url: enqueue_recurring_task_path(recurring_task), method: :post do %>\n      <button\n        type=\"submit\"\n        class=\"btn btn-md btn-outline\"\n      >\n        <%= icon_play class: \"size-4 text-amber-500 mr-1\" %>\n        Enqueue Now\n      </button>\n    <% end %>\n  </td>\n</tr>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/recurring_tasks/index.html.erb",
    "content": "<div class=\"card\">\n  <div class=\"card-header border-b\">\n    <h2 class=\"card-title\">Recurring Tasks</h2>\n\n    <div class=\"!mt-4\">\n      <%= render \"solid_queue_dashboard/recurring_tasks/filters\" %>\n    </div>\n  </div>\n\n  <div class=\"card-content !p-0\">\n    <% if @recurring_tasks.any? %>\n      <%= render \"solid_queue_dashboard/recurring_tasks/table\", recurring_tasks: @recurring_tasks %>\n    <% else %>\n      <div class=\"px-6 py-12\">\n        <p class=\"text-muted-foreground text-center\">\n          No recurring tasks found\n        </p>\n      </div>\n    <% end %>\n  </div>\n</div>"
  },
  {
    "path": "app/views/solid_queue_dashboard/recurring_tasks/show.html.erb",
    "content": "<h1 class=\"text-4xl flex items-center gap-2\">\n  <%= recurring_task_circle(@recurring_task.type, class: \"size-4\") %>\n\n  <span class=\"tracking-tighter font-bold\">\n    Recurring Task #<%= @recurring_task.id %>\n  </span>\n</h1>\n\n<div class=\"card mt-6\">\n  <div class=\"card-content pt-6 grid grid-cols-1 sm:grid-cols-2 sm:gap-16\">\n    <div class=\"space-y-4\">\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Type</span>\n        <div class=\"info-line-separator\"></div>\n        <span class=\"info-line-value\"><%= recurring_task_type_badge(@recurring_task.type) %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Key</span>\n        <div class=\"info-line-separator\"></div>\n        <span class=\"info-line-value\"><%= @recurring_task.key %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Schedule</span>\n        <div class=\"info-line-separator\"></div>\n        <span class=\"info-line-value\"><%= @recurring_task.schedule %></span>\n      </div>\n\n      <% if @recurring_task.queue_name? %>\n        <div class=\"info-line\">\n          <span class=\"info-line-label\">Queue Name</span>\n          <div class=\"info-line-separator\"></div>\n          <span class=\"info-line-value\"><%= @recurring_task.queue_name %></span>\n        </div>\n      <% end %>\n    </div>\n\n    <div class=\"space-y-4\">\n      <% if @recurring_task.priority? %>\n        <div class=\"info-line\">\n          <span class=\"info-line-label\">Priority</span>\n          <div class=\"info-line-separator\"></div>\n          <span class=\"info-line-value\"><%= @recurring_task.priority %></span>\n        </div>\n      <% end %>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Static</span>\n        <div class=\"info-line-separator\"></div>\n        <span class=\"info-line-value\"><%= @recurring_task.static ? \"Yes\" : \"No\" %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Created At</span>\n        <div class=\"info-line-separator\"></div>\n        <span class=\"info-line-value\" data-date><%= @recurring_task.created_at.to_fs(:database) %></span>\n      </div>\n\n      <div class=\"info-line\">\n        <span class=\"info-line-label\">Updated At</span>\n        <div class=\"info-line-separator\"></div>\n        <span class=\"info-line-value\" data-date><%= @recurring_task.updated_at.to_fs(:database) %></span>\n      </div>\n    </div>\n  </div>\n</div>\n\n<% if @recurring_task.command.present? %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-amber-500 dark:border-t-amber-600\">\n      <h3 class=\"card-title\">Command</h3>\n      <p class=\"card-description\">The command to be executed</p>\n    </div>\n    <div class=\"card-content pt-6\">\n      <pre><%= @recurring_task.command %></pre>\n    </div>\n  </div>\n<% end %>\n\n<% if @recurring_task.class_name.present? %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-blue-500 dark:border-t-blue-600\">\n      <h3 class=\"card-title\">Job Class</h3>\n      <p class=\"card-description\">The job class to be executed</p>\n    </div>\n    <div class=\"card-content pt-6\">\n      <pre><%= @recurring_task.class_name %></pre>\n    </div>\n  </div>\n<% end %>\n\n<% if @recurring_task.arguments.present? %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-purple-500 dark:border-t-purple-600\">\n      <h3 class=\"card-title\">Arguments</h3>\n      <p class=\"card-description\">The arguments to be passed to the job</p>\n    </div>\n    <div class=\"card-content pt-6\">\n      <pre><%= JSON.pretty_generate(@recurring_task.arguments) %></pre>\n    </div>\n  </div>\n<% end %>\n\n<% if @recurring_task.description.present? %>\n  <div class=\"card mt-8 overflow-hidden\">\n    <div class=\"card-header border-b border-t-4 border-t-amber-500 dark:border-t-amber-600\">\n      <h3 class=\"card-title\">Description</h3>\n      <p class=\"card-description\">Additional information about this recurring task</p>\n    </div>\n    <div class=\"card-content pt-6\">\n      <pre><%= @recurring_task.description %></pre>\n    </div>\n  </div>\n<% end %>\n\n<div class=\"card mt-8 overflow-hidden\">\n  <div class=\"card-header border-b border-t-4 border-t-zinc-500 dark:border-t-zinc-600\">\n    <h3 class=\"card-title\">Next Runs</h3>\n    <p class=\"card-description\">Based on the current schedule</p>\n  </div>\n  <div class=\"card-content pt-5\">\n    <ul class=\"list-decimal marker:text-sm marker:text-muted-foreground ml-4 space-y-1\">\n      <% @recurring_task.next_runs.each do |run_time| %>\n        <li>\n          <span data-date><%= run_time.strftime(\"%Y-%m-%d %H:%M:%S %Z\") %></span>\n          <span class=\"text-muted-foreground\">\n            in <%= distance_of_time_in_words(Time.current, run_time) %>\n          </span>\n        </li>\n      <% end %>\n    </ul>\n  </div>\n</div>\n"
  },
  {
    "path": "app/views/solid_queue_dashboard/stats/index.html.erb",
    "content": "<div class=\"card mt-4\">\n  <div class=\"card-header border-b\">\n    <h3 class=\"card-title\">Failure Rate</h3>\n  </div>\n  <div class=\"card-content !p-0\">\n    <div class=\"table-wrapper\">\n      <table class=\"table\">\n        <thead class=\"table-header\">\n          <tr class=\"table-row\">\n            <th class=\"table-head\">Job</th>\n            <th class=\"table-head\">Failure Rate</th>\n          </tr>\n        </thead>\n        <tbody class=\"table-body\">\n          <% @job_class_names.each do |class_name| %>\n            <tr class=\"table-row\" data-href=\"<%= jobs_path(class_name:, status: :failed) %>\">\n              <td class=\"table-cell font-medium\"><%= class_name.titleize %></td>\n              <td class=\"table-cell font-medium\"><%= format_failure_rate(SolidQueueDashboard.decorate(SolidQueue::Job.where(class_name:)).failure_rate) %></td>\n            </tr>\n          <% end %>\n        </tbody>\n      </table>\n    </div>\n  </div>\n</div>"
  },
  {
    "path": "bin/console",
    "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nrequire \"bundler/setup\"\nrequire \"solid_queue_dashboard\"\n\n# You can add fixtures and/or initialization code here to make experimenting\n# with your gem easier. You can also use a different console, if you like.\n\nrequire \"irb\"\nIRB.start(__FILE__)\n"
  },
  {
    "path": "bin/dev",
    "content": "#!/usr/bin/env bash\n\nexec foreman start -f Procfile.dev"
  },
  {
    "path": "bin/setup",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\nIFS=$'\\n\\t'\nset -vx\n\nbundle install\n"
  },
  {
    "path": "bin/setup-test-app",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\nIFS=$'\\n\\t'\nset -vx\n\ncd test_app\nbundle install\nbin/rails db:setup\n"
  },
  {
    "path": "config/routes.rb",
    "content": "SolidQueueDashboard::Engine.routes.draw do\n  resources :jobs, only: [ :index, :show ] do\n    member do\n      post :retry\n    end\n  end\n\n  resources :processes, only: [ :index, :show ]\n\n  resources :recurring_tasks, path: \"recurring-tasks\", only: [ :index, :show ] do\n    member do\n      post :enqueue\n    end\n  end\n\n  get \"stats\", to: \"stats#index\", as: :stats\n  post \"appearance/toggle\", to: \"appearance#toggle\", as: :toggle_appearance\n\n  root \"dashboard#index\"\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/configuration.rb",
    "content": "module SolidQueueDashboard\n  class Configuration\n    attr_accessor :title\n\n    def initialize\n      @title = \"Solid Queue Dashboard\"\n    end\n  end\n\n  def self.configuration\n    @configuration ||= Configuration.new\n  end\n\n  def self.configure\n    yield(configuration)\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/decorators/job_decorator.rb",
    "content": "module SolidQueueDashboard\n  module Decorators\n    class JobDecorator < SimpleDelegator\n      def color\n        Job.status_color(status)\n      end\n\n      def status\n        return @status if defined?(@status)\n\n        @status = if running?\n          Job::RUNNING\n        elsif retried?\n          Job::RETRIED\n        elsif failed?\n          Job::FAILED\n        elsif success?\n          Job::SUCCESS\n        elsif scheduled?\n          Job::SCHEDULED\n        else\n          Job::PENDING\n        end\n      end\n\n      def running?\n        return @running if defined?(@running)\n        @running = claimed_execution.present?\n      end\n\n      def success?\n        return @success if defined?(@success)\n        @success = finished_at.present? && !failed? && !retried?\n      end\n\n      def retried?\n        return @retried if defined?(@retried)\n        @retried = finished_at.present? && !failed_execution.present? &&\n          (arguments[\"executions\"].to_i > 0 || execution_history.where(scheduled_at: finished_at..).any?)\n      end\n\n      def failed?\n        return @failed if defined?(@failed)\n        @failed = failed_execution.present?\n      end\n\n      def scheduled?\n        return @scheduled if defined?(@scheduled)\n        @scheduled = scheduled_at.present? && scheduled_at > Time.current\n      end\n\n      def pending?\n        return @pending if defined?(@pending)\n        @pending = !finished_at.present? && !running?\n      end\n\n      def execution_history\n        SolidQueue::Job.where(active_job_id: active_job_id)\n      end\n\n      def error_message\n        return @error_message if defined?(@error_message)\n\n        @error_message = failed_execution ?\n          \"#{failed_execution.error[\"exception_class\"]}: #{failed_execution.error[\"message\"]}\" :\n          nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/decorators/jobs_decorator.rb",
    "content": "module SolidQueueDashboard\n  module Decorators\n    class JobsDecorator < SimpleDelegator\n      def with_status(status)\n        case status.to_sym\n        when Job::RUNNING\n          running\n        when Job::SUCCESS\n          success\n        when Job::FAILED\n          failed\n        when Job::SCHEDULED\n          scheduled\n        when Job::PENDING\n          pending\n        when Job::RETRIED\n          retried\n        else\n          raise \"Invalid status: #{status}\"\n        end\n      end\n\n      def running\n        where.associated(:claimed_execution)\n      end\n\n      def success\n        where.not(finished_at: nil)\n          .where.not(id: failed)\n          .where.not(id: retried)\n      end\n\n      def scheduled\n        where(finished_at: nil, scheduled_at: Time.current..)\n      end\n\n      def pending\n        where(finished_at: nil, scheduled_at: ..Time.current)\n          .where.not(id: failed)\n          .where.not(id: running)\n      end\n\n      def retried\n        where(finished_at: ..Time.current)\n          .where.not(id: failed)\n          .where(\n            active_job_id: SolidQueue::Job\n              .select(:active_job_id)\n              .group(:active_job_id)\n              .having(\"COUNT(*) > 1\")\n          )\n          .where.not(\n            id: SolidQueue::Job\n              .select(\"MAX(id)\")\n              .group(:active_job_id)\n          )\n      end\n\n      def failure_rate\n        success_count = success.count\n        retried_count = retried.count\n        failed_count = failed.count\n\n        total = success_count + retried_count + failed_count\n        return 0 if total.zero?\n\n        (failed_count + retried_count).to_f / total * 100\n      end\n\n      def each\n        super do |job|\n          yield JobDecorator.new(job)\n        end\n      end\n\n      def to_a\n        super.map { |job| JobDecorator.new(job) }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/decorators/process_decorator.rb",
    "content": "module SolidQueueDashboard\n  module Decorators\n    class ProcessDecorator < SimpleDelegator\n      def color\n        Process.kind_color(kind)\n      end\n\n      def dead?\n        last_heartbeat_at < Process::HEARTBEAT_DEAD_THRESHOLD.ago\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/decorators/processes_decorator.rb",
    "content": "module SolidQueueDashboard\n  module Decorators\n    class ProcessesDecorator < SimpleDelegator\n      def each\n        super do |job|\n          yield ProcessDecorator.new(job)\n        end\n      end\n\n      def to_a\n        super.map { |job| ProcessDecorator.new(job) }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/decorators/recurring_task_decorator.rb",
    "content": "module SolidQueueDashboard\n  module Decorators\n    class RecurringTaskDecorator < SimpleDelegator\n      def type\n        if command.present?\n          RecurringTask::COMMAND\n        elsif class_name.present?\n          RecurringTask::JOB\n        else\n          \"Unknown\"\n        end\n      end\n\n      def next_runs(count: 5)\n        cron = Fugit.parse(schedule)\n        return [] unless cron\n\n        cron.next.take(count)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/decorators/recurring_tasks_decorator.rb",
    "content": "module SolidQueueDashboard\n  module Decorators\n    class RecurringTasksDecorator < SimpleDelegator\n      def with_type(type)\n        case type.to_sym\n        when RecurringTask::JOB\n          where.not(class_name: nil)\n        when RecurringTask::COMMAND\n          where.not(command: nil)\n        else\n          raise \"Unknown type: #{type}\"\n        end\n      end\n\n      def each\n        super do |task|\n          yield RecurringTaskDecorator.new(task)\n        end\n      end\n\n      def to_a\n        super.map { |task| RecurringTaskDecorator.new(task) }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/engine.rb",
    "content": "module SolidQueueDashboard\n  class Engine < ::Rails::Engine\n    isolate_namespace SolidQueueDashboard\n\n    initializer \"solid_queue_dashboard.assets.precompile\" do |app|\n      app.config.assets.precompile += %w[\n        solid_queue_dashboard/alpine.js\n        solid_queue_dashboard/application.js\n        solid_queue_dashboard/application.css\n      ]\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/job.rb",
    "content": "module SolidQueueDashboard\n  module Job\n    # Constants\n    RUNNING = :running\n    SUCCESS = :success\n    RETRIED = :retried\n    FAILED = :failed\n    PENDING = :pending\n    SCHEDULED = :scheduled\n\n    STATUSES = [ RUNNING, SUCCESS, RETRIED, FAILED, SCHEDULED, PENDING ]\n\n    STATUS_COLORS = {\n      SUCCESS => \"green\",\n      RETRIED => \"amber\",\n      FAILED => \"red\",\n      SCHEDULED => \"purple\",\n      PENDING => \"zinc\",\n      RUNNING => \"sky\"\n    }\n\n    COMMAND_CLASS_NAME = \"SolidQueue::RecurringJob\"\n\n    def self.status_color(status)\n      STATUS_COLORS[status] || \"zinc\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/process.rb",
    "content": "module SolidQueueDashboard\n  module Process\n    # Constants\n    SUPERVISOR = \"Supervisor\"\n    DISPATCHER = \"Dispatcher\"\n    WORKER = \"Worker\"\n    SCHEDULER = \"Scheduler\"\n\n    KINDS = [ SUPERVISOR, DISPATCHER, WORKER, SCHEDULER ]\n\n    KIND_COLORS = {\n      SUPERVISOR => \"yellow\",\n      DISPATCHER => \"green\",\n      WORKER => \"sky\",\n      SCHEDULER => \"purple\"\n    }\n\n    HEARTBEAT_DEAD_THRESHOLD = 3.minutes\n\n    def self.kind_color(kind)\n      KIND_COLORS[kind] || \"zinc\"\n    end\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/recurring_task.rb",
    "content": "module SolidQueueDashboard\n  module RecurringTask\n    # Constants\n    COMMAND = :command\n    JOB = :job\n\n    TYPES = [ COMMAND, JOB ]\n\n    TYPE_COLORS = {\n      COMMAND => \"amber\",\n      JOB => \"sky\"\n    }\n  end\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard/version.rb",
    "content": "# frozen_string_literal: true\n\nmodule SolidQueueDashboard\n  VERSION = \"0.2.0\"\nend\n"
  },
  {
    "path": "lib/solid_queue_dashboard.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"rails\"\nrequire \"groupdate\"\nrequire \"chartkick\"\nrequire_relative \"solid_queue_dashboard/version\"\nrequire_relative \"solid_queue_dashboard/configuration\"\nrequire_relative \"solid_queue_dashboard/engine\"\nrequire_relative \"solid_queue_dashboard/job\"\nrequire_relative \"solid_queue_dashboard/process\"\nrequire_relative \"solid_queue_dashboard/recurring_task\"\nrequire_relative \"solid_queue_dashboard/decorators/job_decorator\"\nrequire_relative \"solid_queue_dashboard/decorators/jobs_decorator\"\nrequire_relative \"solid_queue_dashboard/decorators/process_decorator\"\nrequire_relative \"solid_queue_dashboard/decorators/processes_decorator\"\nrequire_relative \"solid_queue_dashboard/decorators/recurring_task_decorator\"\nrequire_relative \"solid_queue_dashboard/decorators/recurring_tasks_decorator\"\n\nmodule SolidQueueDashboard\n  class Error < StandardError; end\n\n  def self.job_queue_names\n    SolidQueue::Job.distinct.pluck(:queue_name)\n  end\n\n  def self.job_class_names\n    SolidQueue::Job.distinct.pluck(:class_name)\n  end\n\n  def self.decorate(object)\n    case object\n    when SolidQueue::Job\n      Decorators::JobDecorator.new(object)\n    when SolidQueue::Job.const_get(:ActiveRecord_Relation)\n      Decorators::JobsDecorator.new(object)\n    when SolidQueue::Process\n      Decorators::ProcessDecorator.new(object)\n    when SolidQueue::Process.const_get(:ActiveRecord_Relation)\n      Decorators::ProcessesDecorator.new(object)\n    when SolidQueue::RecurringTask\n      Decorators::RecurringTaskDecorator.new(object)\n    when SolidQueue::RecurringTask.const_get(:ActiveRecord_Relation)\n      Decorators::RecurringTasksDecorator.new(object)\n    else\n      raise Error, \"Cannot decorate #{object.class}\"\n    end\n  end\nend\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"private\": true,\n  \"scripts\": {\n    \"build\": \"tailwindcss -i ./app/assets/stylesheets/solid_queue_dashboard/tailwind.css -o ./app/assets/stylesheets/solid_queue_dashboard/application.css\",\n    \"watch\": \"tailwindcss -i ./app/assets/stylesheets/solid_queue_dashboard/tailwind.css -o ./app/assets/stylesheets/solid_queue_dashboard/application.css --watch\"\n  },\n  \"devDependencies\": {\n    \"@tailwindcss/forms\": \"^0.5.9\",\n    \"@tailwindcss/typography\": \"^0.5.15\",\n    \"tailwindcss\": \"^3.4.13\",\n    \"tailwindcss-animate\": \"^1.0.7\"\n  }\n}"
  },
  {
    "path": "sig/solid_queue_dashboard.rbs",
    "content": "module SolidQueueDashboard\n  VERSION: String\n  # See the writing guide of rbs: https://github.com/ruby/rbs#guides\nend\n"
  },
  {
    "path": "solid_queue_dashboard.gemspec",
    "content": "# frozen_string_literal: true\n\nrequire_relative \"lib/solid_queue_dashboard/version\"\n\nGem::Specification.new do |spec|\n  spec.name = \"solid_queue_dashboard\"\n  spec.version = SolidQueueDashboard::VERSION\n  spec.authors = [ \"Andrew Kodkod\" ]\n  spec.email = [ \"andrew@kodkod.me\" ]\n\n  spec.summary = \"Solid Queue Dashboard\"\n  spec.description = \"Dashboard for Solid Queue\"\n  spec.homepage = \"https://github.com/akodkod/solid_queue_dashboard\"\n  spec.license = \"MIT\"\n  spec.required_ruby_version = \">= 3.0.0\"\n\n  spec.metadata[\"allowed_push_host\"] = \"https://rubygems.org\"\n\n  spec.metadata[\"homepage_uri\"] = spec.homepage\n  spec.metadata[\"source_code_uri\"] = \"https://github.com/akodkod/solid_queue_dashboard\"\n  spec.metadata[\"changelog_uri\"] = \"https://github.com/akodkod/solid_queue_dashboard/CHANGELOG.md\"\n\n  # Specify which files should be added to the gem when it is released.\n  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.\n  gemspec = File.basename(__FILE__)\n  spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls|\n    ls.readlines(\"\\x0\", chomp: true).reject do |filename|\n      (filename == gemspec) ||\n        filename.start_with?(*%w[bin/ test/ spec/ features/ test_app/ .git .github appveyor Gemfile]) ||\n        filename.end_with?(\".gem\") # Exclude gem files\n    end\n  end\n\n  spec.bindir = \"exe\"\n  spec.executables = spec.files.grep(%r{\\Aexe/}) { |f| File.basename(f) }\n  spec.require_paths = [ \"lib\" ]\n\n  spec.add_dependency \"solid_queue\", \">= 1.0.0\"\n  spec.add_dependency \"groupdate\", \">= 6.5\"\n  spec.add_dependency \"chartkick\", \">= 5.0\"\nend\n"
  },
  {
    "path": "tailwind.config.js",
    "content": "const { fontFamily } = require(\"tailwindcss/defaultTheme\")\n\n/** @type {import('tailwindcss').Config} */\nmodule.exports = {\n  darkMode: [\"class\"],\n  content: [\n    \"./app/views/**/*.html.erb\",\n    \"./app/helpers/**/*.rb\",\n    \"./app/javascript/**/*.js\",\n  ],\n  theme: {\n    container: {\n      center: true,\n      padding: \"2rem\",\n      screens: {\n        \"2xl\": \"1400px\",\n      },\n    },\n    extend: {\n      colors: {\n        border: \"hsl(var(--border))\",\n        input: \"hsl(var(--input))\",\n        ring: \"hsl(var(--ring))\",\n        background: \"hsl(var(--background))\",\n        foreground: \"hsl(var(--foreground))\",\n        primary: {\n          DEFAULT: \"hsl(var(--primary))\",\n          foreground: \"hsl(var(--primary-foreground))\",\n        },\n        secondary: {\n          DEFAULT: \"hsl(var(--secondary))\",\n          foreground: \"hsl(var(--secondary-foreground))\",\n        },\n        destructive: {\n          DEFAULT: \"hsl(var(--destructive))\",\n          foreground: \"hsl(var(--destructive-foreground))\",\n        },\n        muted: {\n          DEFAULT: \"hsl(var(--muted))\",\n          foreground: \"hsl(var(--muted-foreground))\",\n        },\n        accent: {\n          DEFAULT: \"hsl(var(--accent))\",\n          foreground: \"hsl(var(--accent-foreground))\",\n        },\n        popover: {\n          DEFAULT: \"hsl(var(--popover))\",\n          foreground: \"hsl(var(--popover-foreground))\",\n        },\n        card: {\n          DEFAULT: \"hsl(var(--card))\",\n          foreground: \"hsl(var(--card-foreground))\",\n        },\n      },\n      borderRadius: {\n        lg: `var(--radius)`,\n        md: `calc(var(--radius) - 2px)`,\n        sm: \"calc(var(--radius) - 4px)\",\n      },\n      opacity: {\n        7.5: \"0.075\",\n      },\n      keyframes: {\n        \"accordion-down\": {\n          from: { height: \"0\" },\n          to: { height: \"var(--radix-accordion-content-height)\" },\n        },\n        \"accordion-up\": {\n          from: { height: \"var(--radix-accordion-content-height)\" },\n          to: { height: \"0\" },\n        },\n      },\n      animation: {\n        \"accordion-down\": \"accordion-down 0.2s ease-out\",\n        \"accordion-up\": \"accordion-up 0.2s ease-out\",\n      },\n    },\n  },\n  plugins: [\n    require(\"tailwindcss-animate\"),\n    require(\"@tailwindcss/forms\")({ strategy: \"class\" }),\n  ],\n}\n"
  },
  {
    "path": "test/test_helper.rb",
    "content": "# frozen_string_literal: true\n\n$LOAD_PATH.unshift File.expand_path(\"../lib\", __dir__)\nrequire \"solid_queue_dashboard\"\n\nrequire \"minitest/autorun\"\n"
  },
  {
    "path": "test/test_solid_queue_dashboard.rb",
    "content": "# frozen_string_literal: true\n\nrequire \"test_helper\"\n\nclass TestSolidQueueDashboard < Minitest::Test\n  def test_that_it_has_a_version_number\n    assert ::SolidQueueDashboard::VERSION\n  end\nend\n"
  },
  {
    "path": "test_app/.ruby-version",
    "content": "3.3.4\n"
  },
  {
    "path": "test_app/Gemfile",
    "content": "source \"https://rubygems.org\"\n\ngem \"rails\", \"~> 8.0.0.beta1\"\ngem \"sqlite3\", \">= 2.1\"\ngem \"puma\", \">= 5.0\"\ngem \"propshaft\"\ngem \"solid_queue\"\ngem 'solid_queue_dashboard', path: '..'\ngem \"thruster\", require: false\ngem \"ostruct\"\ngem \"tzinfo-data\", platforms: %i[ windows jruby ]\n\ngroup :development, :test do\n  gem \"debug\", platforms: %i[ mri windows ], require: \"debug/prelude\"\nend\n"
  },
  {
    "path": "test_app/README.md",
    "content": "# Test App\n"
  },
  {
    "path": "test_app/Rakefile",
    "content": "# Add your own tasks in files placed in lib/tasks ending in .rake,\n# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.\n\nrequire_relative \"config/application\"\n\nRails.application.load_tasks\n"
  },
  {
    "path": "test_app/app/controllers/application_controller.rb",
    "content": "class ApplicationController < ActionController::API\nend\n"
  },
  {
    "path": "test_app/app/controllers/concerns/.keep",
    "content": ""
  },
  {
    "path": "test_app/app/jobs/accept_arguments_job.rb",
    "content": "class AcceptArgumentsJob < ApplicationJob\n  queue_as :default\n\n  def perform(*args)\n    # Do something later\n  end\nend\n"
  },
  {
    "path": "test_app/app/jobs/always_fail_job.rb",
    "content": "class AlwaysFailJob < ApplicationJob\n  queue_as :default\n\n  def perform(*args)\n    raise \"Sorry, I always fail :)\"\n  end\nend\n"
  },
  {
    "path": "test_app/app/jobs/application_job.rb",
    "content": "class ApplicationJob < ActiveJob::Base\n  # Automatically retry jobs that encountered a deadlock\n  # retry_on ActiveRecord::Deadlocked\n\n  # Most jobs are safe to ignore if the underlying records are no longer available\n  # discard_on ActiveJob::DeserializationError\nend\n"
  },
  {
    "path": "test_app/app/jobs/few_seconds_job.rb",
    "content": "class FewSecondsJob < ApplicationJob\n  queue_as :another_queue\n\n  def perform(*args)\n    sleep rand(1..3).seconds\n  end\nend\n"
  },
  {
    "path": "test_app/app/jobs/good_job.rb",
    "content": "class GoodJob < ApplicationJob\n  queue_as :default\n\n  def perform(*args)\n    # I'm a good job. I never fail :)\n  end\nend\n"
  },
  {
    "path": "test_app/app/jobs/long_running_job.rb",
    "content": "class LongRunningJob < ApplicationJob\n  queue_as :default\n\n  def perform(*args)\n    sleep rand(10..60).minutes\n  end\nend\n"
  },
  {
    "path": "test_app/app/jobs/random_fail_job.rb",
    "content": "class RandomFailJob < ApplicationJob\n  queue_as :default\n\n  def perform(*args)\n    return if rand(1..100) <= 50\n\n    raise \"Sorry, I failed randomly :(\"\n  end\nend\n"
  },
  {
    "path": "test_app/app/jobs/retrying_job.rb",
    "content": "class RetryingJob < ApplicationJob\n  queue_as :default\n  retry_on StandardError, wait: 5.seconds, attempts: 3\n\n  def perform(*args)\n    raise \"Sorry, I always fail but will retry 3 times\"\n  end\nend\n"
  },
  {
    "path": "test_app/app/models/application_record.rb",
    "content": "class ApplicationRecord < ActiveRecord::Base\n  primary_abstract_class\nend\n"
  },
  {
    "path": "test_app/app/models/concerns/.keep",
    "content": ""
  },
  {
    "path": "test_app/bin/bundle",
    "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\n#\n# This file was generated by Bundler.\n#\n# The application 'bundle' is installed as part of a gem, and\n# this file is here to facilitate running it.\n#\n\nrequire \"rubygems\"\n\nm = Module.new do\n  module_function\n\n  def invoked_as_script?\n    File.expand_path($0) == File.expand_path(__FILE__)\n  end\n\n  def env_var_version\n    ENV[\"BUNDLER_VERSION\"]\n  end\n\n  def cli_arg_version\n    return unless invoked_as_script? # don't want to hijack other binstubs\n    return unless \"update\".start_with?(ARGV.first || \" \") # must be running `bundle update`\n    bundler_version = nil\n    update_index = nil\n    ARGV.each_with_index do |a, i|\n      if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)\n        bundler_version = a\n      end\n      next unless a =~ /\\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\\z/\n      bundler_version = $1\n      update_index = i\n    end\n    bundler_version\n  end\n\n  def gemfile\n    gemfile = ENV[\"BUNDLE_GEMFILE\"]\n    return gemfile if gemfile && !gemfile.empty?\n\n    File.expand_path(\"../Gemfile\", __dir__)\n  end\n\n  def lockfile\n    lockfile =\n      case File.basename(gemfile)\n      when \"gems.rb\" then gemfile.sub(/\\.rb$/, \".locked\")\n      else \"#{gemfile}.lock\"\n      end\n    File.expand_path(lockfile)\n  end\n\n  def lockfile_version\n    return unless File.file?(lockfile)\n    lockfile_contents = File.read(lockfile)\n    return unless lockfile_contents =~ /\\n\\nBUNDLED WITH\\n\\s{2,}(#{Gem::Version::VERSION_PATTERN})\\n/\n    Regexp.last_match(1)\n  end\n\n  def bundler_requirement\n    @bundler_requirement ||=\n      env_var_version ||\n      cli_arg_version ||\n      bundler_requirement_for(lockfile_version)\n  end\n\n  def bundler_requirement_for(version)\n    return \"#{Gem::Requirement.default}.a\" unless version\n\n    bundler_gem_version = Gem::Version.new(version)\n\n    bundler_gem_version.approximate_recommendation\n  end\n\n  def load_bundler!\n    ENV[\"BUNDLE_GEMFILE\"] ||= gemfile\n\n    activate_bundler\n  end\n\n  def activate_bundler\n    gem_error = activation_error_handling do\n      gem \"bundler\", bundler_requirement\n    end\n    return if gem_error.nil?\n    require_error = activation_error_handling do\n      require \"bundler/version\"\n    end\n    return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))\n    warn \"Activating bundler (#{bundler_requirement}) failed:\\n#{gem_error.message}\\n\\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`\"\n    exit 42\n  end\n\n  def activation_error_handling\n    yield\n    nil\n  rescue StandardError, LoadError => e\n    e\n  end\nend\n\nm.load_bundler!\n\nif m.invoked_as_script?\n  load Gem.bin_path(\"bundler\", \"bundle\")\nend\n"
  },
  {
    "path": "test_app/bin/dev",
    "content": "#!/usr/bin/env ruby\nexec \"./bin/rails\", \"server\", *ARGV\n"
  },
  {
    "path": "test_app/bin/jobs",
    "content": "#!/usr/bin/env ruby\n\nrequire_relative \"../config/environment\"\nrequire \"solid_queue/cli\"\n\nSolidQueue::Cli.start(ARGV)\n"
  },
  {
    "path": "test_app/bin/rails",
    "content": "#!/usr/bin/env ruby\nAPP_PATH = File.expand_path(\"../config/application\", __dir__)\nrequire_relative \"../config/boot\"\nrequire \"rails/commands\"\n"
  },
  {
    "path": "test_app/bin/rake",
    "content": "#!/usr/bin/env ruby\nrequire_relative \"../config/boot\"\nrequire \"rake\"\nRake.application.run\n"
  },
  {
    "path": "test_app/bin/setup",
    "content": "#!/usr/bin/env ruby\nrequire \"fileutils\"\n\nAPP_ROOT = File.expand_path(\"..\", __dir__)\nAPP_NAME = \"test-app\"\n\ndef system!(*args)\n  system(*args, exception: true)\nend\n\nFileUtils.chdir APP_ROOT do\n  # This script is a way to set up or update your development environment automatically.\n  # This script is idempotent, so that you can run it at any time and get an expectable outcome.\n  # Add necessary setup steps to this file.\n\n  puts \"== Installing dependencies ==\"\n  system(\"bundle check\") || system!(\"bundle install\")\n\n  # puts \"\\n== Copying sample files ==\"\n  # unless File.exist?(\"config/database.yml\")\n  #   FileUtils.cp \"config/database.yml.sample\", \"config/database.yml\"\n  # end\n\n  puts \"\\n== Preparing database ==\"\n  system! \"bin/rails db:prepare\"\n\n  puts \"\\n== Removing old logs and tempfiles ==\"\n  system! \"bin/rails log:clear tmp:clear\"\n\n  unless ARGV.include?(\"--skip-server\")\n    puts \"\\n== Starting development server ==\"\n    STDOUT.flush # flush the output before exec(2) so that it displays\n    exec \"bin/dev\"\n  end\nend\n"
  },
  {
    "path": "test_app/bin/thrust",
    "content": "#!/usr/bin/env ruby\nrequire \"rubygems\"\nrequire \"bundler/setup\"\n\nload Gem.bin_path(\"thruster\", \"thrust\")\n"
  },
  {
    "path": "test_app/config/application.rb",
    "content": "require_relative \"boot\"\n\nrequire \"rails\"\n# Pick the frameworks you want:\nrequire \"active_model/railtie\"\nrequire \"active_job/railtie\"\nrequire \"active_record/railtie\"\n# require \"active_storage/engine\"\nrequire \"action_controller/railtie\"\n# require \"action_mailer/railtie\"\n# require \"action_mailbox/engine\"\n# require \"action_text/engine\"\nrequire \"action_view/railtie\"\n# require \"action_cable/engine\"\n# require \"rails/test_unit/railtie\"\n\n# Require the gems listed in Gemfile, including any gems\n# you've limited to :test, :development, or :production.\nBundler.require(*Rails.groups)\n\nmodule TestApp\n  class Application < Rails::Application\n    # Initialize configuration defaults for originally generated Rails version.\n    config.load_defaults 8.0\n\n    # Please, add to the `ignore` list any other `lib` subdirectories that do\n    # not contain `.rb` files, or that should not be reloaded or eager loaded.\n    # Common ones are `templates`, `generators`, or `middleware`, for example.\n    config.autoload_lib(ignore: %w[assets tasks])\n\n    # Use Solid Queue as Active Job queue adapter\n    config.active_job.queue_adapter = :solid_queue\n    config.solid_queue.connects_to = { database: { writing: :queue } }\n\n    # Configuration for the application, engines, and railties goes here.\n    #\n    # These settings can be overridden in specific environments using the files\n    # in config/environments, which are processed later.\n    #\n    # config.time_zone = \"Central Time (US & Canada)\"\n    # config.eager_load_paths << Rails.root.join(\"extras\")\n  end\nend\n"
  },
  {
    "path": "test_app/config/boot.rb",
    "content": "ENV[\"BUNDLE_GEMFILE\"] ||= File.expand_path(\"../Gemfile\", __dir__)\n\nrequire \"bundler/setup\" # Set up gems listed in the Gemfile.\n"
  },
  {
    "path": "test_app/config/credentials.yml.enc",
    "content": "ZBhnsj0GRj3aqXy4hhkzqAmLW/3gBUqWrFHjTiik0RVGI+PJDVawlfIA6ALEX4t8ZQh9UPbsTvgKWBolxwCpE6hcFGOEMIo2Jyi1Mcu3kcRX8XKakSldkIAk5tFWdFfO2BteUUbmWQz3Crb/8H0o6E3EAZOTmq/ERZ9E+WSzv+duIX8NmKD7tJwuC60EK7OxLZYMWZ48FCXBjHQqnyVsh6JuxrkOLqi/Mk/GxSZkQhpVeIvnaVFmzbgQ809PklFD8KiGCrbaKYZyZVGPGA835tJ6wvV9dVg303n8XMxqYvi57Qjw+9lxkKWXWeCb2xUogGkagjmftU7xftbAwbPr+tFGwsJ2TXE1JC2Rsvsd/xHJUEg8SS4Z0SquanWnqeDxPFvQulZlTF6pRlIoxeJZOTi+OoaKq7xw+U81NDTNcDYWUOZNBDirR/S/8uGRvqgMb1HYvp5wluI00IuqQTEAxX8Y1+vTF5R40KhAoUeZRVBK/BNmEIq2HVQt--mUOt2tSizY9V6Z99--yy2u14aFO5JavtYdvTA/Dw=="
  },
  {
    "path": "test_app/config/database.yml",
    "content": "default: &default\n  adapter: sqlite3\n  pool: <%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %>\n  timeout: 5000\n\ndevelopment:\n  primary:\n    <<: *default\n    database: storage/development.sqlite3\n  queue:\n    <<: *default\n    migrations_paths: db/queue_migrate\n    database: storage/development_queue.sqlite3\n\ntest:\n  primary:\n    <<: *default\n    database: storage/test.sqlite3\n  queue:\n    <<: *default\n    migrations_paths: db/queue_migrate\n    database: storage/test_queue.sqlite3\n"
  },
  {
    "path": "test_app/config/environment.rb",
    "content": "# Load the Rails application.\nrequire_relative \"application\"\n\n# Initialize the Rails application.\nRails.application.initialize!\n"
  },
  {
    "path": "test_app/config/environments/development.rb",
    "content": "require \"active_support/core_ext/integer/time\"\n\nRails.application.configure do\n  # Settings specified here will take precedence over those in config/application.rb.\n\n  # Make code changes take effect immediately without server restart.\n  config.enable_reloading = true\n\n  # Do not eager load code on boot.\n  config.eager_load = false\n\n  # Show full error reports.\n  config.consider_all_requests_local = true\n\n  # Enable server timing.\n  config.server_timing = true\n\n  # Enable/disable Action Controller caching. By default Action Controller caching is disabled.\n  # Run rails dev:cache to toggle Action Controller caching.\n  if Rails.root.join(\"tmp/caching-dev.txt\").exist?\n    config.public_file_server.headers = { \"cache-control\" => \"public, max-age=#{2.days.to_i}\" }\n  else\n    config.action_controller.perform_caching = false\n  end\n\n  # Change to :null_store to avoid any caching.\n  config.cache_store = :memory_store\n\n  # Print deprecation notices to the Rails logger.\n  config.active_support.deprecation = :log\n\n  # Raise an error on page load if there are pending migrations.\n  config.active_record.migration_error = :page_load\n\n  # Highlight code that triggered database queries in logs.\n  config.active_record.verbose_query_logs = true\n\n  # Append comments with runtime information tags to SQL queries in logs.\n  config.active_record.query_log_tags_enabled = true\n\n  # Raises error for missing translations.\n  # config.i18n.raise_on_missing_translations = true\n\n  # Annotate rendered view with file names.\n  config.action_view.annotate_rendered_view_with_filenames = true\n\n  # Raise error when a before_action's only/except options reference missing actions.\n  config.action_controller.raise_on_missing_callback_actions = true\nend\n"
  },
  {
    "path": "test_app/config/environments/production.rb",
    "content": "require \"active_support/core_ext/integer/time\"\n\nRails.application.configure do\n  # Settings specified here will take precedence over those in config/application.rb.\n\n  # Code is not reloaded between requests.\n  config.enable_reloading = false\n\n  # Eager load code on boot for better performance and memory savings (ignored by Rake tasks).\n  config.eager_load = true\n\n  # Full error reports are disabled.\n  config.consider_all_requests_local = false\n\n  # Cache assets for far-future expiry since they are all digest stamped.\n  config.public_file_server.headers = { \"cache-control\" => \"public, max-age=#{1.year.to_i}\" }\n\n  # Enable serving of images, stylesheets, and JavaScripts from an asset server.\n  # config.asset_host = \"http://assets.example.com\"\n\n  # Assume all access to the app is happening through a SSL-terminating reverse proxy.\n  config.assume_ssl = true\n\n  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.\n  config.force_ssl = true\n\n  # Skip http-to-https redirect for the default health check endpoint.\n  # config.ssl_options = { redirect: { exclude: ->(request) { request.path == \"/up\" } } }\n\n  # Log to STDOUT with the current request id as a default log tag.\n  config.log_tags = [ :request_id ]\n  config.logger   = ActiveSupport::TaggedLogging.logger(STDOUT)\n\n  # Change to \"debug\" to log everything (including potentially personally-identifiable information!)\n  config.log_level = ENV.fetch(\"RAILS_LOG_LEVEL\", \"info\")\n\n  # Prevent health checks from clogging up the logs.\n  config.silence_healthcheck_path = \"/up\"\n\n  # Don't log any deprecations.\n  config.active_support.report_deprecations = false\n\n  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to\n  # the I18n.default_locale when a translation cannot be found).\n  config.i18n.fallbacks = true\n\n  # Do not dump schema after migrations.\n  config.active_record.dump_schema_after_migration = false\n\n  # Only use :id for inspections in production.\n  config.active_record.attributes_for_inspect = [ :id ]\n\n  # Enable DNS rebinding protection and other `Host` header attacks.\n  # config.hosts = [\n  #   \"example.com\",     # Allow requests from example.com\n  #   /.*\\.example\\.com/ # Allow requests from subdomains like `www.example.com`\n  # ]\n  #\n  # Skip DNS rebinding protection for the default health check endpoint.\n  # config.host_authorization = { exclude: ->(request) { request.path == \"/up\" } }\nend\n"
  },
  {
    "path": "test_app/config/environments/test.rb",
    "content": "# The test environment is used exclusively to run your application's\n# test suite. You never need to work with it otherwise. Remember that\n# your test database is \"scratch space\" for the test suite and is wiped\n# and recreated between test runs. Don't rely on the data there!\n\nRails.application.configure do\n  # Settings specified here will take precedence over those in config/application.rb.\n\n  # While tests run files are not watched, reloading is not necessary.\n  config.enable_reloading = false\n\n  # Eager loading loads your entire application. When running a single test locally,\n  # this is usually not necessary, and can slow down your test suite. However, it's\n  # recommended that you enable it in continuous integration systems to ensure eager\n  # loading is working properly before deploying your code.\n  config.eager_load = ENV[\"CI\"].present?\n\n  # Configure public file server for tests with cache-control for performance.\n  config.public_file_server.headers = { \"cache-control\" => \"public, max-age=3600\" }\n\n  # Show full error reports.\n  config.consider_all_requests_local = true\n  config.cache_store = :null_store\n\n  # Render exception templates for rescuable exceptions and raise for other exceptions.\n  config.action_dispatch.show_exceptions = :rescuable\n\n  # Disable request forgery protection in test environment.\n  config.action_controller.allow_forgery_protection = false\n\n  # Print deprecation notices to the stderr.\n  config.active_support.deprecation = :stderr\n\n  # Raises error for missing translations.\n  # config.i18n.raise_on_missing_translations = true\n\n  # Annotate rendered view with file names.\n  # config.action_view.annotate_rendered_view_with_filenames = true\n\n  # Raise error when a before_action's only/except options reference missing actions.\n  config.action_controller.raise_on_missing_callback_actions = true\nend\n"
  },
  {
    "path": "test_app/config/initializers/cors.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Avoid CORS issues when API is called from the frontend app.\n# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin Ajax requests.\n\n# Read more: https://github.com/cyu/rack-cors\n\n# Rails.application.config.middleware.insert_before 0, Rack::Cors do\n#   allow do\n#     origins \"example.com\"\n#\n#     resource \"*\",\n#       headers: :any,\n#       methods: [:get, :post, :put, :patch, :delete, :options, :head]\n#   end\n# end\n"
  },
  {
    "path": "test_app/config/initializers/filter_parameter_logging.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.\n# Use this to limit dissemination of sensitive information.\n# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.\nRails.application.config.filter_parameters += [\n  :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn, :cvv, :cvc\n]\n"
  },
  {
    "path": "test_app/config/initializers/inflections.rb",
    "content": "# Be sure to restart your server when you modify this file.\n\n# Add new inflection rules using the following format. Inflections\n# are locale specific, and you may define rules for as many different\n# locales as you wish. All of these examples are active by default:\n# ActiveSupport::Inflector.inflections(:en) do |inflect|\n#   inflect.plural /^(ox)$/i, \"\\\\1en\"\n#   inflect.singular /^(ox)en/i, \"\\\\1\"\n#   inflect.irregular \"person\", \"people\"\n#   inflect.uncountable %w( fish sheep )\n# end\n\n# These inflection rules are supported but not enabled by default:\n# ActiveSupport::Inflector.inflections(:en) do |inflect|\n#   inflect.acronym \"RESTful\"\n# end\n"
  },
  {
    "path": "test_app/config/locales/en.yml",
    "content": "# Files in the config/locales directory are used for internationalization and\n# are automatically loaded by Rails. If you want to use locales other than\n# English, add the necessary files in this directory.\n#\n# To use the locales, use `I18n.t`:\n#\n#     I18n.t \"hello\"\n#\n# In views, this is aliased to just `t`:\n#\n#     <%= t(\"hello\") %>\n#\n# To use a different locale, set it with `I18n.locale`:\n#\n#     I18n.locale = :es\n#\n# This would use the information in config/locales/es.yml.\n#\n# To learn more about the API, please read the Rails Internationalization guide\n# at https://guides.rubyonrails.org/i18n.html.\n#\n# Be aware that YAML interprets the following case-insensitive strings as\n# booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings\n# must be quoted to be interpreted as strings. For example:\n#\n#     en:\n#       \"yes\": yup\n#       enabled: \"ON\"\n\nen:\n  hello: \"Hello world\"\n"
  },
  {
    "path": "test_app/config/master.key",
    "content": "c90d2d971451d5d35efbd837a2751096"
  },
  {
    "path": "test_app/config/puma.rb",
    "content": "# This configuration file will be evaluated by Puma. The top-level methods that\n# are invoked here are part of Puma's configuration DSL. For more information\n# about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html.\n#\n# Puma starts a configurable number of processes (workers) and each process\n# serves each request in a thread from an internal thread pool.\n#\n# You can control the number of workers using ENV[\"WEB_CONCURRENCY\"]. You\n# should only set this value when you want to run 2 or more workers. The\n# default is already 1.\n#\n# The ideal number of threads per worker depends both on how much time the\n# application spends waiting for IO operations and on how much you wish to\n# prioritize throughput over latency.\n#\n# As a rule of thumb, increasing the number of threads will increase how much\n# traffic a given process can handle (throughput), but due to CRuby's\n# Global VM Lock (GVL) it has diminishing returns and will degrade the\n# response time (latency) of the application.\n#\n# The default is set to 3 threads as it's deemed a decent compromise between\n# throughput and latency for the average Rails application.\n#\n# Any libraries that use a connection pool or another resource pool should\n# be configured to provide at least as many connections as the number of\n# threads. This includes Active Record's `pool` parameter in `database.yml`.\nthreads_count = ENV.fetch(\"RAILS_MAX_THREADS\", 3)\nthreads threads_count, threads_count\n\n# Specifies the `port` that Puma will listen on to receive requests; default is 3000.\nport ENV.fetch(\"PORT\", 3000)\n\n# Allow puma to be restarted by `bin/rails restart` command.\nplugin :tmp_restart\n\n# Run the Solid Queue supervisor inside of Puma for single-server deployments\nplugin :solid_queue if ENV[\"SOLID_QUEUE_IN_PUMA\"]\n\n# Specify the PID file. Defaults to tmp/pids/server.pid in development.\n# In other environments, only set the PID file if requested.\npidfile ENV[\"PIDFILE\"] if ENV[\"PIDFILE\"]\n"
  },
  {
    "path": "test_app/config/queue.yml",
    "content": "default: &default\n  dispatchers:\n    - polling_interval: 1\n      batch_size: 500\n  workers:\n    - queues: \"*\"\n      threads: 3\n      processes: <%= ENV.fetch(\"JOB_CONCURRENCY\", 1) %>\n      polling_interval: 0.1\n\ndevelopment:\n  <<: *default\n\ntest:\n  <<: *default\n\nproduction:\n  <<: *default\n"
  },
  {
    "path": "test_app/config/recurring.yml",
    "content": " development:\n   periodic_cleanup:\n     class: RandomFailJob\n     queue: background\n     args: [ 1000, { batch_size: 500 } ]\n     schedule: every hour\n   periodic_command:\n     command: \"SoftDeletedRecord.due.delete_all\"\n     priority: 2\n     schedule: at 5am every day\n"
  },
  {
    "path": "test_app/config/routes.rb",
    "content": "Rails.application.routes.draw do\n  mount SolidQueueDashboard::Engine, at: \"/solid-queue\"\n\n  get \"up\", to: \"rails/health#show\", as: :rails_health_check\nend\n"
  },
  {
    "path": "test_app/config.ru",
    "content": "# This file is used by Rack-based servers to start the application.\n\nrequire_relative \"config/environment\"\n\nrun Rails.application\nRails.application.load_server\n"
  },
  {
    "path": "test_app/db/queue_schema.rb",
    "content": "ActiveRecord::Schema[7.1].define(version: 1) do\n  create_table \"solid_queue_blocked_executions\", force: :cascade do |t|\n    t.bigint \"job_id\", null: false\n    t.string \"queue_name\", null: false\n    t.integer \"priority\", default: 0, null: false\n    t.string \"concurrency_key\", null: false\n    t.datetime \"expires_at\", null: false\n    t.datetime \"created_at\", null: false\n    t.index [ \"concurrency_key\", \"priority\", \"job_id\" ], name: \"index_solid_queue_blocked_executions_for_release\"\n    t.index [ \"expires_at\", \"concurrency_key\" ], name: \"index_solid_queue_blocked_executions_for_maintenance\"\n    t.index [ \"job_id\" ], name: \"index_solid_queue_blocked_executions_on_job_id\", unique: true\n  end\n\n  create_table \"solid_queue_claimed_executions\", force: :cascade do |t|\n    t.bigint \"job_id\", null: false\n    t.bigint \"process_id\"\n    t.datetime \"created_at\", null: false\n    t.index [ \"job_id\" ], name: \"index_solid_queue_claimed_executions_on_job_id\", unique: true\n    t.index [ \"process_id\", \"job_id\" ], name: \"index_solid_queue_claimed_executions_on_process_id_and_job_id\"\n  end\n\n  create_table \"solid_queue_failed_executions\", force: :cascade do |t|\n    t.bigint \"job_id\", null: false\n    t.text \"error\"\n    t.datetime \"created_at\", null: false\n    t.index [ \"job_id\" ], name: \"index_solid_queue_failed_executions_on_job_id\", unique: true\n  end\n\n  create_table \"solid_queue_jobs\", force: :cascade do |t|\n    t.string \"queue_name\", null: false\n    t.string \"class_name\", null: false\n    t.text \"arguments\"\n    t.integer \"priority\", default: 0, null: false\n    t.string \"active_job_id\"\n    t.datetime \"scheduled_at\"\n    t.datetime \"finished_at\"\n    t.string \"concurrency_key\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [ \"active_job_id\" ], name: \"index_solid_queue_jobs_on_active_job_id\"\n    t.index [ \"class_name\" ], name: \"index_solid_queue_jobs_on_class_name\"\n    t.index [ \"finished_at\" ], name: \"index_solid_queue_jobs_on_finished_at\"\n    t.index [ \"queue_name\", \"finished_at\" ], name: \"index_solid_queue_jobs_for_filtering\"\n    t.index [ \"scheduled_at\", \"finished_at\" ], name: \"index_solid_queue_jobs_for_alerting\"\n  end\n\n  create_table \"solid_queue_pauses\", force: :cascade do |t|\n    t.string \"queue_name\", null: false\n    t.datetime \"created_at\", null: false\n    t.index [ \"queue_name\" ], name: \"index_solid_queue_pauses_on_queue_name\", unique: true\n  end\n\n  create_table \"solid_queue_processes\", force: :cascade do |t|\n    t.string \"kind\", null: false\n    t.datetime \"last_heartbeat_at\", null: false\n    t.bigint \"supervisor_id\"\n    t.integer \"pid\", null: false\n    t.string \"hostname\"\n    t.text \"metadata\"\n    t.datetime \"created_at\", null: false\n    t.string \"name\", null: false\n    t.index [ \"last_heartbeat_at\" ], name: \"index_solid_queue_processes_on_last_heartbeat_at\"\n    t.index [ \"name\", \"supervisor_id\" ], name: \"index_solid_queue_processes_on_name_and_supervisor_id\", unique: true\n    t.index [ \"supervisor_id\" ], name: \"index_solid_queue_processes_on_supervisor_id\"\n  end\n\n  create_table \"solid_queue_ready_executions\", force: :cascade do |t|\n    t.bigint \"job_id\", null: false\n    t.string \"queue_name\", null: false\n    t.integer \"priority\", default: 0, null: false\n    t.datetime \"created_at\", null: false\n    t.index [ \"job_id\" ], name: \"index_solid_queue_ready_executions_on_job_id\", unique: true\n    t.index [ \"priority\", \"job_id\" ], name: \"index_solid_queue_poll_all\"\n    t.index [ \"queue_name\", \"priority\", \"job_id\" ], name: \"index_solid_queue_poll_by_queue\"\n  end\n\n  create_table \"solid_queue_recurring_executions\", force: :cascade do |t|\n    t.bigint \"job_id\", null: false\n    t.string \"task_key\", null: false\n    t.datetime \"run_at\", null: false\n    t.datetime \"created_at\", null: false\n    t.index [ \"job_id\" ], name: \"index_solid_queue_recurring_executions_on_job_id\", unique: true\n    t.index [ \"task_key\", \"run_at\" ], name: \"index_solid_queue_recurring_executions_on_task_key_and_run_at\", unique: true\n  end\n\n  create_table \"solid_queue_recurring_tasks\", force: :cascade do |t|\n    t.string \"key\", null: false\n    t.string \"schedule\", null: false\n    t.string \"command\", limit: 2048\n    t.string \"class_name\"\n    t.text \"arguments\"\n    t.string \"queue_name\"\n    t.integer \"priority\", default: 0\n    t.boolean \"static\", default: true, null: false\n    t.text \"description\"\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [ \"key\" ], name: \"index_solid_queue_recurring_tasks_on_key\", unique: true\n    t.index [ \"static\" ], name: \"index_solid_queue_recurring_tasks_on_static\"\n  end\n\n  create_table \"solid_queue_scheduled_executions\", force: :cascade do |t|\n    t.bigint \"job_id\", null: false\n    t.string \"queue_name\", null: false\n    t.integer \"priority\", default: 0, null: false\n    t.datetime \"scheduled_at\", null: false\n    t.datetime \"created_at\", null: false\n    t.index [ \"job_id\" ], name: \"index_solid_queue_scheduled_executions_on_job_id\", unique: true\n    t.index [ \"scheduled_at\", \"priority\", \"job_id\" ], name: \"index_solid_queue_dispatch_all\"\n  end\n\n  create_table \"solid_queue_semaphores\", force: :cascade do |t|\n    t.string \"key\", null: false\n    t.integer \"value\", default: 1, null: false\n    t.datetime \"expires_at\", null: false\n    t.datetime \"created_at\", null: false\n    t.datetime \"updated_at\", null: false\n    t.index [ \"expires_at\" ], name: \"index_solid_queue_semaphores_on_expires_at\"\n    t.index [ \"key\", \"value\" ], name: \"index_solid_queue_semaphores_on_key_and_value\"\n    t.index [ \"key\" ], name: \"index_solid_queue_semaphores_on_key\", unique: true\n  end\n\n  add_foreign_key \"solid_queue_blocked_executions\", \"solid_queue_jobs\", column: \"job_id\", on_delete: :cascade\n  add_foreign_key \"solid_queue_claimed_executions\", \"solid_queue_jobs\", column: \"job_id\", on_delete: :cascade\n  add_foreign_key \"solid_queue_failed_executions\", \"solid_queue_jobs\", column: \"job_id\", on_delete: :cascade\n  add_foreign_key \"solid_queue_ready_executions\", \"solid_queue_jobs\", column: \"job_id\", on_delete: :cascade\n  add_foreign_key \"solid_queue_recurring_executions\", \"solid_queue_jobs\", column: \"job_id\", on_delete: :cascade\n  add_foreign_key \"solid_queue_scheduled_executions\", \"solid_queue_jobs\", column: \"job_id\", on_delete: :cascade\nend\n"
  },
  {
    "path": "test_app/db/schema.rb",
    "content": "# This file is auto-generated from the current state of the database. Instead\n# of editing this file, please use the migrations feature of Active Record to\n# incrementally modify your database, and then regenerate this schema definition.\n#\n# This file is the source Rails uses to define your schema when running `bin/rails\n# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to\n# be faster and is potentially less error prone than running all of your\n# migrations from scratch. Old migrations may fail to apply correctly if those\n# migrations use external dependencies or application code.\n#\n# It's strongly recommended that you check this file into your version control system.\n\nActiveRecord::Schema[8.0].define(version: 0) do\nend\n"
  },
  {
    "path": "test_app/db/seeds.rb",
    "content": "# This file should ensure the existence of records required to run the application in every environment (production,\n# development, test). The code here should be idempotent so that it can be executed at any point in every environment.\n# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup).\n#\n# Example:\n#\n#   [\"Action\", \"Comedy\", \"Drama\", \"Horror\"].each do |genre_name|\n#     MovieGenre.find_or_create_by!(name: genre_name)\n#   end\n"
  },
  {
    "path": "test_app/lib/tasks/.keep",
    "content": ""
  },
  {
    "path": "test_app/lib/tasks/jobs.rake",
    "content": "require \"active_support/testing/time_helpers\"\n\nnamespace :jobs do\n  desc \"Generate dummy data for jobs\"\n  task :generate_dummy_data, [ :count ] => :environment do |t, args|\n    include ActiveSupport::Testing::TimeHelpers\n\n    count = (args[:count] || 100).to_i\n\n    job_classes = [\n      GoodJob,\n      # FewSecondsJob,\n      RandomFailJob,\n      AlwaysFailJob,\n      RetryingJob\n    ]\n\n    # Random arguments\n    arguments = [\n      [ { \"key\" => \"value\", \"another_key\" => false, truth: 42 } ],\n      [ \"hello_world\", true, nil ],\n      [ 451 ],\n      [ Time.now.utc ]\n    ]\n\n    count.times do\n      # Generate a random time in the past (between 1 and 10 days ago)\n      random_past_time = rand(1..10).days.ago + rand(1..23).hours + rand(1..59).minutes\n\n      # Travel to the random past time and enqueue a random job\n      travel_to(random_past_time) do\n        job_class = job_classes.sample\n        job_arguments = arguments.sample\n\n        job_class.perform_later(*job_arguments)\n      end\n    end\n\n    # Reset the time back to the present\n    travel_back\n  end\nend\n"
  },
  {
    "path": "test_app/public/robots.txt",
    "content": "# See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file\n"
  },
  {
    "path": "test_app/script/.keep",
    "content": ""
  },
  {
    "path": "test_app/storage/.keep",
    "content": ""
  },
  {
    "path": "test_app/vendor/.keep",
    "content": ""
  }
]