skadi 0.4.0.beta.2 → 0.4.0.beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7cae6dfd50e92042510427a4ab85f50ddec126be0146bb339365fb3abba18c08
4
- data.tar.gz: b594845d90d1919256594c87b4234389677166685227b9bd3ad843a735b41be7
3
+ metadata.gz: 69c9f96eeeec38ea33c8eb352d9c12d9466ec10294c6f293bad4a8d0011bcd03
4
+ data.tar.gz: 07f70d68d1da2bf863770b29b284d2a6083c157854def0052075ec3a1dcbb13b
5
5
  SHA512:
6
- metadata.gz: be0041507c78c96f704e09137a3c35a3c4b86de11e7031756246b0f6086526d4797c9cfafd0de12f6b118d05e2aaa6b353e3b58a3ff53a68914fe34e816a2a81
7
- data.tar.gz: 8ecdc5b41b742221964fc0d45d302f898dbd66db09fab8351926a17aa89760f1fee6d97730946b2e4598e26464fc53c11f0fe6985c0225f88d3b45a3df0f3708
6
+ metadata.gz: 6a33409c7b1adc14884970673422fda594d2af59ba5a7a72d5705430e43c9d66ced9b9db915d31a1132fd4471c46ca4b22dfda79243ae4f1347ce3d0f42e3180
7
+ data.tar.gz: a5ca6dc6342300c4fd459f16e0595877e788f684ca197810c3b8168a91e00420f5a91f4e0ea9a0f5f5c8b6ec68a78c020acaf1550bc53c4baa1d8e51a93c0073
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 0.4.0.beta.4 [2026-09-03]
2
+ - Add initializer to install script
3
+ - Change migration generator to detect the Rails database engine from config
4
+ - Use :jsonb data type for SQLite 3.45.0+
5
+
6
+ ## 0.4.0.beta.3 [2026-09-01]
7
+ - Add "Traffic type" demographic to count bot vs human traffic
8
+ - Change demographic names to be more consistent
9
+ - Fix dashboard association filters not displaying when no other filters are visible
10
+
1
11
  ## 0.4.0.beta.2 [2026-08-27]
2
12
  - Remove server host from referrer and exit page URLs
3
13
  - Update dashboard datasets to allow belongs_to joining, and remove chart level filters
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  First-party, privacy-by-default analytics for Rails.
4
4
 
5
- Skadi adds flexible and lightweight first-party analytics to your Rails app. Track page views and events, perform A/B testing and more, giving you all the information you need to improve your website.
5
+ Skadi adds flexible and lightweight first-party analytics and a data dashboard to your Rails application. Track page views and events, perform A/B testing and more, giving you everything you need to improve your website.
6
6
 
7
7
  Skadi is privacy-by-default, which means it respects users' privacy without any additional configuration. It gives you the power to be compliant with privacy laws*, while still collecting useful usage data about your site.
8
8
 
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-500:oklch(63.7% .237 25.331);--color-red-800:oklch(44.4% .177 26.899);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-light:300;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-normal:1.5;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--aspect-video:16 / 9;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-ice-50:oklch(97.4% .02 247.89);--color-ice-100:oklch(95% .022 238.64);--color-ice-200:oklch(87.6% .046 233.06);--color-ice-300:oklch(81.6% .078 224.93);--color-ice-400:oklch(72.8% .078 228.47);--color-ice-600:oklch(54% .064 238.76);--color-ice-700:oklch(45.4% .057 244.01);--color-ice-800:oklch(36.2% .049 247.19);--color-ice-950:oklch(22.5% .038 257.16);--color-dawn-50:oklch(95.8% .023 48.5);--color-dawn-100:oklch(92.6% .041 46.7);--color-dawn-200:oklch(85.2% .086 44);--color-dawn-300:oklch(78% .136 43.7);--color-dawn-600:oklch(54.9% .194 34.66);--color-dawn-700:oklch(47.2% .193 29.23);--color-dawn-900:oklch(31.1% .098 40.03);--color-night-50:oklch(96.6% .016 278.57);--color-night-100:oklch(92.5% .037 280.64);--color-night-400:oklch(71.7% .154 285.62);--color-night-700:oklch(52.5% .293 292.3);--color-night-800:oklch(40.1% .23 287.69);--color-night-900:oklch(27.1% .162 282.12);--color-night-950:oklch(21.4% .135 274.82);--spacing-prose:min(100%, 48rem)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}body{--tw-gradient-position:to top}@supports (background-image:linear-gradient(in lab, red, red)){body{--tw-gradient-position:to top in oklab}}body{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:#ffede40d}@supports (color:color-mix(in lab, red, red)){body{--tw-gradient-from:color-mix(in oklab, var(--color-dawn-50) 5%, transparent)}}body{--tw-gradient-via:#9c93ff0d}@supports (color:color-mix(in lab, red, red)){body{--tw-gradient-via:color-mix(in oklab, var(--color-night-400) 5%, transparent)}}body{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops);--tw-gradient-to:#4a74900d}@supports (color:color-mix(in lab, red, red)){body{--tw-gradient-to:color-mix(in oklab, var(--color-ice-600) 5%, transparent)}}body{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));padding-bottom:calc(var(--spacing) * 32)}p{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}label{gap:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);flex-direction:column;display:flex}.help-text{max-width:calc(var(--spacing) * 128);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--color-gray-500)}input,select{max-width:calc(var(--spacing) * 120);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-night-100);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal);flex-grow:1}[contenteditable]{max-width:calc(var(--spacing) * 120)}button:where(:not(.unstyled)){--tw-translate-x:0px;--tw-translate-y:0px;width:max-content;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;gap:calc(var(--spacing) * 2);border-bottom-style:var(--tw-border-style);border-color:#2840561a;border-bottom-width:4px;display:flex}@supports (color:color-mix(in lab, red, red)){button:where(:not(.unstyled)){border-color:color-mix(in oklab, var(--color-ice-800) 10%, transparent)}}button:where(:not(.unstyled)){background-color:var(--color-ice-100);padding-inline:calc(var(--spacing) * 4);padding-top:calc(var(--spacing) * 1.5);padding-bottom:var(--spacing);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-ice-950)}button:where(:not(.unstyled)):hover,button:where(:not(.unstyled)):active{background-color:var(--color-ice-50);color:var(--color-black)}button:where(:not(.unstyled)):active{--tw-translate-y:var(--spacing);translate:var(--tw-translate-x) var(--tw-translate-y);clip-path:inset(0 0 .25rem)}button:where(:not(.unstyled)).sm{gap:var(--spacing);padding-inline:calc(var(--spacing) * 3);padding-top:var(--spacing);padding-bottom:calc(var(--spacing) * .75);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}button:where(:not(.unstyled)).emph{border-color:#00000040}@supports (color:color-mix(in lab, red, red)){button:where(:not(.unstyled)).emph{border-color:color-mix(in oklab, var(--color-black) 25%, transparent)}}button:where(:not(.unstyled)).emph{background-color:var(--color-night-700);color:var(--color-white)}button:where(:not(.unstyled)).ghost{border-style:var(--tw-border-style);padding-block:calc(var(--spacing) * 2);color:var(--color-night-800);background-color:#0000;border-width:0}@media (hover:hover){button:where(:not(.unstyled)).ghost:hover{color:var(--color-night-900);--tw-backdrop-brightness:brightness(95%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}}button:where(:not(.unstyled)).ghost:active{translate:none}button:where(:not(.unstyled)).ghost{clip-path:none}button:where(:not(.unstyled)).ghost.sm{padding-block:var(--spacing)}[contenteditable=true]{width:var(--spacing-prose);cursor:text;border-left-style:var(--tw-border-style);--tw-border-style:dashed;border-style:dashed;border-left-width:1px;border-color:var(--color-gray-500);padding-left:calc(var(--spacing) * 3)}[contenteditable][placeholder]:empty:after{color:var(--color-gray-500);content:attr(placeholder);display:inline}#skadi-dashboard{width:calc(var(--spacing) * 256);max-width:100%;padding-inline:calc(var(--spacing) * 4);margin-inline:auto}nav{align-items:flex-start;gap:calc(var(--spacing) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:3px;border-color:var(--color-night-700);width:100%;display:flex}nav>button{margin-bottom:calc(var(--spacing) * -.5);white-space:nowrap;border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3);padding-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);text-overflow:ellipsis;background-color:#0000;border-width:0;flex-shrink:1;display:block;overflow:hidden}nav>button:active{--tw-translate-x:0px;--tw-translate-y:0px;translate:var(--tw-translate-x) var(--tw-translate-y);clip-path:none}nav>button.selected{background-color:var(--color-night-700);padding-inline:calc(var(--spacing) * 4);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-white);flex-shrink:0}nav>button:hover{background-color:var(--color-night-700);color:var(--color-white);flex-shrink:0}nav>button:active{background-color:var(--color-night-700);color:var(--color-night-50)}table{min-width:100%}table td,table th{border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-night-100);padding-block:var(--spacing);padding-right:calc(var(--spacing) * 4);padding-left:calc(var(--spacing) * 2);text-align:left}table th{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}table tr:hover td{background-color:#f1f3ff66}@supports (color:color-mix(in lab, red, red)){table tr:hover td{background-color:color-mix(in oklab, var(--color-night-50) 40%, transparent)}}.pill{background-color:#f1f3ff80}@supports (color:color-mix(in lab, red, red)){.pill{background-color:color-mix(in oklab, var(--color-night-50) 50%, transparent)}}.pill{padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5)}}@layer components;@layer utilities{.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.top-0{top:0}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-18{top:calc(var(--spacing) * 18)}.-right-4\.75{right:calc(var(--spacing) * -4.75)}.right-2{right:calc(var(--spacing) * 2)}.right-6{right:calc(var(--spacing) * 6)}.bottom-2{bottom:calc(var(--spacing) * 2)}.-left-5{left:calc(var(--spacing) * -5)}.left-0\.75{left:calc(var(--spacing) * .75)}.left-1\/2{left:50%}.left-auto{left:auto}.z-10{z-index:10}.col-span-2{grid-column:span 2/span 2}.col-span-4{grid-column:span 4/span 4}.mx-auto{margin-inline:auto}.my-1{margin-block:var(--spacing)}.-mt-1{margin-top:calc(var(--spacing) * -1)}.-mt-2{margin-top:calc(var(--spacing) * -2)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mt-px{margin-top:1px}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-1{margin-left:var(--spacing)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.table{display:table}.aspect-video{aspect-ratio:var(--aspect-video)}.size-4\.5{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}.h-6{height:calc(var(--spacing) * 6)}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-13{width:calc(var(--spacing) * 13)}.w-full{width:100%}.w-max{width:max-content}.max-w-160{max-width:calc(var(--spacing) * 160)}.max-w-256{max-width:calc(var(--spacing) * 256)}.max-w-full{max-width:100%}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-full{flex-basis:100%}.-translate-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-6\.5{--tw-translate-x:calc(var(--spacing) * -6.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-3\.25{--tw-translate-x:calc(var(--spacing) * 3.25);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-6\.5{--tw-translate-x:calc(var(--spacing) * 6.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.grid-flow-col{grid-auto-flow:column}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[auto_4rem_1fr_auto\]{grid-template-columns:auto 4rem 1fr auto}.grid-rows-\[0fr\]{grid-template-rows:0fr}.grid-rows-\[1fr\]{grid-template-rows:1fr}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}.gap-y-4{row-gap:calc(var(--spacing) * 4)}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded-full{border-radius:2147483647px}.border{border-style:var(--tw-border-style);border-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-black\/20{border-color:#0003}@supports (color:color-mix(in lab, red, red)){.border-black\/20{border-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.border-dawn-200{border-color:var(--color-dawn-200)}.border-dawn-600{border-color:var(--color-dawn-600)}.border-gray-600{border-color:var(--color-gray-600)}.border-ice-100{border-color:var(--color-ice-100)}.border-ice-200{border-color:var(--color-ice-200)}.border-ice-400{border-color:var(--color-ice-400)}.border-ice-600{border-color:var(--color-ice-600)}.border-ice-700{border-color:var(--color-ice-700)}.border-night-50{border-color:var(--color-night-50)}.border-night-100{border-color:var(--color-night-100)}.border-night-700{border-color:var(--color-night-700)}.border-red-500{border-color:var(--color-red-500)}.border-red-800{border-color:var(--color-red-800)}.bg-dawn-50{background-color:var(--color-dawn-50)}.bg-dawn-100{background-color:var(--color-dawn-100)}.bg-dawn-300{background-color:var(--color-dawn-300)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-50\/50{background-color:#f9fafb80}@supports (color:color-mix(in lab, red, red)){.bg-gray-50\/50{background-color:color-mix(in oklab, var(--color-gray-50) 50%, transparent)}}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-600{background-color:var(--color-gray-600)}.bg-ice-50{background-color:var(--color-ice-50)}.bg-ice-50\/50{background-color:#eff8ff80}@supports (color:color-mix(in lab, red, red)){.bg-ice-50\/50{background-color:color-mix(in oklab, var(--color-ice-50) 50%, transparent)}}.bg-ice-300{background-color:var(--color-ice-300)}.bg-ice-600{background-color:var(--color-ice-600)}.bg-night-700{background-color:var(--color-night-700)}.bg-red-50\/50{background-color:#fef2f280}@supports (color:color-mix(in lab, red, red)){.bg-red-50\/50{background-color:color-mix(in oklab, var(--color-red-50) 50%, transparent)}}.bg-white{background-color:var(--color-white)}.fill-current{fill:currentColor}.p-1{padding:var(--spacing)}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-8{padding-block:calc(var(--spacing) * 8)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pr-0\.5{padding-right:calc(var(--spacing) * .5)}.pr-1{padding-right:var(--spacing)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.625rem\]{font-size:.625rem}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-pre-wrap{white-space:pre-wrap}.text-dawn-700{color:var(--color-dawn-700)}.text-dawn-900\/65{color:#571900a6}@supports (color:color-mix(in lab, red, red)){.text-dawn-900\/65{color:color-mix(in oklab, var(--color-dawn-900) 65%, transparent)}}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-ice-600{color:var(--color-ice-600)}.text-ice-700{color:var(--color-ice-700)}.text-ice-800{color:var(--color-ice-800)}.text-night-700{color:var(--color-night-700)}.text-night-800{color:var(--color-night-800)}.text-night-950{color:var(--color-night-950)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.opacity-25{opacity:.25}.shadow-inner{--tw-shadow:inset 0 2px 4px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-\[grid-template-rows\]{transition-property:grid-template-rows;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}@media (hover:hover){.group-hover\:text-black:is(:where(.group):hover *){color:var(--color-black)}.group-hover\:text-night-800:is(:where(.group):hover *){color:var(--color-night-800)}}.only\:col-span-2:only-child{grid-column:span 2/span 2}@media (hover:hover){.hover\:border-night-700:hover{border-color:var(--color-night-700)}.hover\:bg-night-50:hover{background-color:var(--color-night-50)}.hover\:bg-transparent:hover{background-color:#0000}.hover\:text-black:hover{color:var(--color-black)}.hover\:backdrop-filter-none:hover{-webkit-backdrop-filter:none;backdrop-filter:none}}@media (width>=40rem){.sm\:sticky{position:sticky}.sm\:-mb-4{margin-bottom:calc(var(--spacing) * -4)}.sm\:contents{display:contents}.sm\:grid{display:grid}.sm\:h-0{height:0}.sm\:justify-start{justify-content:flex-start}.sm\:gap-12{gap:calc(var(--spacing) * 12)}}@media (width>=48rem){.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}}@media (width>=64rem){.lg\:px-12{padding-inline:calc(var(--spacing) * 12)}}@media (width>=80rem){.xl\:full-width{width:calc(100vw - calc(2 * var(--full-width-margin,2rem)));max-width:none;margin-left:calc(-50vw + (var(--full-width-margin,2rem)));margin-right:calc(-50vw + (var(--full-width-margin,2rem)));position:relative;left:50%;right:50%}.xl\:max-w-384{max-width:calc(var(--spacing) * 384)}.xl\:flex-row{flex-direction:row}.xl\:items-start{align-items:flex-start}.xl\:justify-center{justify-content:center}}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial}}}@layer theme{:root,:host{--font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-500:oklch(63.7% .237 25.331);--color-red-800:oklch(44.4% .177 26.899);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-light:300;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--leading-normal:1.5;--ease-in-out:cubic-bezier(.4, 0, .2, 1);--aspect-video:16 / 9;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-ice-50:oklch(97.4% .02 247.89);--color-ice-100:oklch(95% .022 238.64);--color-ice-200:oklch(87.6% .046 233.06);--color-ice-300:oklch(81.6% .078 224.93);--color-ice-400:oklch(72.8% .078 228.47);--color-ice-600:oklch(54% .064 238.76);--color-ice-700:oklch(45.4% .057 244.01);--color-ice-800:oklch(36.2% .049 247.19);--color-ice-950:oklch(22.5% .038 257.16);--color-dawn-50:oklch(95.8% .023 48.5);--color-dawn-100:oklch(92.6% .041 46.7);--color-dawn-200:oklch(85.2% .086 44);--color-dawn-300:oklch(78% .136 43.7);--color-dawn-600:oklch(54.9% .194 34.66);--color-dawn-700:oklch(47.2% .193 29.23);--color-dawn-900:oklch(31.1% .098 40.03);--color-night-50:oklch(96.6% .016 278.57);--color-night-100:oklch(92.5% .037 280.64);--color-night-400:oklch(71.7% .154 285.62);--color-night-700:oklch(52.5% .293 292.3);--color-night-800:oklch(40.1% .23 287.69);--color-night-900:oklch(27.1% .162 282.12);--color-night-950:oklch(21.4% .135 274.82);--spacing-prose:min(100%, 48rem)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}body{--tw-gradient-position:to top}@supports (background-image:linear-gradient(in lab, red, red)){body{--tw-gradient-position:to top in oklab}}body{background-image:linear-gradient(var(--tw-gradient-stops));--tw-gradient-from:#ffede40d}@supports (color:color-mix(in lab, red, red)){body{--tw-gradient-from:color-mix(in oklab, var(--color-dawn-50) 5%, transparent)}}body{--tw-gradient-via:#9c93ff0d}@supports (color:color-mix(in lab, red, red)){body{--tw-gradient-via:color-mix(in oklab, var(--color-night-400) 5%, transparent)}}body{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops);--tw-gradient-to:#4a74900d}@supports (color:color-mix(in lab, red, red)){body{--tw-gradient-to:color-mix(in oklab, var(--color-ice-600) 5%, transparent)}}body{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position));padding-bottom:calc(var(--spacing) * 32)}p{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}label{gap:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);flex-direction:column;display:flex}.help-text{max-width:calc(var(--spacing) * 128);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal);color:var(--color-gray-500)}input,select{max-width:calc(var(--spacing) * 120);border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-night-100);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 2);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal);flex-grow:1}[contenteditable]{max-width:calc(var(--spacing) * 120)}button:where(:not(.unstyled)){--tw-translate-x:0px;--tw-translate-y:0px;width:max-content;translate:var(--tw-translate-x) var(--tw-translate-y);cursor:pointer;align-items:center;gap:calc(var(--spacing) * 2);border-bottom-style:var(--tw-border-style);border-color:#2840561a;border-bottom-width:4px;display:flex}@supports (color:color-mix(in lab, red, red)){button:where(:not(.unstyled)){border-color:color-mix(in oklab, var(--color-ice-800) 10%, transparent)}}button:where(:not(.unstyled)){background-color:var(--color-ice-100);padding-inline:calc(var(--spacing) * 4);padding-top:calc(var(--spacing) * 1.5);padding-bottom:var(--spacing);font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-ice-950)}button:where(:not(.unstyled)):hover,button:where(:not(.unstyled)):active{background-color:var(--color-ice-50);color:var(--color-black)}button:where(:not(.unstyled)):active{--tw-translate-y:var(--spacing);translate:var(--tw-translate-x) var(--tw-translate-y);clip-path:inset(0 0 .25rem)}button:where(:not(.unstyled)).sm{gap:var(--spacing);padding-inline:calc(var(--spacing) * 3);padding-top:var(--spacing);padding-bottom:calc(var(--spacing) * .75);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}button:where(:not(.unstyled)).emph{border-color:#00000040}@supports (color:color-mix(in lab, red, red)){button:where(:not(.unstyled)).emph{border-color:color-mix(in oklab, var(--color-black) 25%, transparent)}}button:where(:not(.unstyled)).emph{background-color:var(--color-night-700);color:var(--color-white)}button:where(:not(.unstyled)).ghost{border-style:var(--tw-border-style);padding-block:calc(var(--spacing) * 2);color:var(--color-night-800);background-color:#0000;border-width:0}@media (hover:hover){button:where(:not(.unstyled)).ghost:hover{color:var(--color-night-900);--tw-backdrop-brightness:brightness(95%);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}}button:where(:not(.unstyled)).ghost:active{translate:none}button:where(:not(.unstyled)).ghost{clip-path:none}button:where(:not(.unstyled)).ghost.sm{padding-block:var(--spacing)}[contenteditable=true]{width:var(--spacing-prose);cursor:text;border-left-style:var(--tw-border-style);--tw-border-style:dashed;border-style:dashed;border-left-width:1px;border-color:var(--color-gray-500);padding-left:calc(var(--spacing) * 3)}[contenteditable][placeholder]:empty:after{color:var(--color-gray-500);content:attr(placeholder);display:inline}#skadi-dashboard{width:calc(var(--spacing) * 256);max-width:100%;padding-inline:calc(var(--spacing) * 4);margin-inline:auto}nav{align-items:flex-start;gap:calc(var(--spacing) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:3px;border-color:var(--color-night-700);width:100%;display:flex}nav>button{margin-bottom:calc(var(--spacing) * -.5);white-space:nowrap;border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3);padding-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);text-overflow:ellipsis;background-color:#0000;border-width:0;flex-shrink:1;display:block;overflow:hidden}nav>button:active{--tw-translate-x:0px;--tw-translate-y:0px;translate:var(--tw-translate-x) var(--tw-translate-y);clip-path:none}nav>button.selected{background-color:var(--color-night-700);padding-inline:calc(var(--spacing) * 4);--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--color-white);flex-shrink:0}nav>button:hover{background-color:var(--color-night-700);color:var(--color-white);flex-shrink:0}nav>button:active{background-color:var(--color-night-700);color:var(--color-night-50)}table{min-width:100%}table td,table th{border-style:var(--tw-border-style);border-width:1px;border-color:var(--color-night-100);padding-block:var(--spacing);padding-right:calc(var(--spacing) * 4);padding-left:calc(var(--spacing) * 2);text-align:left}table th{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}table tr:hover td{background-color:#f1f3ff66}@supports (color:color-mix(in lab, red, red)){table tr:hover td{background-color:color-mix(in oklab, var(--color-night-50) 40%, transparent)}}.pill{background-color:#f1f3ff80}@supports (color:color-mix(in lab, red, red)){.pill{background-color:color-mix(in oklab, var(--color-night-50) 50%, transparent)}}.pill{padding-inline:calc(var(--spacing) * 1.5);padding-block:calc(var(--spacing) * .5)}}@layer components;@layer utilities{.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.top-0{top:0}.top-1\/2{top:50%}.top-18{top:calc(var(--spacing) * 18)}.-right-4\.75{right:calc(var(--spacing) * -4.75)}.right-2{right:calc(var(--spacing) * 2)}.right-6{right:calc(var(--spacing) * 6)}.bottom-2{bottom:calc(var(--spacing) * 2)}.-left-5{left:calc(var(--spacing) * -5)}.left-0\.75{left:calc(var(--spacing) * .75)}.left-1\/2{left:50%}.left-auto{left:auto}.z-10{z-index:10}.col-span-2{grid-column:span 2/span 2}.col-span-4{grid-column:span 4/span 4}.mx-auto{margin-inline:auto}.my-1{margin-block:var(--spacing)}.-mt-1{margin-top:calc(var(--spacing) * -1)}.-mt-2{margin-top:calc(var(--spacing) * -2)}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mt-px{margin-top:1px}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-1{margin-left:var(--spacing)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-auto{margin-left:auto}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.table{display:table}.aspect-video{aspect-ratio:var(--aspect-video)}.size-4\.5{width:calc(var(--spacing) * 4.5);height:calc(var(--spacing) * 4.5)}.h-6{height:calc(var(--spacing) * 6)}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-13{width:calc(var(--spacing) * 13)}.w-full{width:100%}.w-max{width:max-content}.max-w-160{max-width:calc(var(--spacing) * 160)}.max-w-256{max-width:calc(var(--spacing) * 256)}.max-w-full{max-width:100%}.min-w-0{min-width:0}.flex-1{flex:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-full{flex-basis:100%}.-translate-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-x-6\.5{--tw-translate-x:calc(var(--spacing) * -6.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-3\.25{--tw-translate-x:calc(var(--spacing) * 3.25);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-6\.5{--tw-translate-x:calc(var(--spacing) * 6.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.cursor-pointer{cursor:pointer}.grid-flow-col{grid-auto-flow:column}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[auto_4rem_1fr_auto\]{grid-template-columns:auto 4rem 1fr auto}.grid-rows-\[0fr\]{grid-template-rows:0fr}.grid-rows-\[1fr\]{grid-template-rows:1fr}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:var(--spacing)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}.gap-y-4{row-gap:calc(var(--spacing) * 4)}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded-full{border-radius:2147483647px}.border{border-style:var(--tw-border-style);border-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-black\/20{border-color:#0003}@supports (color:color-mix(in lab, red, red)){.border-black\/20{border-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.border-dawn-200{border-color:var(--color-dawn-200)}.border-dawn-600{border-color:var(--color-dawn-600)}.border-gray-600{border-color:var(--color-gray-600)}.border-ice-100{border-color:var(--color-ice-100)}.border-ice-200{border-color:var(--color-ice-200)}.border-ice-400{border-color:var(--color-ice-400)}.border-ice-600{border-color:var(--color-ice-600)}.border-ice-700{border-color:var(--color-ice-700)}.border-night-50{border-color:var(--color-night-50)}.border-night-100{border-color:var(--color-night-100)}.border-night-700{border-color:var(--color-night-700)}.border-red-500{border-color:var(--color-red-500)}.border-red-800{border-color:var(--color-red-800)}.bg-dawn-50{background-color:var(--color-dawn-50)}.bg-dawn-100{background-color:var(--color-dawn-100)}.bg-dawn-300{background-color:var(--color-dawn-300)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-50\/50{background-color:#f9fafb80}@supports (color:color-mix(in lab, red, red)){.bg-gray-50\/50{background-color:color-mix(in oklab, var(--color-gray-50) 50%, transparent)}}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-600{background-color:var(--color-gray-600)}.bg-ice-50{background-color:var(--color-ice-50)}.bg-ice-50\/50{background-color:#eff8ff80}@supports (color:color-mix(in lab, red, red)){.bg-ice-50\/50{background-color:color-mix(in oklab, var(--color-ice-50) 50%, transparent)}}.bg-ice-300{background-color:var(--color-ice-300)}.bg-ice-600{background-color:var(--color-ice-600)}.bg-night-700{background-color:var(--color-night-700)}.bg-red-50\/50{background-color:#fef2f280}@supports (color:color-mix(in lab, red, red)){.bg-red-50\/50{background-color:color-mix(in oklab, var(--color-red-50) 50%, transparent)}}.bg-white{background-color:var(--color-white)}.fill-current{fill:currentColor}.p-1{padding:var(--spacing)}.p-2{padding:calc(var(--spacing) * 2)}.p-4{padding:calc(var(--spacing) * 4)}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-8{padding-block:calc(var(--spacing) * 8)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pr-0\.5{padding-right:calc(var(--spacing) * .5)}.pr-1{padding-right:var(--spacing)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[0\.625rem\]{font-size:.625rem}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.whitespace-pre-wrap{white-space:pre-wrap}.text-dawn-700{color:var(--color-dawn-700)}.text-dawn-900\/65{color:#571900a6}@supports (color:color-mix(in lab, red, red)){.text-dawn-900\/65{color:color-mix(in oklab, var(--color-dawn-900) 65%, transparent)}}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-ice-600{color:var(--color-ice-600)}.text-ice-700{color:var(--color-ice-700)}.text-ice-800{color:var(--color-ice-800)}.text-night-700{color:var(--color-night-700)}.text-night-800{color:var(--color-night-800)}.text-night-950{color:var(--color-night-950)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.opacity-25{opacity:.25}.shadow-inner{--tw-shadow:inset 0 2px 4px 0 var(--tw-shadow-color,#0000000d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-\[grid-template-rows\]{transition-property:grid-template-rows;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}@media (hover:hover){.group-hover\:text-black:is(:where(.group):hover *){color:var(--color-black)}.group-hover\:text-night-800:is(:where(.group):hover *){color:var(--color-night-800)}}.only\:col-span-2:only-child{grid-column:span 2/span 2}@media (hover:hover){.hover\:border-night-700:hover{border-color:var(--color-night-700)}.hover\:bg-night-50:hover{background-color:var(--color-night-50)}.hover\:bg-transparent:hover{background-color:#0000}.hover\:text-black:hover{color:var(--color-black)}.hover\:backdrop-filter-none:hover{-webkit-backdrop-filter:none;backdrop-filter:none}}@media (width>=40rem){.sm\:sticky{position:sticky}.sm\:-mb-4{margin-bottom:calc(var(--spacing) * -4)}.sm\:contents{display:contents}.sm\:grid{display:grid}.sm\:h-0{height:0}.sm\:justify-start{justify-content:flex-start}.sm\:gap-12{gap:calc(var(--spacing) * 12)}}@media (width>=48rem){.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}}@media (width>=64rem){.lg\:px-12{padding-inline:calc(var(--spacing) * 12)}}@media (width>=80rem){.xl\:full-width{width:calc(100vw - calc(2 * var(--full-width-margin,2rem)));max-width:none;margin-left:calc(-50vw + (var(--full-width-margin,2rem)));margin-right:calc(-50vw + (var(--full-width-margin,2rem)));position:relative;left:50%;right:50%}.xl\:max-w-384{max-width:calc(var(--spacing) * 384)}.xl\:flex-row{flex-direction:row}.xl\:items-start{align-items:flex-start}.xl\:justify-center{justify-content:center}}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}
@@ -27,7 +27,7 @@ var e=Array.isArray,t=Array.prototype.indexOf,n=Array.prototype.includes,r=Array
27
27
  absolute inset-0 left-auto p-2
28
28
  text-night-800 hover:text-black hover:bg-night-50
29
29
  cursor-pointer
30
- "><!></button>`),ua=U(`<p> </p>`),da=U(`<div class="relative w-max"><input type="date"/> <!></div>`),fa=U(`<div class="relative w-max"><input type="number"/> <!></div>`),pa=U(`<option> </option>`),ma=U(`<!>`,1),ha=U(`<select><!></select>`),ga=U(`<div class="flex items-center gap-2 font-normal"> <!> </div>`),_a=U(`<div class="relative flex"><input type="text"/> <!></div>`),va=U(`<textarea></textarea>`),ya=U(`<span class="help-text mb-1"> </span>`),ba=U(`<label><!> <!> <!></label>`);function xa(e,t){qe(t,!0);let n=e=>{var t=Kr(),n=I(t),r=e=>{var t=la();aa(F(t),{name:`clear`}),A(t),H(`click`,t,E),W(e,t)};K(n,e=>{V(_)&&e(r)}),W(e,t)},r=ta(t,`type`,3,`text`),i=ta(t,`model`,7),a=ta(t,`description`,3,null),o=ta(t,`selectOptions`,3,null),s=ta(t,`leftValue`,3,null),c=ta(t,`rightValue`,3,null),l=ta(t,`switchIndeterminate`,3,!1),u=ta(t,`allowEmpty`,3,!1),f=ta(t,`showClear`,3,!0),p=ta(t,`trimOnBlur`,3,!1),m=ta(t,`class`,3,``),h=ea(t,ca),g=j(()=>l()&&i()[t.key]!==c()&&i()[t.key]!==s()?null:i()[t.key]===c()||c()===null&&i()[t.key]===void 0),_=j(()=>f()&&i()[t.key]),v=j(()=>[`date`,`number`,`text`,`textarea`,`contenteditable`].includes(r())?1e3:250),y,b=null,x=()=>{b!==null&&b!==``||u()?i()[t.key]=b:delete i()[t.key]},S=e=>{if(r()===`contenteditable`)b=e.currentTarget.innerText;else if(r()===`number`){let t=e.currentTarget.value.trim();b=t.match(/^-?\d*\.?\d+$/)?Number.parseFloat(t):null}else b=e.currentTarget.value;y&&clearTimeout(y),y=setTimeout(x,V(v))},C=()=>{V(g)?s()===null?delete i()[t.key]:i()[t.key]=s():V(g)===null?i()[t.key]=c():l()||c()===null?delete i()[t.key]:i()[t.key]=c()},w=()=>{y&&(clearTimeout(y),x()),p()&&typeof i()[t.key]==`string`&&(i()[t.key]=i()[t.key].trim())},T=(e,t)=>(e.innerText=t??``,{update(t){document.activeElement!==e&&(e.innerText=t??``)}}),E=()=>{y&&clearTimeout(y),(r()===`text`||r()===`string`)&&u()?i()[t.key]=``:delete i()[t.key]};var D=ba(),ee=F(D);li(ee,()=>t.children);var te=L(ee,2),ne=e=>{var n=ua();Vi(n,()=>({contenteditable:!0,onblur:w,oninput:S,class:`mt-1 whitespace-pre-wrap`,...h}));var r=F(n,!0);A(n),ui(n,(e,t)=>T?.(e,t),()=>i()[t.key]),R(()=>G(r,i()[t.key])),W(e,n)},re=e=>{var r=da(),a=F(r);Fi(a);var o=L(a,2);n(o),A(r),R(()=>{Ii(a,i()[t.key]),bi(a,1,`w-max ${V(_)?`pr-8`:``}`)}),Fr(`blur`,a,w),H(`input`,a,S),W(e,r)},ie=e=>{var r=fa(),a=F(r);Fi(a);var o=L(a,2);n(o),A(r),R(()=>{Ii(a,i()[t.key]),bi(a,1,V(_)?`pr-8`:``)}),Fr(`blur`,a,w),H(`input`,a,S),W(e,r)},ae=e=>{var n=ha();qi(n,()=>{var e=F(n),t=ma(),r=I(t),i=e=>{var t=Kr();q(I(t),17,o,ei,(e,t)=>{var n=Kr(),r=I(n),i=e=>{var n=pa(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t)),i!==(i=V(t))&&(n.__value=V(t))}),W(e,n)},a=e=>{var n=pa(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t).label??V(t).value),i!==(i=V(t).value)&&(n.value=(n.__value=V(t).value)??``)}),W(e,n)};K(r,e=>{typeof V(t)==`string`?e(i):e(a,-1)}),W(e,n)}),W(e,t)},a=j(()=>Array.isArray(o())),s=e=>{var t=Kr();li(I(t),()=>o()??d),W(e,t)};K(r,e=>{V(a)?e(i):e(s,-1)}),W(e,t)});var r;wi(n),R(()=>{r!==(r=i()[t.key]??``)&&(n.value=(n.__value=i()[t.key]??``)??``,Ci(n,i()[t.key]??``))}),Fr(`blur`,n,w),H(`input`,n,S),W(e,n)},oe=e=>{var n=ga(),r=F(n),i=L(r);{let e=j(()=>t.leftLabel?``:void 0),n=j(()=>t.rightLabel?``:void 0);sa(i,{get value(){return V(g)},onToggle:C,get labelOff(){return V(e)},get labelOn(){return V(n)}})}var a=L(i);A(n),R(()=>{G(r,`${t.leftLabel??``} `),G(a,` ${t.rightLabel??``}`)}),W(e,n)},se=e=>{var r=_a(),a=F(r);Fi(a);var o=L(a,2);n(o),A(r),R(()=>{Ii(a,i()[t.key]),bi(a,1,`grow ${V(_)?`pr-8`:``}`)}),Fr(`blur`,a,w),H(`input`,a,S),W(e,r)},ce=e=>{var n=va();ut(n),Vi(n,()=>({onblur:w,oninput:S,...h,value:i()[t.key]})),W(e,n)};K(te,e=>{r()===`contenteditable`?e(ne):r()===`date`?e(re,1):r()===`number`?e(ie,2):r()===`select`?e(ae,3):r()===`switch`?e(oe,4):r()===`string`||r()===`text`?e(se,5):r()===`textarea`&&e(ce,6)});var le=L(te,2),ue=e=>{var t=ya(),n=F(t,!0);A(t),R(()=>G(n,a())),W(e,t)},de=e=>{var t=Kr();li(I(t),()=>a()??d),W(e,t)};K(le,e=>{typeof a()==`string`?e(ue):e(de,-1)}),A(D),R(()=>bi(D,1,mi(m()))),W(e,D),Je()}Ir([`click`,`input`]);var Sa=U(`<div><button type="button" class="group w-full flex items-center unstyled cursor-pointer py-0.5"><!> <!></button> <div class="contents"><div><div class="flex flex-col gap-3 px-0.5 pb-2 mt-2 overflow-hidden"><!></div></div></div></div>`);function Ca(e,t){qe(t,!0);let n=ta(t,`startOpen`,3,!1),r=ta(t,`wrapperClass`,3,`border-night-700`),i=N(on(br(()=>n())));function a(){P(i,!1)}let o=()=>{P(i,!V(i))};var s={close:a},c=Sa(),l=F(c),u=F(l);li(u,()=>t.title,()=>V(i));var d=L(u,2);{let e=j(()=>V(i)?`chevron_up`:`chevron_down`);aa(d,{get name(){return V(e)},size:24,class:`text-ice-800 group-hover:text-black ml-auto`})}A(l);var f=L(l,2),p=F(f),m=F(p);return li(F(m),()=>t.children),A(m),A(p),A(f),A(c),R(()=>{bi(c,1,`border-l-4 ${r()??``} pl-4 py-0.5`),bi(p,1,`grid transition-[grid-template-rows] ease-in-out overflow-hidden ${V(i)?`grid-rows-[1fr]`:`grid-rows-[0fr]`}`)}),H(`click`,l,o),W(e,c),Je(s)}Ir([`click`]);var wa=JSON.parse(document.querySelector(`[data-dashboard-config]`)?.dataset?.datasetSchema),Ta=e=>e.replace(/_/g,` `).replace(/^[a-z]/,e=>e.toLocaleUpperCase()).replace(/\bSql\b/g,`SQL`).replace(/\bUtm\b/g,`UTM`),Ea={"01":`January`,"02":`February`,"03":`March`,"04":`April`,"05":`May`,"06":`June`,"07":`July`,"08":`August`,"09":`September`,10:`October`,11:`November`,12:`December`},Da={"01":`Jan`,"02":`Feb`,"03":`Mar`,"04":`Apr`,"05":`May`,"06":`Jun`,"07":`Jul`,"08":`Aug`,"09":`Sep`,10:`Oct`,11:`Nov`,12:`Dec`},Oa=(e,t)=>{if(typeof e!=`string`||!e.match(/^\d{4}-\d{2}-\d{2}/))return`${e}`;let[n,r,i]=e.substring(0,10).split(`-`,3);if(!n||!r||!i)return e;switch(t){case`month`:return`${Ea[r]} ${n}`;case`week`:return`w/c ${+i} ${Da[r]} ${n.substring(2,4)}`;case`day`:return`${+i} ${Da[r]} ${n.substring(2,4)}`}},ka=e=>e.type===`percentage`,Aa=e=>e.type===`sql`,ja=e=>!ka(e)&&!Aa(e),Ma=e=>e.operator===`empty`||e.operator===`not empty`,Na={boolean:!0,date:new Date().toISOString().substring(0,10),number:0,one_of:``,string:``},Pa=e=>{if(e.type===`one_of`&&e.options){let t=e.options[0];return typeof t==`string`?t:t?.value??``}return Na[e.type??`string`]},Fa=(e,t)=>{if(!t.includes(`.`))return{datasetType:e.type,targetSchema:wa[e.type],field:t,fieldSchema:wa[e.type]?.fields?.[t]};let[n,r]=t.split(`.`,2);return{datasetType:n,targetSchema:wa[n],field:r,fieldSchema:wa[n]?.fields?.[r],association:`belongs_to`}},Ia=(e,t)=>{if(!e?.fields?.[t.field]?.filter)return!1;let n=e.fields[t.field];if(!n||!Ba(n).includes(t.operator))return!1;if(Ma(t))return!(`value`in t);let r=n.type??`string`;switch(r){case`one_of`:return n.options?.some(e=>typeof e==`string`?e===t.value:e.value===t.value);case`date`:return typeof t.value==`string`&&t.value.match(/^\d{4}-[01]\d-[0-3]\d$/);default:return typeof t.value===r}},La=e=>wa[e]?.label??Ta(e),Ra=(e,t)=>wa[t??``]?.fields?.[e]?.label??Ta(e),za={boolean:[`=`,`!=`,`empty`,`not empty`],date:[`=`,`!=`,`>`,`>=`,`<=`,`<`,`empty`,`not empty`],number:[`=`,`!=`,`>`,`>=`,`<=`,`<`,`empty`,`not empty`],one_of:[`=`,`!=`,`empty`,`not empty`],string:[`=`,`!=`,`like`,`not like`,`empty`,`not empty`]},Ba=e=>za[e?.type??`string`],Va=(e,t)=>{let n=wa[e];return t===e||n?.counts?.[t]||n?.belongs_to?.includes(t)?e:n?.belongs_to?.find(e=>!!wa[e]?.counts?.[t])},Ha=U(`<option> </option>`),Ua=U(`<span class="sr-only"> </span>`),Wa=U(`<p class="help-text -mt-1 mb-1 col-span-4"> </p>`),Ga=U(`<span> </span> <label><span class="sr-only">operator</span> <select></select></label> <!> <button type="button" class="unstyled text-night-800 hover:text-black hover:bg-night-50 p-2 cursor-pointer"><!></button> <!>`,1);function Ka(e,t){qe(t,!0);let n=j(()=>wa[t.datasetType]?.fields?.[t.filter.field]),r=(e,r)=>{if(!t.dataset.filters)return;let i=r.currentTarget.value,a=t.dataset.filters[e],o=Ma(a);a.operator=i,Ma(a)?delete a.value:(o||a.value===void 0)&&(a.value=V(n)?Pa(V(n)):``)};var i=Ga(),a=I(i),o=F(a);A(a);var s=L(a,2),c=L(F(s),2);q(c,21,()=>Ba(V(n)),ei,(e,t)=>{var n=Ha(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t)),i!==(i=V(t))&&(n.__value=V(t))}),W(e,n)}),A(c);var l;wi(c),A(s);var u=L(s,2),d=e=>{var r=Kr(),i=I(r),a=e=>{{let r=j(()=>V(n).leftValue!==void 0&&V(n).leftValue),i=j(()=>V(n).rightValue===void 0||V(n).rightValue);xa(e,{type:`switch`,get model(){return t.filter},get leftLabel(){return V(n).leftLabel},get leftValue(){return V(r)},get rightLabel(){return V(n).rightLabel},get rightValue(){return V(i)},key:`value`,class:`ml-1`,children:(e,n)=>{var r=Ua(),i=F(r);A(r),R(e=>G(i,`${e??``} value`),[()=>Ra(t.filter.field,t.datasetType)]),W(e,r)},$$slots:{default:!0}})}},o=e=>{xa(e,{type:`select`,get model(){return t.filter},key:`value`,get selectOptions(){return V(n).options},class:`w-max`,allowEmpty:!0,children:(e,n)=>{var r=Ua(),i=F(r);A(r),R(e=>G(i,`${e??``} value`),[()=>Ra(t.filter.field,t.datasetType)]),W(e,r)},$$slots:{default:!0}})},s=e=>{{let r=j(()=>V(n)?.type??`string`),i=j(()=>!V(n)?.type||V(n)?.type===`string`);xa(e,{get type(){return V(r)},get model(){return t.filter},key:`value`,class:`w-full`,allowEmpty:!0,get showClear(){return V(i)},children:(e,n)=>{var r=Ua(),i=F(r);A(r),R(e=>G(i,`${e??``} value`),[()=>Ra(t.filter.field,t.datasetType)]),W(e,r)},$$slots:{default:!0}})}};K(i,e=>{V(n)?.type===`boolean`?e(a):V(n)?.type===`one_of`?e(o,1):e(s,-1)}),W(e,r)},f=j(()=>!Ma(t.filter));K(u,e=>{V(f)&&e(d)});var p=L(u,2);aa(F(p),{name:`delete`}),A(p);var m=L(p,2),h=e=>{var t=Wa(),r=F(t,!0);A(t),R(()=>G(r,V(n).description)),W(e,t)};K(m,e=>{V(n)?.description&&e(h)}),R((e,n)=>{G(o,`${e??``}:`),bi(s,1,`h-full ${n??``}`),l!==(l=t.filter.operator)&&(c.value=(c.__value=t.filter.operator)??``,Ci(c,t.filter.operator))},[()=>Ra(t.filter.field,t.datasetType),()=>Ma(t.filter)?`col-span-2 w-max`:``]),H(`change`,c,e=>r(t.index,e)),H(`click`,p,function(...e){t.removeFilter?.apply(this,e)}),W(e,i),Je()}Ir([`change`,`click`]);var qa=U(`<p class="text-sm font-medium text-ice-600 mt-2 col-span-4"> </p> <!>`,1),Ja=U(`<div class="grid grid-cols-[auto_4rem_1fr_auto] gap-1 items-center"><!> <!></div>`),Ya=U(`<option> </option>`),Xa=U(`<div class="border-l-2 border-ice-700 pl-4 mt-4 py-0.5 flex flex-col gap-3"><p class="text-sm font-medium text-ice-700">Filters</p> <!> <label><span class="sr-only">Add a filter</span> <select class="text-gray-600"><option selected="">Add a filter</option><!></select></label></div>`);function Za(e,t){qe(t,!0);let n=ta(t,`dataset`,7),r=e=>{if(!ja(n()))return;let{field:t,datasetType:r,fieldSchema:i,association:a}=Fa(n(),e.currentTarget.value),o=n();a===`belongs_to`&&(n().belongs_to??={},n().belongs_to[r]??={},o=n().belongs_to[r]),i&&(o.filters??=[],o.filters.push({field:t,operator:`=`,value:Pa(i)}),e.currentTarget.value=``)},i=(e,r)=>{if(!ja(n()))return;let i=n();if(r!==null){if(!n().belongs_to?.[r])return;i=n().belongs_to[r]}Array.isArray(i.filters)&&(i.filters.length===1?(delete i.filters,r!==null&&t.pruneBelongsTo()):i.filters.splice(e,1))};var a=Xa(),o=L(F(a),2),s=e=>{var t=Ja(),r=F(t);q(r,17,()=>n().filters??[],ei,(e,t,r)=>{Ka(e,{get dataset(){return n()},get datasetType(){return n().type},get filter(){return V(t)},index:r,removeFilter:()=>i(r,null)})});var a=L(r,2),o=e=>{var t=Kr();q(I(t),17,()=>Object.entries(n().belongs_to),([e,t])=>e,(e,t)=>{var n=j(()=>h(V(t),2));let r=()=>V(n)[0],a=()=>V(n)[1];var o=Kr(),s=I(o),c=e=>{var t=qa(),n=I(t),o=F(n,!0);A(n),q(L(n,2),17,()=>a().filters,ei,(e,t,n)=>{Ka(e,{get dataset(){return a()},get datasetType(){return r()},get filter(){return V(t)},index:n,removeFilter:()=>i(n,r())})}),R(e=>G(o,e),[()=>La(r())]),W(e,t)};K(s,e=>{a().filters?.length&&e(c)}),W(e,o)}),W(e,t)};K(a,e=>{n().belongs_to&&e(o)}),A(t),W(e,t)},c=j(()=>Array.isArray(n().filters));K(o,e=>{V(c)&&e(s)});var l=L(o,2),u=L(F(l),2),d=F(u);d.value=d.__value=``,q(L(d),17,()=>t.filterFields,ei,(e,t)=>{var n=Ya(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t).label),i!==(i=V(t).value)&&(n.value=(n.__value=V(t).value)??``)}),W(e,n)}),A(u),A(l),A(a),R(()=>bi(l,1,n().filters?.length?`mt-4`:``)),H(`change`,u,r),W(e,a),Je()}Ir([`change`]);var Qa=U(`<div class="flex items-center gap-1 pill pr-0.5"><div class="font-medium"><!> </div> <button type="button" class="unstyled text-night-800 hover:text-black hover:bg-night-50 p-1 cursor-pointer"><!></button></div>`),$a=U(`<div class="flex flex-wrap gap-2"></div>`),eo=U(`<option> </option>`),to=U(`<div class="border-l-2 border-ice-700 pl-4 mt-4 py-0.5 flex flex-col gap-3"><p class="text-sm font-medium text-ice-700">Selected fields</p> <p class="text-xs text-grey-600">If no fields are selected, all fields in the dataset will be returned</p> <!> <label><span class="sr-only">Add a select</span> <select class="text-gray-600"><option selected="">Add a select</option><!></select></label></div>`);function no(e,t){qe(t,!0);let n=ta(t,`dataset`,7),r=e=>{if(!ja(n()))return;let t=e.currentTarget.value;n().selects??=[],n().selects.push(t);let{datasetType:r,association:i}=Fa(n(),t);i===`belongs_to`&&(n().belongs_to??={},n().belongs_to[r]??={}),e.currentTarget.value=``},i=e=>{if(!(!ja(n())||!Array.isArray(n().selects))){if(n().selects.length===1)delete n().selects;else{let t=n().selects.indexOf(e);n().selects.splice(t,1)}e.includes(`.`)&&t.pruneBelongsTo()}};var a=to(),o=L(F(a),4),s=e=>{var t=$a();q(t,21,()=>n().selects,ei,(e,t)=>{let r=j(()=>{let{association:e,field:r,fieldSchema:i,datasetType:a}=Fa(n(),V(t));return{association:e,field:r,fieldSchema:i,datasetType:a}});var a=Qa(),o=F(a),s=F(o),c=e=>{var t=Gr();R(e=>G(t,`${e??``}:`),[()=>La(V(r).datasetType)]),W(e,t)};K(s,e=>{V(r).association===`belongs_to`&&e(c)});var l=L(s);A(o);var u=L(o,2);aa(F(u),{size:`16`,name:`delete`}),A(u),A(a),R(e=>G(l,` ${e??``}`),[()=>V(r).fieldSchema?.label??Ta(V(r).field)]),H(`click`,u,()=>i(V(t))),W(e,a)}),A(t),W(e,t)},c=j(()=>Array.isArray(n().selects));K(o,e=>{V(c)&&e(s)});var l=L(o,2),u=L(F(l),2),d=F(u);d.value=d.__value=``,q(L(d),17,()=>t.selectFields,ei,(e,t)=>{var r=Kr(),i=I(r),a=e=>{var n=eo(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t).label),i!==(i=V(t).value)&&(n.value=(n.__value=V(t).value)??``)}),W(e,n)},o=j(()=>!Array.isArray(n().selects)||!n().selects.includes(V(t).value));K(i,e=>{V(o)&&e(a)}),W(e,r)}),A(u),A(l),A(a),H(`change`,u,r),W(e,a),Je()}Ir([`click`,`change`]);var ro=U(`<div class="flex items-center gap-1 pill pr-0.5"><div class="font-medium"> </div> <button type="button" class="unstyled text-night-800 hover:text-black hover:bg-night-50 p-1 cursor-pointer"><!></button></div>`),io=U(`<div class="flex flex-wrap gap-2"></div>`),ao=U(`<p class="text-sm font-medium text-ice-600"> </p> <div class="flex flex-wrap gap-2 -mt-2"></div>`,1),oo=U(`<option> </option>`),so=U(`<div class="border-l-2 border-ice-700 pl-4 mt-4 py-0.5 flex flex-col gap-3"><p class="text-sm font-medium text-ice-700">Splits</p> <p class="-mt-2 text-xs text-grey-600">Shows a separate chart series for each unique value of the given fields</p> <!> <!> <label><span class="sr-only">Add a split</span> <select class="text-gray-600"><option selected="">Add a split</option><!></select></label></div>`);function co(e,t){qe(t,!0);let n=ta(t,`dataset`,7),r=e=>{if(!ja(n()))return;let{datasetType:t,field:r,association:i}=Fa(n(),e.currentTarget.value),a;i===`belongs_to`?(n().belongs_to??={},n().belongs_to[t]??={},a=n().belongs_to[t]):a=n(),a&&(a.split_by??=[],a.split_by.push(r),e.currentTarget.value=``)},i=(e,r)=>{if(!ja(n()))return;let i=n();if(r!==null){if(!n().belongs_to?.[r])return;i=n().belongs_to[r]}if(Array.isArray(i.split_by)){if(i.split_by.length===1)delete i.split_by,r!==null&&t.pruneBelongsTo();else{let t=i.split_by.indexOf(e);i.split_by.splice(t,1)}}};var a=so();{let e=(e,t=d,r)=>{let a=Et(()=>m(r?.(),null));var o=ro(),s=F(o),c=F(s,!0);A(s);var l=L(s,2);aa(F(l),{size:`16`,name:`delete`}),A(l),A(o),R(e=>G(c,e),[()=>Ra(t(),V(a)??n().type)]),H(`click`,l,()=>i(t(),V(a))),W(e,o)};var o=L(F(a),4),s=t=>{var r=io();q(r,21,()=>n().split_by,ei,(t,n)=>{e(t,()=>V(n))}),A(r),W(t,r)},c=j(()=>Array.isArray(n().split_by));K(o,e=>{V(c)&&e(s)});var l=L(o,2),u=t=>{var r=Kr();q(I(r),17,()=>Object.entries(n().belongs_to),([e,t])=>e,(t,n)=>{var r=j(()=>h(V(n),2));let i=()=>V(r)[0],a=()=>V(r)[1];var o=Kr(),s=I(o),c=t=>{var n=ao(),r=I(n),o=F(r,!0);A(r);var s=L(r,2);q(s,21,()=>a().split_by,ei,(t,n)=>{e(t,()=>V(n),i)}),A(s),R(e=>G(o,e),[()=>La(i())]),W(t,n)},l=j(()=>Array.isArray(a().split_by)&&a().split_by.length>0);K(s,e=>{V(l)&&e(c)}),W(t,o)}),W(t,r)};K(l,e=>{n().belongs_to&&e(u)});var f=L(l,2),p=L(F(f),2),g=F(p);g.value=g.__value=``,q(L(g),17,()=>t.splitFields,ei,(e,t)=>{var r=Kr(),i=I(r),a=e=>{var n=oo(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t).label),i!==(i=V(t).value)&&(n.value=(n.__value=V(t).value)??``)}),W(e,n)},o=j(()=>!Array.isArray(n().split_by)||!n().split_by.includes(V(t).value));K(i,e=>{V(o)&&e(a)}),W(e,r)}),A(p),A(f),A(a),H(`change`,p,r)}W(e,a),Je()}Ir([`click`,`change`]);var lo=U(`<span class="capitalize"> </span> `,1),uo=U(`<p class="text-sm font-semibold text-night-700 group-hover:text-night-800"><!></p>`),fo=U(`<option> </option>`),po=U(`<label>Count by <select></select></label>`),mo=U(`<div class="sm:grid grid-cols-[auto_1fr] gap-4 sm:gap-12"><!> <!></div> <!>`,1),ho=U(`<!> <!>`,1),go=U(`<span class="help-text">Note: your query must return three columns: <code>date</code>, <code>split</code>, and <code>count</code>. <code>split</code> can be <code>NULL</code></span>`),_o=U(`<label><span class="text-sm font-medium"> </span> <span class="ml-3 text-gray-500 text-xs font-normal">required?</span> <!></label>`),vo=U(`<div class="mt-4 flex flex-wrap gap-y-2 gap-x-4"><p class="text-sm font-medium text-ice-700 mb-0.5 basis-full">Linked tables</p> <!></div>`),yo=U(`<button type="button" class="sm">Duplicate</button>`),bo=U(`<button type="button" class="sm px-1"><!></button>`),xo=U(`<button type="button" class="sm bg-dawn-100 ml-auto">Yes, delete this dataset</button>`),So=U(`<button type="button" class="sm bg-dawn-100 ml-auto">Delete</button>`),Co=U(`<label>Label <input type="text"/> <span class="help-text">Splits can be incorporated into the label using <code>%1</code>, <code>%2</code>, etc. or with a default value if empty using <code>%1(none)</code></span></label> <div class="sm:grid grid-cols-2 gap-x-2 gap-y-4"><label class="only:col-span-2">Type <select></select></label> <!></div> <!> <!> <div class="flex flex-row gap-2 mt-4"><!> <!> <!> <!></div>`,1);function wo(e,t){qe(t,!0);let n=ta(t,`dataset`,7),r=ta(t,`startOpen`,3,!1),i=j(()=>ka(n())?[``,...t.chartConfig.datasets.filter(e=>!(e.type===`percentage`||ja(e)&&e.split_by)).map(e=>({value:e.id,label:e.label}))]:[]),a=j(()=>[...Object.keys(wa),...t.chartConfig.type===`table`?[]:[`percentage`],`sql`]),o=j(()=>wa[n().type]),s=j(()=>{if(!V(o))return{filter:[],select:[],split:[]};let e=wa[n().type]?.fields??{},t=[],r=[],i=[];for(let[n,a]of Object.entries(e)){let e={label:a.label??Ta(n),value:n};a.filter&&t.push(e),a.select&&r.push(e),a.split&&i.push(e)}if(Array.isArray(V(o).belongs_to))for(let e of V(o).belongs_to){let n=wa[e];if(n?.fields)for(let[a,o]of Object.entries(n.fields)){let s={label:`${n.label??Ta(e)}: ${o.label??Ta(a)}`,value:`${e}.${a}`};o.filter&&t.push(s),o.select&&r.push(s),o.split&&i.push(s)}}return{filter:t,select:r,split:i}}),c=j(()=>{if(!ja(n())||t.chartConfig.type===`table`||!V(o))return[];let e=[{label:V(o).counts?.[n().type]?.label??Ta(n().type),value:n().type}];for(let[t,r]of Object.entries(V(o).counts??{}))t!==n().type&&e.push({label:r.label??Ta(t),value:t});if(Array.isArray(V(o).belongs_to))for(let t of V(o).belongs_to){let n=wa[t];e.push({label:n?.counts?.[t]?.label??Ta(t),value:t});for(let[r,i]of Object.entries(n?.counts??{}))r!==t&&e.push({label:i.label??Ta(r),value:r})}return e}),l=N(!1),u=e=>{let r=e.currentTarget.value;if(r===n().type||t.chartConfig.type===`table`&&n().type===`percentage`)return;let i=n().type;n().type=r;let a=[`id`,`type`,`label`,`visible`,`axis`];ja(n())&&(a.push(`filters`,`belongs_to`),t.chartConfig.type===`table`?a.push(`selects`):a.push(`count_by`,`split_by`));for(let e of Object.keys(n()))a.includes(e)||delete n()[e];if(ja(n())){if(Array.isArray(n().filters))for(let e=0;e<n().filters.length;e++)(!V(o)||!Ia(V(o),n().filters[e]))&&(n().filters.splice(e,1),e--);if(n().count_by&&(n().count_by===i?n().count_by=n().type:V(c).find(e=>e.value===n().count_by)||(n().count_by=n().type)),n().selects){for(let e=0;e<n().selects.length;e++){let t=n().selects[e];if(t.includes(`.`)){let[i,a]=t.split(`.`,2);if(i===r&&!n().selects.includes(a)){n().selects[e]=a;continue}if(i&&V(o)?.belongs_to?.includes(i))continue}else if(V(o)?.fields[t]?.select)continue;n().selects.splice(e,1),e--}n().selects.length===0&&delete n().selects}if(n().split_by){for(let e=0;e<n().split_by.length;e++){let t=n().split_by[e];V(o)?.fields[t]?.split||(n().split_by.splice(e,1),e--)}n().split_by.length===0&&delete n().split_by}if(n().belongs_to?.[r]){if(Array.isArray(n().belongs_to[r].filters)){n().filters??=[];for(let e of n().belongs_to[r].filters)n().filters.find(t=>t.field===e.field&&t.operator===e.operator&&t.value===e.value)||n().filters.push(e)}if(Array.isArray(n().belongs_to[r].split_by)){n().split_by??=[];for(let e of n().belongs_to[r].split_by)n().split_by.includes(e)||n().split_by.push(e)}delete n().belongs_to[r]}m()}Aa(n())&&(n().sql=`SELECT
30
+ "><!></button>`),ua=U(`<p> </p>`),da=U(`<div class="relative w-max"><input type="date"/> <!></div>`),fa=U(`<div class="relative w-max"><input type="number"/> <!></div>`),pa=U(`<option> </option>`),ma=U(`<!>`,1),ha=U(`<select><!></select>`),ga=U(`<div class="flex items-center gap-2 font-normal"> <!> </div>`),_a=U(`<div class="relative flex"><input type="text"/> <!></div>`),va=U(`<textarea></textarea>`),ya=U(`<span class="help-text mb-1"> </span>`),ba=U(`<label><!> <!> <!></label>`);function xa(e,t){qe(t,!0);let n=e=>{var t=Kr(),n=I(t),r=e=>{var t=la();aa(F(t),{name:`clear`}),A(t),H(`click`,t,E),W(e,t)};K(n,e=>{V(_)&&e(r)}),W(e,t)},r=ta(t,`type`,3,`text`),i=ta(t,`model`,7),a=ta(t,`description`,3,null),o=ta(t,`selectOptions`,3,null),s=ta(t,`leftValue`,3,null),c=ta(t,`rightValue`,3,null),l=ta(t,`switchIndeterminate`,3,!1),u=ta(t,`allowEmpty`,3,!1),f=ta(t,`showClear`,3,!0),p=ta(t,`trimOnBlur`,3,!1),m=ta(t,`class`,3,``),h=ea(t,ca),g=j(()=>l()&&i()[t.key]!==c()&&i()[t.key]!==s()?null:i()[t.key]===c()||c()===null&&i()[t.key]===void 0),_=j(()=>f()&&i()[t.key]),v=j(()=>[`date`,`number`,`text`,`textarea`,`contenteditable`].includes(r())?1e3:250),y,b=null,x=()=>{b!==null&&b!==``||u()?i()[t.key]=b:delete i()[t.key]},S=e=>{if(r()===`contenteditable`)b=e.currentTarget.innerText;else if(r()===`number`){let t=e.currentTarget.value.trim();b=t.match(/^-?\d*\.?\d+$/)?Number.parseFloat(t):null}else b=e.currentTarget.value;y&&clearTimeout(y),y=setTimeout(x,V(v))},C=()=>{V(g)?s()===null?delete i()[t.key]:i()[t.key]=s():V(g)===null?i()[t.key]=c():l()||c()===null?delete i()[t.key]:i()[t.key]=c()},w=()=>{y&&(clearTimeout(y),x()),p()&&typeof i()[t.key]==`string`&&(i()[t.key]=i()[t.key].trim())},T=(e,t)=>(e.innerText=t??``,{update(t){document.activeElement!==e&&(e.innerText=t??``)}}),E=()=>{y&&clearTimeout(y),(r()===`text`||r()===`string`)&&u()?i()[t.key]=``:delete i()[t.key]};var D=ba(),ee=F(D);li(ee,()=>t.children);var te=L(ee,2),ne=e=>{var n=ua();Vi(n,()=>({contenteditable:!0,onblur:w,oninput:S,class:`mt-1 whitespace-pre-wrap`,...h}));var r=F(n,!0);A(n),ui(n,(e,t)=>T?.(e,t),()=>i()[t.key]),R(()=>G(r,i()[t.key])),W(e,n)},re=e=>{var r=da(),a=F(r);Fi(a);var o=L(a,2);n(o),A(r),R(()=>{Ii(a,i()[t.key]),bi(a,1,`w-max ${V(_)?`pr-8`:``}`)}),Fr(`blur`,a,w),H(`input`,a,S),W(e,r)},ie=e=>{var r=fa(),a=F(r);Fi(a);var o=L(a,2);n(o),A(r),R(()=>{Ii(a,i()[t.key]),bi(a,1,V(_)?`pr-8`:``)}),Fr(`blur`,a,w),H(`input`,a,S),W(e,r)},ae=e=>{var n=ha();qi(n,()=>{var e=F(n),t=ma(),r=I(t),i=e=>{var t=Kr();q(I(t),17,o,ei,(e,t)=>{var n=Kr(),r=I(n),i=e=>{var n=pa(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t)),i!==(i=V(t))&&(n.__value=V(t))}),W(e,n)},a=e=>{var n=pa(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t).label??V(t).value),i!==(i=V(t).value)&&(n.value=(n.__value=V(t).value)??``)}),W(e,n)};K(r,e=>{typeof V(t)==`string`?e(i):e(a,-1)}),W(e,n)}),W(e,t)},a=j(()=>Array.isArray(o())),s=e=>{var t=Kr();li(I(t),()=>o()??d),W(e,t)};K(r,e=>{V(a)?e(i):e(s,-1)}),W(e,t)});var r;wi(n),R(()=>{r!==(r=i()[t.key]??``)&&(n.value=(n.__value=i()[t.key]??``)??``,Ci(n,i()[t.key]??``))}),Fr(`blur`,n,w),H(`input`,n,S),W(e,n)},oe=e=>{var n=ga(),r=F(n),i=L(r);{let e=j(()=>t.leftLabel?``:void 0),n=j(()=>t.rightLabel?``:void 0);sa(i,{get value(){return V(g)},onToggle:C,get labelOff(){return V(e)},get labelOn(){return V(n)}})}var a=L(i);A(n),R(()=>{G(r,`${t.leftLabel??``} `),G(a,` ${t.rightLabel??``}`)}),W(e,n)},se=e=>{var r=_a(),a=F(r);Fi(a);var o=L(a,2);n(o),A(r),R(()=>{Ii(a,i()[t.key]),bi(a,1,`grow ${V(_)?`pr-8`:``}`)}),Fr(`blur`,a,w),H(`input`,a,S),W(e,r)},ce=e=>{var n=va();ut(n),Vi(n,()=>({onblur:w,oninput:S,...h,value:i()[t.key]})),W(e,n)};K(te,e=>{r()===`contenteditable`?e(ne):r()===`date`?e(re,1):r()===`number`?e(ie,2):r()===`select`?e(ae,3):r()===`switch`?e(oe,4):r()===`string`||r()===`text`?e(se,5):r()===`textarea`&&e(ce,6)});var le=L(te,2),ue=e=>{var t=ya(),n=F(t,!0);A(t),R(()=>G(n,a())),W(e,t)},de=e=>{var t=Kr();li(I(t),()=>a()??d),W(e,t)};K(le,e=>{typeof a()==`string`?e(ue):e(de,-1)}),A(D),R(()=>bi(D,1,mi(m()))),W(e,D),Je()}Ir([`click`,`input`]);var Sa=U(`<div><button type="button" class="group w-full flex items-center unstyled cursor-pointer py-0.5"><!> <!></button> <div class="contents"><div><div class="flex flex-col gap-3 px-0.5 pb-2 mt-2 overflow-hidden"><!></div></div></div></div>`);function Ca(e,t){qe(t,!0);let n=ta(t,`startOpen`,3,!1),r=ta(t,`wrapperClass`,3,`border-night-700`),i=N(on(br(()=>n())));function a(){P(i,!1)}let o=()=>{P(i,!V(i))};var s={close:a},c=Sa(),l=F(c),u=F(l);li(u,()=>t.title,()=>V(i));var d=L(u,2);{let e=j(()=>V(i)?`chevron_up`:`chevron_down`);aa(d,{get name(){return V(e)},size:24,class:`text-ice-800 group-hover:text-black ml-auto`})}A(l);var f=L(l,2),p=F(f),m=F(p);return li(F(m),()=>t.children),A(m),A(p),A(f),A(c),R(()=>{bi(c,1,`border-l-4 ${r()??``} pl-4 py-0.5`),bi(p,1,`grid transition-[grid-template-rows] ease-in-out overflow-hidden ${V(i)?`grid-rows-[1fr]`:`grid-rows-[0fr]`}`)}),H(`click`,l,o),W(e,c),Je(s)}Ir([`click`]);var wa=JSON.parse(document.querySelector(`[data-dashboard-config]`)?.dataset?.datasetSchema),Ta=e=>e.replace(/_/g,` `).replace(/^[a-z]/,e=>e.toLocaleUpperCase()).replace(/\bSql\b/g,`SQL`).replace(/\bUtm\b/g,`UTM`),Ea={"01":`January`,"02":`February`,"03":`March`,"04":`April`,"05":`May`,"06":`June`,"07":`July`,"08":`August`,"09":`September`,10:`October`,11:`November`,12:`December`},Da={"01":`Jan`,"02":`Feb`,"03":`Mar`,"04":`Apr`,"05":`May`,"06":`Jun`,"07":`Jul`,"08":`Aug`,"09":`Sep`,10:`Oct`,11:`Nov`,12:`Dec`},Oa=(e,t)=>{if(typeof e!=`string`||!e.match(/^\d{4}-\d{2}-\d{2}/))return`${e}`;let[n,r,i]=e.substring(0,10).split(`-`,3);if(!n||!r||!i)return e;switch(t){case`month`:return`${Ea[r]} ${n}`;case`week`:return`w/c ${+i} ${Da[r]} ${n.substring(2,4)}`;case`day`:return`${+i} ${Da[r]} ${n.substring(2,4)}`}},ka=e=>e.type===`percentage`,Aa=e=>e.type===`sql`,ja=e=>!ka(e)&&!Aa(e),Ma=e=>e.operator===`empty`||e.operator===`not empty`,Na={boolean:!0,date:new Date().toISOString().substring(0,10),number:0,one_of:``,string:``},Pa=e=>{if(e.type===`one_of`&&e.options){let t=e.options[0];return typeof t==`string`?t:t?.value??``}return Na[e.type??`string`]},Fa=(e,t)=>{if(!t.includes(`.`))return{datasetType:e.type,targetSchema:wa[e.type],field:t,fieldSchema:wa[e.type]?.fields?.[t]};let[n,r]=t.split(`.`,2);return{datasetType:n,targetSchema:wa[n],field:r,fieldSchema:wa[n]?.fields?.[r],association:`belongs_to`}},Ia=(e,t)=>{if(!e?.fields?.[t.field]?.filter)return!1;let n=e.fields[t.field];if(!n||!Ba(n).includes(t.operator))return!1;if(Ma(t))return!(`value`in t);let r=n.type??`string`;switch(r){case`one_of`:return n.options?.some(e=>typeof e==`string`?e===t.value:e.value===t.value);case`date`:return typeof t.value==`string`&&t.value.match(/^\d{4}-[01]\d-[0-3]\d$/);default:return typeof t.value===r}},La=e=>wa[e]?.label??Ta(e),Ra=(e,t)=>wa[t??``]?.fields?.[e]?.label??Ta(e),za={boolean:[`=`,`!=`,`empty`,`not empty`],date:[`=`,`!=`,`>`,`>=`,`<=`,`<`,`empty`,`not empty`],number:[`=`,`!=`,`>`,`>=`,`<=`,`<`,`empty`,`not empty`],one_of:[`=`,`!=`,`empty`,`not empty`],string:[`=`,`!=`,`like`,`not like`,`empty`,`not empty`]},Ba=e=>za[e?.type??`string`],Va=(e,t)=>{let n=wa[e];return t===e||n?.counts?.[t]||n?.belongs_to?.includes(t)?e:n?.belongs_to?.find(e=>!!wa[e]?.counts?.[t])},Ha=U(`<option> </option>`),Ua=U(`<span class="sr-only"> </span>`),Wa=U(`<p class="help-text -mt-1 mb-1 col-span-4"> </p>`),Ga=U(`<span> </span> <label><span class="sr-only">operator</span> <select></select></label> <!> <button type="button" class="unstyled text-night-800 hover:text-black hover:bg-night-50 p-2 cursor-pointer"><!></button> <!>`,1);function Ka(e,t){qe(t,!0);let n=j(()=>wa[t.datasetType]?.fields?.[t.filter.field]),r=(e,r)=>{if(!t.dataset.filters)return;let i=r.currentTarget.value,a=t.dataset.filters[e],o=Ma(a);a.operator=i,Ma(a)?delete a.value:(o||a.value===void 0)&&(a.value=V(n)?Pa(V(n)):``)};var i=Ga(),a=I(i),o=F(a);A(a);var s=L(a,2),c=L(F(s),2);q(c,21,()=>Ba(V(n)),ei,(e,t)=>{var n=Ha(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t)),i!==(i=V(t))&&(n.__value=V(t))}),W(e,n)}),A(c);var l;wi(c),A(s);var u=L(s,2),d=e=>{var r=Kr(),i=I(r),a=e=>{{let r=j(()=>V(n).leftValue!==void 0&&V(n).leftValue),i=j(()=>V(n).rightValue===void 0||V(n).rightValue);xa(e,{type:`switch`,get model(){return t.filter},get leftLabel(){return V(n).leftLabel},get leftValue(){return V(r)},get rightLabel(){return V(n).rightLabel},get rightValue(){return V(i)},key:`value`,class:`ml-1`,children:(e,n)=>{var r=Ua(),i=F(r);A(r),R(e=>G(i,`${e??``} value`),[()=>Ra(t.filter.field,t.datasetType)]),W(e,r)},$$slots:{default:!0}})}},o=e=>{xa(e,{type:`select`,get model(){return t.filter},key:`value`,get selectOptions(){return V(n).options},class:`w-max`,allowEmpty:!0,children:(e,n)=>{var r=Ua(),i=F(r);A(r),R(e=>G(i,`${e??``} value`),[()=>Ra(t.filter.field,t.datasetType)]),W(e,r)},$$slots:{default:!0}})},s=e=>{{let r=j(()=>V(n)?.type??`string`),i=j(()=>!V(n)?.type||V(n)?.type===`string`);xa(e,{get type(){return V(r)},get model(){return t.filter},key:`value`,class:`w-full`,allowEmpty:!0,get showClear(){return V(i)},children:(e,n)=>{var r=Ua(),i=F(r);A(r),R(e=>G(i,`${e??``} value`),[()=>Ra(t.filter.field,t.datasetType)]),W(e,r)},$$slots:{default:!0}})}};K(i,e=>{V(n)?.type===`boolean`?e(a):V(n)?.type===`one_of`?e(o,1):e(s,-1)}),W(e,r)},f=j(()=>!Ma(t.filter));K(u,e=>{V(f)&&e(d)});var p=L(u,2);aa(F(p),{name:`delete`}),A(p);var m=L(p,2),h=e=>{var t=Wa(),r=F(t,!0);A(t),R(()=>G(r,V(n).description)),W(e,t)};K(m,e=>{V(n)?.description&&e(h)}),R((e,n)=>{G(o,`${e??``}:`),bi(s,1,`h-full ${n??``}`),l!==(l=t.filter.operator)&&(c.value=(c.__value=t.filter.operator)??``,Ci(c,t.filter.operator))},[()=>Ra(t.filter.field,t.datasetType),()=>Ma(t.filter)?`col-span-2 w-max`:``]),H(`change`,c,e=>r(t.index,e)),H(`click`,p,function(...e){t.removeFilter?.apply(this,e)}),W(e,i),Je()}Ir([`change`,`click`]);var qa=U(`<p class="text-sm font-medium text-ice-600 mt-2 col-span-4"> </p> <!>`,1),Ja=U(`<div class="grid grid-cols-[auto_4rem_1fr_auto] gap-1 items-center"><!> <!></div>`),Ya=U(`<option> </option>`),Xa=U(`<div class="border-l-2 border-ice-700 pl-4 mt-4 py-0.5 flex flex-col gap-3"><p class="text-sm font-medium text-ice-700">Filters</p> <!> <label><span class="sr-only">Add a filter</span> <select class="text-gray-600"><option selected="">Add a filter</option><!></select></label></div>`);function Za(e,t){qe(t,!0);let n=ta(t,`dataset`,7),r=j(()=>n().filters?.length?!0:n().belongs_to?Object.values(n().belongs_to).some(e=>e.filters?.length):!1),i=e=>{if(!ja(n()))return;let{field:t,datasetType:r,fieldSchema:i,association:a}=Fa(n(),e.currentTarget.value),o=n();a===`belongs_to`&&(n().belongs_to??={},n().belongs_to[r]??={},o=n().belongs_to[r]),i&&(o.filters??=[],o.filters.push({field:t,operator:`=`,value:Pa(i)}),e.currentTarget.value=``)},a=(e,r)=>{if(!ja(n()))return;let i=n();if(r!==null){if(!n().belongs_to?.[r])return;i=n().belongs_to[r]}Array.isArray(i.filters)&&(i.filters.length===1?(delete i.filters,r!==null&&t.pruneBelongsTo()):i.filters.splice(e,1))};var o=Xa(),s=L(F(o),2),c=e=>{var t=Ja(),r=F(t);q(r,17,()=>n().filters??[],ei,(e,t,r)=>{Ka(e,{get dataset(){return n()},get datasetType(){return n().type},get filter(){return V(t)},index:r,removeFilter:()=>a(r,null)})});var i=L(r,2),o=e=>{var t=Kr();q(I(t),17,()=>Object.entries(n().belongs_to),([e,t])=>e,(e,t)=>{var n=j(()=>h(V(t),2));let r=()=>V(n)[0],i=()=>V(n)[1];var o=Kr(),s=I(o),c=e=>{var t=qa(),n=I(t),o=F(n,!0);A(n),q(L(n,2),17,()=>i().filters,ei,(e,t,n)=>{Ka(e,{get dataset(){return i()},get datasetType(){return r()},get filter(){return V(t)},index:n,removeFilter:()=>a(n,r())})}),R(e=>G(o,e),[()=>La(r())]),W(e,t)};K(s,e=>{i().filters?.length&&e(c)}),W(e,o)}),W(e,t)};K(i,e=>{n().belongs_to&&e(o)}),A(t),W(e,t)};K(s,e=>{V(r)&&e(c)});var l=L(s,2),u=L(F(l),2),d=F(u);d.value=d.__value=``,q(L(d),17,()=>t.filterFields,ei,(e,t)=>{var n=Ya(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t).label),i!==(i=V(t).value)&&(n.value=(n.__value=V(t).value)??``)}),W(e,n)}),A(u),A(l),A(o),R(()=>bi(l,1,V(r)?`mt-4`:``)),H(`change`,u,i),W(e,o),Je()}Ir([`change`]);var Qa=U(`<div class="flex items-center gap-1 pill pr-0.5"><div class="font-medium"><!> </div> <button type="button" class="unstyled text-night-800 hover:text-black hover:bg-night-50 p-1 cursor-pointer"><!></button></div>`),$a=U(`<div class="flex flex-wrap gap-2"></div>`),eo=U(`<option> </option>`),to=U(`<div class="border-l-2 border-ice-700 pl-4 mt-4 py-0.5 flex flex-col gap-3"><p class="text-sm font-medium text-ice-700">Selected fields</p> <p class="text-xs text-grey-600">If no fields are selected, all fields in the dataset will be returned</p> <!> <label><span class="sr-only">Add a select</span> <select class="text-gray-600"><option selected="">Add a select</option><!></select></label></div>`);function no(e,t){qe(t,!0);let n=ta(t,`dataset`,7),r=e=>{if(!ja(n()))return;let t=e.currentTarget.value;n().selects??=[],n().selects.push(t);let{datasetType:r,association:i}=Fa(n(),t);i===`belongs_to`&&(n().belongs_to??={},n().belongs_to[r]??={}),e.currentTarget.value=``},i=e=>{if(!(!ja(n())||!Array.isArray(n().selects))){if(n().selects.length===1)delete n().selects;else{let t=n().selects.indexOf(e);n().selects.splice(t,1)}e.includes(`.`)&&t.pruneBelongsTo()}};var a=to(),o=L(F(a),4),s=e=>{var t=$a();q(t,21,()=>n().selects,ei,(e,t)=>{let r=j(()=>{let{association:e,field:r,fieldSchema:i,datasetType:a}=Fa(n(),V(t));return{association:e,field:r,fieldSchema:i,datasetType:a}});var a=Qa(),o=F(a),s=F(o),c=e=>{var t=Gr();R(e=>G(t,`${e??``}:`),[()=>La(V(r).datasetType)]),W(e,t)};K(s,e=>{V(r).association===`belongs_to`&&e(c)});var l=L(s);A(o);var u=L(o,2);aa(F(u),{size:`16`,name:`delete`}),A(u),A(a),R(e=>G(l,` ${e??``}`),[()=>V(r).fieldSchema?.label??Ta(V(r).field)]),H(`click`,u,()=>i(V(t))),W(e,a)}),A(t),W(e,t)},c=j(()=>Array.isArray(n().selects));K(o,e=>{V(c)&&e(s)});var l=L(o,2),u=L(F(l),2),d=F(u);d.value=d.__value=``,q(L(d),17,()=>t.selectFields,ei,(e,t)=>{var r=Kr(),i=I(r),a=e=>{var n=eo(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t).label),i!==(i=V(t).value)&&(n.value=(n.__value=V(t).value)??``)}),W(e,n)},o=j(()=>!Array.isArray(n().selects)||!n().selects.includes(V(t).value));K(i,e=>{V(o)&&e(a)}),W(e,r)}),A(u),A(l),A(a),H(`change`,u,r),W(e,a),Je()}Ir([`click`,`change`]);var ro=U(`<div class="flex items-center gap-1 pill pr-0.5"><div class="font-medium"> </div> <button type="button" class="unstyled text-night-800 hover:text-black hover:bg-night-50 p-1 cursor-pointer"><!></button></div>`),io=U(`<div class="flex flex-wrap gap-2"></div>`),ao=U(`<p class="text-sm font-medium text-ice-600"> </p> <div class="flex flex-wrap gap-2 -mt-2"></div>`,1),oo=U(`<option> </option>`),so=U(`<div class="border-l-2 border-ice-700 pl-4 mt-4 py-0.5 flex flex-col gap-3"><p class="text-sm font-medium text-ice-700">Splits</p> <p class="-mt-2 text-xs text-grey-600">Shows a separate chart series for each unique value of the given fields</p> <!> <!> <label><span class="sr-only">Add a split</span> <select class="text-gray-600"><option selected="">Add a split</option><!></select></label></div>`);function co(e,t){qe(t,!0);let n=ta(t,`dataset`,7),r=e=>{if(!ja(n()))return;let{datasetType:t,field:r,association:i}=Fa(n(),e.currentTarget.value),a;i===`belongs_to`?(n().belongs_to??={},n().belongs_to[t]??={},a=n().belongs_to[t]):a=n(),a&&(a.split_by??=[],a.split_by.push(r),e.currentTarget.value=``)},i=(e,r)=>{if(!ja(n()))return;let i=n();if(r!==null){if(!n().belongs_to?.[r])return;i=n().belongs_to[r]}if(Array.isArray(i.split_by)){if(i.split_by.length===1)delete i.split_by,r!==null&&t.pruneBelongsTo();else{let t=i.split_by.indexOf(e);i.split_by.splice(t,1)}}};var a=so();{let e=(e,t=d,r)=>{let a=Et(()=>m(r?.(),null));var o=ro(),s=F(o),c=F(s,!0);A(s);var l=L(s,2);aa(F(l),{size:`16`,name:`delete`}),A(l),A(o),R(e=>G(c,e),[()=>Ra(t(),V(a)??n().type)]),H(`click`,l,()=>i(t(),V(a))),W(e,o)};var o=L(F(a),4),s=t=>{var r=io();q(r,21,()=>n().split_by,ei,(t,n)=>{e(t,()=>V(n))}),A(r),W(t,r)},c=j(()=>Array.isArray(n().split_by));K(o,e=>{V(c)&&e(s)});var l=L(o,2),u=t=>{var r=Kr();q(I(r),17,()=>Object.entries(n().belongs_to),([e,t])=>e,(t,n)=>{var r=j(()=>h(V(n),2));let i=()=>V(r)[0],a=()=>V(r)[1];var o=Kr(),s=I(o),c=t=>{var n=ao(),r=I(n),o=F(r,!0);A(r);var s=L(r,2);q(s,21,()=>a().split_by,ei,(t,n)=>{e(t,()=>V(n),i)}),A(s),R(e=>G(o,e),[()=>La(i())]),W(t,n)},l=j(()=>Array.isArray(a().split_by)&&a().split_by.length>0);K(s,e=>{V(l)&&e(c)}),W(t,o)}),W(t,r)};K(l,e=>{n().belongs_to&&e(u)});var f=L(l,2),p=L(F(f),2),g=F(p);g.value=g.__value=``,q(L(g),17,()=>t.splitFields,ei,(e,t)=>{var r=Kr(),i=I(r),a=e=>{var n=oo(),r=F(n,!0);A(n);var i={};R(()=>{G(r,V(t).label),i!==(i=V(t).value)&&(n.value=(n.__value=V(t).value)??``)}),W(e,n)},o=j(()=>!Array.isArray(n().split_by)||!n().split_by.includes(V(t).value));K(i,e=>{V(o)&&e(a)}),W(e,r)}),A(p),A(f),A(a),H(`change`,p,r)}W(e,a),Je()}Ir([`click`,`change`]);var lo=U(`<span class="capitalize"> </span> `,1),uo=U(`<p class="text-sm font-semibold text-night-700 group-hover:text-night-800"><!></p>`),fo=U(`<option> </option>`),po=U(`<label>Count by <select></select></label>`),mo=U(`<div class="sm:grid grid-cols-[auto_1fr] gap-4 sm:gap-12"><!> <!></div> <!>`,1),ho=U(`<!> <!>`,1),go=U(`<span class="help-text">Note: your query must return three columns: <code>date</code>, <code>split</code>, and <code>count</code>. <code>split</code> can be <code>NULL</code></span>`),_o=U(`<label><span class="text-sm font-medium"> </span> <span class="ml-3 text-gray-500 text-xs font-normal">required?</span> <!></label>`),vo=U(`<div class="mt-4 flex flex-wrap gap-y-2 gap-x-4"><p class="text-sm font-medium text-ice-700 mb-0.5 basis-full">Linked tables</p> <!></div>`),yo=U(`<button type="button" class="sm">Duplicate</button>`),bo=U(`<button type="button" class="sm px-1"><!></button>`),xo=U(`<button type="button" class="sm bg-dawn-100 ml-auto">Yes, delete this dataset</button>`),So=U(`<button type="button" class="sm bg-dawn-100 ml-auto">Delete</button>`),Co=U(`<label>Label <input type="text"/> <span class="help-text">Splits can be incorporated into the label using <code>%1</code>, <code>%2</code>, etc. or with a default value if empty using <code>%1(none)</code></span></label> <div class="sm:grid grid-cols-2 gap-x-2 gap-y-4"><label class="only:col-span-2">Type <select></select></label> <!></div> <!> <!> <div class="flex flex-row gap-2 mt-4"><!> <!> <!> <!></div>`,1);function wo(e,t){qe(t,!0);let n=ta(t,`dataset`,7),r=ta(t,`startOpen`,3,!1),i=j(()=>ka(n())?[``,...t.chartConfig.datasets.filter(e=>!(e.type===`percentage`||ja(e)&&e.split_by)).map(e=>({value:e.id,label:e.label}))]:[]),a=j(()=>[...Object.keys(wa),...t.chartConfig.type===`table`?[]:[`percentage`],`sql`]),o=j(()=>wa[n().type]),s=j(()=>{if(!V(o))return{filter:[],select:[],split:[]};let e=wa[n().type]?.fields??{},t=[],r=[],i=[];for(let[n,a]of Object.entries(e)){let e={label:a.label??Ta(n),value:n};a.filter&&t.push(e),a.select&&r.push(e),a.split&&i.push(e)}if(Array.isArray(V(o).belongs_to))for(let e of V(o).belongs_to){let n=wa[e];if(n?.fields)for(let[a,o]of Object.entries(n.fields)){let s={label:`${n.label??Ta(e)}: ${o.label??Ta(a)}`,value:`${e}.${a}`};o.filter&&t.push(s),o.select&&r.push(s),o.split&&i.push(s)}}return{filter:t,select:r,split:i}}),c=j(()=>{if(!ja(n())||t.chartConfig.type===`table`||!V(o))return[];let e=[{label:V(o).counts?.[n().type]?.label??Ta(n().type),value:n().type}];for(let[t,r]of Object.entries(V(o).counts??{}))t!==n().type&&e.push({label:r.label??Ta(t),value:t});if(Array.isArray(V(o).belongs_to))for(let t of V(o).belongs_to){let n=wa[t];e.push({label:n?.counts?.[t]?.label??Ta(t),value:t});for(let[r,i]of Object.entries(n?.counts??{}))r!==t&&e.push({label:i.label??Ta(r),value:r})}return e}),l=N(!1),u=e=>{let r=e.currentTarget.value;if(r===n().type||t.chartConfig.type===`table`&&n().type===`percentage`)return;let i=n().type;n().type=r;let a=[`id`,`type`,`label`,`visible`,`axis`];ja(n())&&(a.push(`filters`,`belongs_to`),t.chartConfig.type===`table`?a.push(`selects`):a.push(`count_by`,`split_by`));for(let e of Object.keys(n()))a.includes(e)||delete n()[e];if(ja(n())){if(Array.isArray(n().filters))for(let e=0;e<n().filters.length;e++)(!V(o)||!Ia(V(o),n().filters[e]))&&(n().filters.splice(e,1),e--);if(n().count_by&&(n().count_by===i?n().count_by=n().type:V(c).find(e=>e.value===n().count_by)||(n().count_by=n().type)),n().selects){for(let e=0;e<n().selects.length;e++){let t=n().selects[e];if(t.includes(`.`)){let[i,a]=t.split(`.`,2);if(i===r&&!n().selects.includes(a)){n().selects[e]=a;continue}if(i&&V(o)?.belongs_to?.includes(i))continue}else if(V(o)?.fields[t]?.select)continue;n().selects.splice(e,1),e--}n().selects.length===0&&delete n().selects}if(n().split_by){for(let e=0;e<n().split_by.length;e++){let t=n().split_by[e];V(o)?.fields[t]?.split||(n().split_by.splice(e,1),e--)}n().split_by.length===0&&delete n().split_by}if(n().belongs_to?.[r]){if(Array.isArray(n().belongs_to[r].filters)){n().filters??=[];for(let e of n().belongs_to[r].filters)n().filters.find(t=>t.field===e.field&&t.operator===e.operator&&t.value===e.value)||n().filters.push(e)}if(Array.isArray(n().belongs_to[r].split_by)){n().split_by??=[];for(let e of n().belongs_to[r].split_by)n().split_by.includes(e)||n().split_by.push(e)}delete n().belongs_to[r]}m()}Aa(n())&&(n().sql=`SELECT
31
31
  skadi_views.created_at as "date",
32
32
  NULL as "split",
33
33
  1 as "count"
@@ -1 +1 @@
1
- var e=[],t=[],n=-1,r,i,a=!1,o={},s=window,c=document,l=`-contentful-paint`,u=`first${l}`,d=`largest${l}`,f={...c.currentScript.dataset},p=()=>{r??=setTimeout(m,500)},m=()=>{r&&=(clearTimeout(r),null),navigator.sendBeacon(f.endpoint,new Blob([JSON.stringify({view:f.view,demographics:e,events:t,consent:o,...a&&{exit_page:i}})],{type:`application/json`}))&&(e=[],t=[],o={})},h=(e,t)=>{if(e<=0)return null;if(e<t[0])return`< ${t[0]}ms`;for(let n=1;n<t.length;n++)if(e<=t[n])return`${t[n-1]}ms to ${t[n]}ms`;return`> ${t[3]}ms`},g=(t,n,r=!1)=>{if(n===null)return;let i={name:t,value:n.toString()};r&&(i.uri=f.uri),e.push(i)};new PerformanceObserver(e=>{let t=e.getEntries().at(-1);t&&(n=t.startTime)}).observe({type:d,buffered:!0}),new PerformanceObserver((e,t)=>{let n=e.getEntriesByName(u)[0];n&&(g(u,h(n.startTime,[1e3,1800,3e3,4500]),!0),t.disconnect())}).observe({type:`paint`,buffered:!0}),s.addEventListener(`load`,()=>{f.visit===`1`&&(g(`timezone`,Intl.DateTimeFormat().resolvedOptions().timeZone),g(`locale`,Intl.NumberFormat().resolvedOptions().locale),g(`screen-size`,`${s.innerWidth}x${s.innerHeight}`),g(`input-device`,s.matchMedia(`(pointer: fine)`).matches?`mouse`:`touch`)),p()}),c.addEventListener(`click`,e=>{let t=e.target?.closest(`a`);t?.href&&(t.target===`_blank`||e.ctrlKey||e.metaKey||(i=t.href))}),s.addEventListener(`pagehide`,()=>{g(d,h(n,[1500,2500,4e3,6e3]),!0),a=!0,m()}),s.addEventListener(`visibilitychange`,()=>{r&&m()}),s.skadi={event:(e,n={})=>{t.push({name:e,properties:n}),p()},demographic:(e,t,n=!1)=>{g(e,t,n),p()},consent:e=>{o=e,m()}};
1
+ var e=[],t=[],n=-1,r,i,a=!1,o={},s=window,c=document,l={...c.currentScript.dataset},u=()=>{r??=setTimeout(d,500)},d=()=>{r&&=(clearTimeout(r),null),navigator.sendBeacon(l.endpoint,new Blob([JSON.stringify({view:l.view,demographics:e,events:t,consent:o,...a&&{exit_page:i}})],{type:`application/json`}))&&(e=[],t=[],o={})},f=(e,t)=>{if(e<=0)return null;if(e<t[0])return`< ${t[0]}ms`;for(let n=1;n<t.length;n++)if(e<=t[n])return`${t[n-1]}ms to ${t[n]}ms`;return`> ${t[3]}ms`},p=(t,n,r=!1)=>{if(n===null)return;let i={name:t,value:n.toString()};r&&(i.uri=l.uri),e.push(i)};new PerformanceObserver(e=>{let t=e.getEntries().at(-1);t&&(n=t.startTime)}).observe({type:`largest-contentful-paint`,buffered:!0}),new PerformanceObserver((e,t)=>{let n=e.getEntriesByName(`first-contentful-paint`)[0];n&&(p(`FCP`,f(n.startTime,[1e3,1800,3e3,4500]),!0),t.disconnect())}).observe({type:`paint`,buffered:!0}),s.addEventListener(`load`,()=>{l.visit===`1`&&(p(`Timezone`,Intl.DateTimeFormat().resolvedOptions().timeZone),p(`Locale`,Intl.NumberFormat().resolvedOptions().locale),p(`Screen size`,`${s.innerWidth}x${s.innerHeight}`),p(`Input device`,s.matchMedia(`(pointer: fine)`).matches?`mouse`:`touch`)),u()}),c.addEventListener(`click`,e=>{let t=e.target?.closest(`a`);t?.href&&(t.target===`_blank`||e.ctrlKey||e.metaKey||(i=t.href))}),s.addEventListener(`pagehide`,()=>{p(`LCP`,f(n,[1500,2500,4e3,6e3]),!0),a=!0,d()}),s.addEventListener(`visibilitychange`,()=>{r&&d()}),s.skadi={event:(e,n={})=>{t.push({name:e,properties:n}),u()},demographic:(e,t,n=!1)=>{p(e,t,n),u()},consent:e=>{o=e,d()}};
@@ -14,8 +14,7 @@ module Skadi
14
14
  VALID_DB_ENGINES = [ :postgres, :mysql, :sqlite ]
15
15
  class_option :db_engine,
16
16
  type: :string,
17
- default: "postgres",
18
- desc: "Database engine (postgres, mysql, sqlite)"
17
+ desc: "Database engine (postgres, mysql, sqlite). Auto-detected from the app's database config when omitted."
19
18
 
20
19
  VALID_USER_ID_TYPES = [ :bigint, :integer, :uuid, :string ]
21
20
  class_option :user_id_type,
@@ -33,14 +32,49 @@ module Skadi
33
32
  "db/migrate/install_skadi.rb"
34
33
  end
35
34
 
35
+ def create_initializer
36
+ template "skadi_initializer.rb", "config/initializers/skadi.rb"
37
+ end
38
+
36
39
  # Thor requires us to use a private block rather than private on individual definitions
37
40
  private
38
41
 
39
42
  def user_id_type = options[:user_id_type].to_sym
40
- def db_engine = options[:db_engine].to_sym
43
+ def db_engine = (options[:db_engine] || detect_db_engine || :sqlite).to_sym
41
44
  def uuid_column_type = (db_engine == :postgres) ? :uuid : :string
42
45
  def uuid_column_options = (db_engine == :postgres) ? "" : ", limit: 36"
43
- def json_column_type = (db_engine == :postgres) ? :jsonb : :json
46
+ def json_column_type
47
+ @_json_column_type ||= case db_engine
48
+ when :mysql
49
+ :json
50
+ when :postgres
51
+ :jsonb
52
+ when :sqlite
53
+ if defined?(ActiveRecord::Base) && ActiveRecord::Base.connection.database_version >= "3.45.0"
54
+ :jsonb
55
+ else
56
+ :json
57
+ end
58
+ end
59
+ rescue StandardError
60
+ # ActiveRecord::Base.connection can throw if the database cannot be reached, in which case we fallback to :json
61
+ return @_json_column_type ||= :json
62
+ end
63
+
64
+ def detect_db_engine
65
+ return unless defined? ActiveRecord::Base
66
+
67
+ case ActiveRecord::Base.connection_db_config.adapter
68
+ when "postgresql"
69
+ :postgres
70
+ when "mysql2", "trilogy"
71
+ :mysql
72
+ when "sqlite3"
73
+ :sqlite
74
+ end
75
+ rescue StandardError
76
+ nil
77
+ end
44
78
  end
45
79
  end
46
80
  end
@@ -0,0 +1,84 @@
1
+ # This auto-generated file contains the configuration options that you are most
2
+ # likely to change. Refer to the Skadi configuration class to see the full list
3
+ # of configuration options and their descriptions.
4
+ # @see {Skadi::Configuration}
5
+
6
+ Skadi.configure do |config|
7
+ # Enables anonymity sets without requiring consent. A hash of the user's IP
8
+ # and User Agent is used to track them across the same day. This data is
9
+ # aggregated at the end of the day, anonymising it. Defaults to false.
10
+ #
11
+ # config.use_anonymity_sets = true
12
+
13
+ # Enables tracking users without requiring consent. The current user will be
14
+ # attached to site visits and used to de-duplicate visitors.
15
+ #
16
+ # config.track_users = true
17
+
18
+
19
+ # A string containing the user model class for the application.
20
+ #
21
+ # config.user_model = "User"
22
+
23
+ # The method to call within your ApplicationController to get the current user.
24
+ #
25
+ # config.user_controller_method = :current_user
26
+
27
+
28
+ # Methods to call within your ApplicationController to authenticate users for
29
+ # using the Skadi dashboard. These methods should return a boolean.
30
+ #
31
+ # config.dashboard_view_controller_method = :skadi_dashboard_can_view
32
+ # config.dashboard_edit_controller_method = :skadi_dashboard_can_edit
33
+ # config.dashboard_dangerously_use_sql_controller_method = :skadi_dashboard_can_dangerously_use_sql
34
+
35
+
36
+ # Add custom fields to the events table in the Skadi dashboard.
37
+ # @see [Skadi::Schema]
38
+ #
39
+ # config.dashboard_custom_event_fields = {
40
+ # http_verb: {
41
+ # # How the field is displayed in the dashboard. A label is auto-generated
42
+ # # if omitted ("http_verb" => "Http Verb").
43
+ # label: "HTTP Verb",
44
+ # # Additional information displayed with this field in the dashboard.
45
+ # description: "Typically, GET requests are page views, and POST, PUT, PATCH and DELETE are form submissions.",
46
+ # # The datatype, one of: :one_of, :date, :string, :number, :boolean.
47
+ # # Defaults to :string if omitted.
48
+ # type: :one_of,
49
+ # # Options for filtering in the dashboard when the :one_of type is used
50
+ # options: %w[GET POST PUT PATCH DELETE],
51
+ # # Whether this field can be selected for tables
52
+ # select: true,
53
+ # # Whether users can filter by this field
54
+ # filter: true,
55
+ # # Whether this field can be used to split a chart view
56
+ # split: true,
57
+ # # The SQL expression used to get this field
58
+ # sql: "properties->>'http_verb'",
59
+ # },
60
+ # }
61
+
62
+ # Add your own database tables to the Skadi dashboard.
63
+ # @see [Skadi::Schema] for format and examples.
64
+ #
65
+ # config.dashboard_custom_schema = {
66
+ # user: {
67
+ # model: "User",
68
+ # fields: {
69
+ # username: {
70
+ # select: true,
71
+ # filter: true,
72
+ # split: true,
73
+ # },
74
+ # name: {
75
+ # label: "Full name",
76
+ # sql: "CONCAT(users.first_name, ' ', users.last_name)",
77
+ # select: true,
78
+ # filter: true,
79
+ # split: true,
80
+ # },
81
+ # },
82
+ # },
83
+ # }
84
+ end
@@ -117,14 +117,18 @@ module Skadi
117
117
  attr_accessor :cookie_domain
118
118
  validates(:cookie_domain, "string or nil", default: nil) { |it| it.nil? || (it.present? && it.is_a?(String)) }
119
119
 
120
- # Whether to track visits by suspected bots, detected via the browser user agent. Defaults to `Rails.env.local?` (true
121
- # for development and testing environments, and false for production/other environments).
120
+ # Whether to track visits by suspected bots, detected via the browser user agent. Defaults to `Rails.env.local?` (true for development and testing environments, and false for production/other environments).
122
121
  attr_accessor :track_bots
123
122
  validates(:track_bots, "boolean", default: Rails.env.local?) { |it| it == true || it == false }
124
123
 
125
124
  # Helper method to return the inverse of :track_bots
126
125
  def do_not_track_bots? = !@track_bots
127
126
 
127
+ # Whether to record a per-action count of bot vs. non-bot views as a demographic. Defaults to false.
128
+ # @return [Boolean]
129
+ attr_accessor :count_bots
130
+ validates(:count_bots, "boolean", default: false) { |it| it == true || it == false }
131
+
128
132
  ###########################
129
133
  # Dashboard configuration #
130
134
  ###########################
@@ -29,7 +29,8 @@ module Skadi
29
29
  @events = []
30
30
  @demographics = []
31
31
 
32
- @do_not_track = bot_protection && Skadi.configuration.do_not_track_bots? && user_agent.bot?
32
+ @untracked_bot = bot_protection && Skadi.configuration.do_not_track_bots? && user_agent.bot?
33
+ @do_not_track = false
33
34
  @new_visit = false
34
35
  end
35
36
 
@@ -38,6 +39,12 @@ module Skadi
38
39
  def _prepare
39
40
  return if do_not_track?
40
41
 
42
+ # We queue the bot demographic regardless of if the request is detected as a bot or not
43
+ queue_bot_demographics
44
+
45
+ # If this is a bot visit and bot tracking is disabled, do not generate request metrics
46
+ return if untracked_bot?
47
+
41
48
  build_visit
42
49
  build_view
43
50
  queue_user_agent_demographics
@@ -59,6 +66,13 @@ module Skadi
59
66
  def _persist
60
67
  return if do_not_track?
61
68
 
69
+ if untracked_bot?
70
+ # Persist demogaphics so that bot counts are persisted
71
+ Demographic.create_or_increment_all(@demographics) if @demographics.any?
72
+
73
+ return
74
+ end
75
+
62
76
  @visit&.save
63
77
  if @view
64
78
  @view.visit = @visit
@@ -88,6 +102,12 @@ module Skadi
88
102
  @do_not_track
89
103
  end
90
104
 
105
+ # Whether the current request has been detected as a bot and we're not tracking them
106
+ # @return [Boolean]
107
+ def untracked_bot?
108
+ @untracked_bot
109
+ end
110
+
91
111
  # Disable tracking for the current request
92
112
  def do_not_track!
93
113
  @do_not_track = true
@@ -107,6 +127,8 @@ module Skadi
107
127
  # @param [String] value
108
128
  # @param [TrueClass, FalseClass] action_specific
109
129
  def demographic(name, value, action_specific: false, uri: nil)
130
+ return if untracked_bot?
131
+
110
132
  raise ArgumentError.new "Skadi::ControllerDelegate.demographic expects String as first parameter, got #{name.is_a?(String) ? "empty string" : name.class.name}" unless name.is_a?(String) && name.present?
111
133
  raise ArgumentError.new "Skadi::ControllerDelegate.demographic expects String as second parameter, got #{value.is_a?(String) ? "empty string" : value.class.name}" unless value.is_a?(String) && value.present?
112
134
 
@@ -123,6 +145,8 @@ module Skadi
123
145
  # @param [Hash] properties
124
146
  # @param [TrueClass, FalseClass] sensitive
125
147
  def event(name, properties = {}, sensitive: false)
148
+ return if untracked_bot?
149
+
126
150
  raise ArgumentError.new "Skadi::ControllerDelegate.event expects String as first parameter, got #{name.is_a?(String) ? "empty string" : name.class.name}" unless name.is_a?(String) && name.present?
127
151
  raise ArgumentError.new "Skadi::ControllerDelegate.event expects Hash as second parameter, got #{properties.class.name}" unless properties.is_a?(Hash)
128
152
 
@@ -308,6 +332,13 @@ module Skadi
308
332
  demographic "Operating system", user_agent.os
309
333
  end
310
334
 
335
+ private def queue_bot_demographics
336
+ return unless Skadi.configuration.count_bots
337
+
338
+ # We manually queue it to avoid the `untracked_bot?` early return of #demographic
339
+ @demographics << { name: "Traffic type", value: user_agent.bot? ? "Bot" : "Human", uri: request.route_uri_pattern }
340
+ end
341
+
311
342
  private def logged_in_user
312
343
  return @logged_in_user if defined?(@logged_in_user)
313
344
 
data/lib/skadi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Skadi
2
- VERSION = "0.4.0.beta.2"
2
+ VERSION = "0.4.0.beta.4"
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skadi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.beta.2
4
+ version: 0.4.0.beta.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Simon J
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-08-27 00:00:00.000000000 Z
10
+ date: 2026-09-03 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -155,6 +155,7 @@ files:
155
155
  - config/routes.rb
156
156
  - lib/generators/skadi/install/USAGE
157
157
  - lib/generators/skadi/install/install_generator.rb
158
+ - lib/generators/skadi/install/templates/skadi_initializer.rb
158
159
  - lib/generators/skadi/install/templates/skadi_migration.rb.erb
159
160
  - lib/skadi.rb
160
161
  - lib/skadi/analytics.rb