From 4ec62f5ed600f0f096b3c4f9912835ad5bb3581a Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Mon, 13 Apr 2026 23:33:04 +0200 Subject: [PATCH] refactor(frontend): migracion a Mantine y limpieza de widgets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Migra el frontend a Mantine v9 siguiendo la regla de theming del registry (@fn_library, sin Tailwind/cn/CVA). - Reescribe DashboardShell, FilterBar, Section, WidgetRenderer y todos los widgets (Area/Bar/Line/Pie/KPI/Sparkline/Table) con componentes y props de Mantine. - Ajusta vite.config, main.tsx, App.tsx, app.css y env.d.ts. - Añade postcss.config.cjs requerido por Mantine. - Actualiza package.json y pnpm-lock. - Ajusta config.go, main.go y los ejemplos (fn_registry_apps/overview) para el nuevo esquema de tipos en frontend/src/types.ts. --- config.go | 7 + examples/fn_registry_apps.yaml | 4 +- examples/fn_registry_overview.yaml | 2 +- frontend/package.json | 20 +- frontend/package.json.md5 | 2 +- frontend/pnpm-lock.yaml | 990 +++++++----------- frontend/postcss.config.cjs | 14 + frontend/src/App.tsx | 33 +- frontend/src/app.css | 173 --- frontend/src/components/DashboardShell.tsx | 88 +- frontend/src/components/FilterBar.tsx | 62 +- frontend/src/components/Section.tsx | 48 +- frontend/src/components/WidgetRenderer.tsx | 26 +- .../components/widgets/AreaChartWidget.tsx | 70 +- .../src/components/widgets/BarChartWidget.tsx | 86 +- frontend/src/components/widgets/KPIWidget.tsx | 2 +- .../components/widgets/LineChartWidget.tsx | 60 +- .../src/components/widgets/PieChartWidget.tsx | 78 +- .../components/widgets/SparklineWidget.tsx | 9 +- .../src/components/widgets/TableWidget.tsx | 69 +- frontend/src/env.d.ts | 5 +- frontend/src/main.tsx | 31 +- frontend/src/types.ts | 1 + frontend/vite.config.ts | 7 +- main.go | 16 +- 25 files changed, 807 insertions(+), 1096 deletions(-) create mode 100644 frontend/postcss.config.cjs diff --git a/config.go b/config.go index d7492f3..13ef6e7 100644 --- a/config.go +++ b/config.go @@ -25,6 +25,7 @@ type Settings struct { Width int `yaml:"width" json:"width"` Height int `yaml:"height" json:"height"` Columns int `yaml:"columns" json:"columns"` + Layout string `yaml:"layout" json:"layout"` // "scrollable" (default) or "single_view" } type ConnConfig struct { @@ -127,6 +128,12 @@ func (c *DashboardConfig) validate() error { if c.Theme == "" { c.Theme = "dark" } + if c.Settings.Layout == "" { + c.Settings.Layout = "scrollable" + } + if c.Settings.Layout != "scrollable" && c.Settings.Layout != "single_view" { + return fmt.Errorf("settings.layout must be 'scrollable' or 'single_view', got %q", c.Settings.Layout) + } if len(c.Connections) == 0 { return fmt.Errorf("at least one connection is required") diff --git a/examples/fn_registry_apps.yaml b/examples/fn_registry_apps.yaml index fa518c7..8456655 100644 --- a/examples/fn_registry_apps.yaml +++ b/examples/fn_registry_apps.yaml @@ -5,12 +5,12 @@ settings: height: 900 columns: 12 -theme: "emerald" +theme: "amber" connections: registry: driver: sqlite - path: ../../registry.db + path: ../../../registry.db queries: # --- KPIs --- diff --git a/examples/fn_registry_overview.yaml b/examples/fn_registry_overview.yaml index 6e43157..504968b 100644 --- a/examples/fn_registry_overview.yaml +++ b/examples/fn_registry_overview.yaml @@ -10,7 +10,7 @@ theme: "dark" connections: registry: driver: sqlite - path: ../../registry.db + path: ../../../registry.db queries: # --- KPIs --- diff --git a/frontend/package.json b/frontend/package.json index 09d1801..85ced90 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,27 +9,25 @@ "preview": "vite preview --host" }, "dependencies": { -"@base-ui/react": "^1.3.0", + "@mantine/charts": "^9.0.0", + "@mantine/core": "^9.0.0", + "@mantine/hooks": "^9.0.0", + "@mantine/notifications": "^9.0.0", "@phosphor-icons/react": "^2.1.10", - "@radix-ui/react-checkbox": "^1.3.3", - "@radix-ui/react-slider": "^1.3.6", + "@tabler/icons-react": "^3.41.1", "@tanstack/react-table": "^8.21.3", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", "date-fns": "^4.1.0", - "lucide-react": "^0.577.0", "react": "^19.2.4", - "react-day-picker": "^9.14.0", "react-dom": "^19.2.4", - "recharts": "^3.8.0", - "tailwind-merge": "^3.5.0" + "recharts": "^3.8.0" }, "devDependencies": { - "@tailwindcss/vite": "^4.2.2", "@types/react": "^19.2.14", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.0", - "tailwindcss": "^4.2.2", + "postcss": "^8.5.8", + "postcss-preset-mantine": "^1.18.0", + "postcss-simple-vars": "^7.0.1", "typescript": "~5.9.3", "vite": "^8.0.0" } diff --git a/frontend/package.json.md5 b/frontend/package.json.md5 index 4592c0a..76a69fd 100755 --- a/frontend/package.json.md5 +++ b/frontend/package.json.md5 @@ -1 +1 @@ -052e44bcd719cd7db765d6c7fb248074 \ No newline at end of file +1677d31df4e76e35008620851dba3211 \ No newline at end of file diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 6f603fa..9a860e3 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -8,52 +8,40 @@ importers: .: dependencies: - '@base-ui/react': - specifier: ^1.3.0 - version: 1.3.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mantine/charts': + specifier: ^9.0.0 + version: 9.0.0(@mantine/core@9.0.0(@mantine/hooks@9.0.0(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mantine/hooks@9.0.0(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(recharts@3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1)) + '@mantine/core': + specifier: ^9.0.0 + version: 9.0.0(@mantine/hooks@9.0.0(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mantine/hooks': + specifier: ^9.0.0 + version: 9.0.0(react@19.2.4) + '@mantine/notifications': + specifier: ^9.0.0 + version: 9.0.0(@mantine/core@9.0.0(@mantine/hooks@9.0.0(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mantine/hooks@9.0.0(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@phosphor-icons/react': specifier: ^2.1.10 version: 2.1.10(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-checkbox': - specifier: ^1.3.3 - version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slider': - specifier: ^1.3.6 - version: 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tabler/icons-react': + specifier: ^3.41.1 + version: 3.41.1(react@19.2.4) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 date-fns: specifier: ^4.1.0 version: 4.1.0 - lucide-react: - specifier: ^0.577.0 - version: 0.577.0(react@19.2.4) react: specifier: ^19.2.4 version: 19.2.4 - react-day-picker: - specifier: ^9.14.0 - version: 9.14.0(react@19.2.4) react-dom: specifier: ^19.2.4 version: 19.2.4(react@19.2.4) recharts: specifier: ^3.8.0 version: 3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1) - tailwind-merge: - specifier: ^3.5.0 - version: 3.5.0 devDependencies: - '@tailwindcss/vite': - specifier: ^4.2.2 - version: 4.2.2(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1)) '@types/react': specifier: ^19.2.14 version: 19.2.14 @@ -62,16 +50,22 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.0 - version: 6.0.1(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1)) - tailwindcss: - specifier: ^4.2.2 - version: 4.2.2 + version: 6.0.1(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.8))) + postcss: + specifier: ^8.5.8 + version: 8.5.8 + postcss-preset-mantine: + specifier: ^1.18.0 + version: 1.18.0(postcss@8.5.8) + postcss-simple-vars: + specifier: ^7.0.1 + version: 7.0.1(postcss@8.5.8) typescript: specifier: ~5.9.3 version: 5.9.3 vite: specifier: ^8.0.0 - version: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1) + version: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.8)) packages: @@ -79,30 +73,6 @@ packages: resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} - '@base-ui/react@1.3.0': - resolution: {integrity: sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@types/react': ^17 || ^18 || ^19 - react: ^17 || ^18 || ^19 - react-dom: ^17 || ^18 || ^19 - peerDependenciesMeta: - '@types/react': - optional: true - - '@base-ui/utils@0.2.6': - resolution: {integrity: sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw==} - peerDependencies: - '@types/react': ^17 || ^18 || ^19 - react: ^17 || ^18 || ^19 - react-dom: ^17 || ^18 || ^19 - peerDependenciesMeta: - '@types/react': - optional: true - - '@date-fns/tz@1.4.1': - resolution: {integrity: sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==} - '@emnapi/core@1.9.1': resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} @@ -124,24 +94,48 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' + '@floating-ui/react@0.27.19': + resolution: {integrity: sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==} + peerDependencies: + react: '>=17.0.0' + react-dom: '>=17.0.0' + '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@mantine/charts@9.0.0': + resolution: {integrity: sha512-TnbjiT2tXZDAQWZrv/+Xu3JKYjPiTfO5jSIbcwnxZSVtLI+PIxA7zrSps+it/Nx3ch8GHpDizJ7UArC0UfmNkQ==} + peerDependencies: + '@mantine/core': 9.0.0 + '@mantine/hooks': 9.0.0 + react: ^19.2.0 + react-dom: ^19.2.0 + recharts: '>=3.2.1' - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@mantine/core@9.0.0': + resolution: {integrity: sha512-GUUXlf+4uDpRu5iZ1PFy1NmgG7ttI+1I6VTw3v/b7N1jwOUhARwL1moGjPMjo3Eie3tHdVOCiVMYAvhlQ1GI5Q==} + peerDependencies: + '@mantine/hooks': 9.0.0 + react: ^19.2.0 + react-dom: ^19.2.0 - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + '@mantine/hooks@9.0.0': + resolution: {integrity: sha512-TKcz+k0JH/jtblBfwOw/vXBX2EpJO66psJ5ZVmdDhwc6vbHDsvY6oYN8ynt9TfRn/eHZXsEmLPNj+wuGtWy4BA==} + peerDependencies: + react: ^19.2.0 - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@mantine/notifications@9.0.0': + resolution: {integrity: sha512-BHln+CvmiQx59dMIzwxjLnXN3ongqRFHyox8DogSkMFwVfH76CTahTMz+1AA2fvkZOI0svsqR0zBZ/J7o3uUqw==} + peerDependencies: + '@mantine/core': 9.0.0 + '@mantine/hooks': 9.0.0 + react: ^19.2.0 + react-dom: ^19.2.0 - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@mantine/store@9.0.0': + resolution: {integrity: sha512-ts1cfBqJEASBNuZ3vzOGDLkfQjF9EDFqUUSOOqZRiwtwt3OyZojIxfWMBcATorH8UODM7dsUhfI82VbGUjZiJA==} + peerDependencies: + react: ^19.2.0 '@napi-rs/wasm-runtime@1.1.2': resolution: {integrity: sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw==} @@ -159,158 +153,6 @@ packages: react: '>= 16.8' react-dom: '>= 16.8' - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-checkbox@1.3.3': - resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slider@1.3.6': - resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@reduxjs/toolkit@2.11.2': resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==} peerDependencies: @@ -423,99 +265,13 @@ packages: '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - '@tabby_ai/hijri-converter@1.0.5': - resolution: {integrity: sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==} - engines: {node: '>=16.0.0'} - - '@tailwindcss/node@4.2.2': - resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} - - '@tailwindcss/oxide-android-arm64@4.2.2': - resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.2.2': - resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.2.2': - resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.2.2': - resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': - resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': - resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-musl@4.2.2': - resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-gnu@4.2.2': - resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-musl@4.2.2': - resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-wasm32-wasi@4.2.2': - resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': - resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.2.2': - resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.2.2': - resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} - engines: {node: '>= 20'} - - '@tailwindcss/vite@4.2.2': - resolution: {integrity: sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==} + '@tabler/icons-react@3.41.1': + resolution: {integrity: sha512-kUgweE+DJtAlMZVIns1FTDdcbpRVnkK7ZpUOXmoxy3JAF0rSHj0TcP4VHF14+gMJGnF+psH2Zt26BLT6owetBA==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 || ^8 + react: '>= 16' + + '@tabler/icons@3.41.1': + resolution: {integrity: sha512-OaRnVbRmH2nHtFeg+RmMJ/7m2oBIF9XCJAUD5gQnMrpK9f05ydj8MZrAf3NZQqOXyxGN1UBL0D5IKLLEUfr74Q==} '@tanstack/react-table@8.21.3': resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} @@ -582,13 +338,19 @@ packages: babel-plugin-react-compiler: optional: true - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -636,9 +398,6 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} - date-fns-jalali@4.1.0-0: - resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==} - date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} @@ -649,9 +408,11 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - enhanced-resolve@5.20.1: - resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} - engines: {node: '>=10.13.0'} + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} es-toolkit@1.45.1: resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==} @@ -673,8 +434,9 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} immer@10.2.0: resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} @@ -690,6 +452,9 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} @@ -760,19 +525,19 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - lucide-react@0.577.0: - resolution: {integrity: sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -780,24 +545,63 @@ packages: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} + postcss-js@4.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-mixins@12.1.2: + resolution: {integrity: sha512-90pSxmZVfbX9e5xCv7tI5RV1mnjdf16y89CJKbf/hD7GyOz1FCxcYMl8ZYA8Hc56dbApTKKmU9HfvgfWdCxlwg==} + engines: {node: ^20.0 || ^22.0 || >=24.0} + peerDependencies: + postcss: ^8.2.14 + + postcss-nested@7.0.2: + resolution: {integrity: sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-preset-mantine@1.18.0: + resolution: {integrity: sha512-sP6/s1oC7cOtBdl4mw/IRKmKvYTuzpRrH/vT6v9enMU/EQEQ31eQnHcWtFghOXLH87AAthjL/Q75rLmin1oZoA==} + peerDependencies: + postcss: '>=8.0.0' + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-simple-vars@7.0.1: + resolution: {integrity: sha512-5GLLXaS8qmzHMOjVxqkk1TZPf1jMqesiI7qLhnlyERalG0sMbHIbJqrcnrpmZdKCLglHnRHoEBB61RtGTsj++A==} + engines: {node: '>=14.0'} + peerDependencies: + postcss: ^8.2.1 + postcss@8.5.8: resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} engines: {node: ^10 || ^12 || >=14} - react-day-picker@9.14.0: - resolution: {integrity: sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==} - engines: {node: '>=18'} - peerDependencies: - react: '>=16.8.0' + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} react-dom@19.2.4: resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: react: ^19.2.4 + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@19.2.4: resolution: {integrity: sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==} + react-number-format@5.4.5: + resolution: {integrity: sha512-y8O2yHHj3w0aE9XO8d2BCcUOOdQTRSVq+WIuMlLVucAm5XNjJAy+BoOJiuQMldVYVOKTMyvVNfnbl2Oqp+YxGw==} + peerDependencies: + react: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-redux@9.2.0: resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} peerDependencies: @@ -810,6 +614,42 @@ packages: redux: optional: true + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + react@19.2.4: resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} engines: {node: '>=0.10.0'} @@ -845,18 +685,18 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + sugarss@5.0.1: + resolution: {integrity: sha512-ctS5RYCBVvPoZAnzIaX5QSShK8ZiZxD5HUqSxlusvEMC+QZQIPCPOIJg6aceFX+K2rf4+SH89eu++h1Zmsr2nw==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.3.3 + tabbable@6.4.0: resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} - tailwind-merge@3.5.0: - resolution: {integrity: sha512-I8K9wewnVDkL1NTGoqWmVEIlUcB9gFriAEkXkfCjX5ib8ezGxtR3xD7iZIxrfArjEsH7F1CHD4RFUtxefdqV/A==} - - tailwindcss@4.2.2: - resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} - - tapable@2.3.2: - resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} - engines: {node: '>=6'} + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -868,16 +708,43 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + type-fest@5.5.0: + resolution: {integrity: sha512-PlBfpQwiUvGViBNX84Yxwjsdhd1TUlXr6zjX7eoirtCPIr08NAmxwa+fcYBTeRQxHo9YC9wwF3m9i700sHma8g==} + engines: {node: '>=20'} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} @@ -928,32 +795,6 @@ snapshots: '@babel/runtime@7.29.2': {} - '@base-ui/react@1.3.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@babel/runtime': 7.29.2 - '@base-ui/utils': 0.2.6(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@floating-ui/utils': 0.2.11 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - tabbable: 6.4.0 - use-sync-external-store: 1.6.0(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - - '@base-ui/utils@0.2.6(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@babel/runtime': 7.29.2 - '@floating-ui/utils': 0.2.11 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - reselect: 5.1.1 - use-sync-external-store: 1.6.0(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - - '@date-fns/tz@1.4.1': {} - '@emnapi/core@1.9.1': dependencies: '@emnapi/wasi-threads': 1.2.0 @@ -985,26 +826,53 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) + '@floating-ui/react@0.27.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@floating-ui/utils': 0.2.11 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tabbable: 6.4.0 + '@floating-ui/utils@0.2.11': {} - '@jridgewell/gen-mapping@0.3.13': + '@mantine/charts@9.0.0(@mantine/core@9.0.0(@mantine/hooks@9.0.0(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mantine/hooks@9.0.0(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(recharts@3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1))': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 + '@mantine/core': 9.0.0(@mantine/hooks@9.0.0(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mantine/hooks': 9.0.0(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + recharts: 3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1) - '@jridgewell/remapping@2.3.5': + '@mantine/core@9.0.0(@mantine/hooks@9.0.0(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 + '@floating-ui/react': 0.27.19(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mantine/hooks': 9.0.0(react@19.2.4) + clsx: 2.1.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-number-format: 5.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.14)(react@19.2.4) + type-fest: 5.5.0 + transitivePeerDependencies: + - '@types/react' - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': + '@mantine/hooks@9.0.0(react@19.2.4)': dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + react: 19.2.4 + + '@mantine/notifications@9.0.0(@mantine/core@9.0.0(@mantine/hooks@9.0.0(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@mantine/hooks@9.0.0(react@19.2.4))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@mantine/core': 9.0.0(@mantine/hooks@9.0.0(react@19.2.4))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@mantine/hooks': 9.0.0(react@19.2.4) + '@mantine/store': 9.0.0(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-transition-group: 4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + + '@mantine/store@9.0.0(react@19.2.4)': + dependencies: + react: 19.2.4 '@napi-rs/wasm-runtime@1.1.2(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': dependencies: @@ -1020,135 +888,6 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-context@1.1.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-direction@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.14)(react@19.2.4) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.14)(react@19.2.4)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.4) - react: 19.2.4 - optionalDependencies: - '@types/react': 19.2.14 - '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1))(react@19.2.4)': dependencies: '@standard-schema/spec': 1.1.0 @@ -1219,75 +958,12 @@ snapshots: '@standard-schema/utils@0.3.0': {} - '@tabby_ai/hijri-converter@1.0.5': {} - - '@tailwindcss/node@4.2.2': + '@tabler/icons-react@3.41.1(react@19.2.4)': dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.20.1 - jiti: 2.6.1 - lightningcss: 1.32.0 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.2.2 + '@tabler/icons': 3.41.1 + react: 19.2.4 - '@tailwindcss/oxide-android-arm64@4.2.2': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.2.2': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.2.2': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.2.2': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.2.2': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.2.2': - optional: true - - '@tailwindcss/oxide@4.2.2': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.2 - '@tailwindcss/oxide-darwin-arm64': 4.2.2 - '@tailwindcss/oxide-darwin-x64': 4.2.2 - '@tailwindcss/oxide-freebsd-x64': 4.2.2 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 - '@tailwindcss/oxide-linux-x64-musl': 4.2.2 - '@tailwindcss/oxide-wasm32-wasi': 4.2.2 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - - '@tailwindcss/vite@4.2.2(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1))': - dependencies: - '@tailwindcss/node': 4.2.2 - '@tailwindcss/oxide': 4.2.2 - tailwindcss: 4.2.2 - vite: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1) + '@tabler/icons@3.41.1': {} '@tanstack/react-table@8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: @@ -1336,17 +1012,17 @@ snapshots: '@types/use-sync-external-store@0.0.6': {} - '@vitejs/plugin-react@6.0.1(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1))': + '@vitejs/plugin-react@6.0.1(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.8)))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 - vite: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1) + vite: 8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.8)) - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 + camelcase-css@2.0.1: {} clsx@2.1.1: {} + cssesc@3.0.0: {} + csstype@3.2.3: {} d3-array@3.2.4: @@ -1387,18 +1063,18 @@ snapshots: d3-timer@3.0.1: {} - date-fns-jalali@4.1.0-0: {} - date-fns@4.1.0: {} decimal.js-light@2.5.1: {} detect-libc@2.1.2: {} - enhanced-resolve@5.20.1: + detect-node-es@1.1.0: {} + + dom-helpers@5.2.1: dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.2 + '@babel/runtime': 7.29.2 + csstype: 3.2.3 es-toolkit@1.45.1: {} @@ -1411,7 +1087,7 @@ snapshots: fsevents@2.3.3: optional: true - graceful-fs@4.2.11: {} + get-nonce@1.0.1: {} immer@10.2.0: {} @@ -1419,7 +1095,10 @@ snapshots: internmap@2.0.3: {} - jiti@2.6.1: {} + jiti@2.6.1: + optional: true + + js-tokens@4.0.0: {} lightningcss-android-arm64@1.32.0: optional: true @@ -1470,41 +1149,77 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 - lucide-react@0.577.0(react@19.2.4): + loose-envify@1.4.0: dependencies: - react: 19.2.4 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + js-tokens: 4.0.0 nanoid@3.3.11: {} + object-assign@4.1.1: {} + picocolors@1.1.1: {} picomatch@4.0.4: {} + postcss-js@4.1.0(postcss@8.5.8): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.8 + + postcss-mixins@12.1.2(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-js: 4.1.0(postcss@8.5.8) + postcss-simple-vars: 7.0.1(postcss@8.5.8) + sugarss: 5.0.1(postcss@8.5.8) + tinyglobby: 0.2.15 + + postcss-nested@7.0.2(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + + postcss-preset-mantine@1.18.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-mixins: 12.1.2(postcss@8.5.8) + postcss-nested: 7.0.2(postcss@8.5.8) + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-simple-vars@7.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss@8.5.8: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - react-day-picker@9.14.0(react@19.2.4): + prop-types@15.8.1: dependencies: - '@date-fns/tz': 1.4.1 - '@tabby_ai/hijri-converter': 1.0.5 - date-fns: 4.1.0 - date-fns-jalali: 4.1.0-0 - react: 19.2.4 + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 react-dom@19.2.4(react@19.2.4): dependencies: react: 19.2.4 scheduler: 0.27.0 + react-is@16.13.1: {} + react-is@19.2.4: {} + react-number-format@5.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-redux@9.2.0(@types/react@19.2.14)(react@19.2.4)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 @@ -1514,6 +1229,42 @@ snapshots: '@types/react': 19.2.14 redux: 5.0.1 + react-remove-scroll-bar@2.3.8(@types/react@19.2.14)(react@19.2.4): + dependencies: + react: 19.2.4 + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + + react-remove-scroll@2.7.2(@types/react@19.2.14)(react@19.2.4): + dependencies: + react: 19.2.4 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.14)(react@19.2.4) + react-style-singleton: 2.2.3(@types/react@19.2.14)(react@19.2.4) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.14)(react@19.2.4) + use-sidecar: 1.1.3(@types/react@19.2.14)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.14 + + react-style-singleton@2.2.3(@types/react@19.2.14)(react@19.2.4): + dependencies: + get-nonce: 1.0.1 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + + react-transition-group@4.4.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + '@babel/runtime': 7.29.2 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react@19.2.4: {} recharts@3.8.1(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react-is@19.2.4)(react@19.2.4)(redux@5.0.1): @@ -1572,13 +1323,13 @@ snapshots: source-map-js@1.2.1: {} + sugarss@5.0.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + tabbable@6.4.0: {} - tailwind-merge@3.5.0: {} - - tailwindcss@4.2.2: {} - - tapable@2.3.2: {} + tagged-tag@1.0.0: {} tiny-invariant@1.3.3: {} @@ -1587,15 +1338,35 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - tslib@2.8.1: - optional: true + tslib@2.8.1: {} + + type-fest@5.5.0: + dependencies: + tagged-tag: 1.0.0 typescript@5.9.3: {} + use-callback-ref@1.3.3(@types/react@19.2.14)(react@19.2.4): + dependencies: + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + + use-sidecar@1.1.3(@types/react@19.2.14)(react@19.2.4): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.14 + use-sync-external-store@1.6.0(react@19.2.4): dependencies: react: 19.2.4 + util-deprecate@1.0.2: {} + victory-vendor@37.3.6: dependencies: '@types/d3-array': 3.2.2 @@ -1613,7 +1384,7 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1): + vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(jiti@2.6.1)(sugarss@5.0.1(postcss@8.5.8)): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -1623,6 +1394,7 @@ snapshots: optionalDependencies: fsevents: 2.3.3 jiti: 2.6.1 + sugarss: 5.0.1(postcss@8.5.8) transitivePeerDependencies: - '@emnapi/core' - '@emnapi/runtime' diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.cjs new file mode 100644 index 0000000..bfba0dd --- /dev/null +++ b/frontend/postcss.config.cjs @@ -0,0 +1,14 @@ +module.exports = { + plugins: { + 'postcss-preset-mantine': {}, + 'postcss-simple-vars': { + variables: { + 'mantine-breakpoint-xs': '36em', + 'mantine-breakpoint-sm': '48em', + 'mantine-breakpoint-md': '62em', + 'mantine-breakpoint-lg': '75em', + 'mantine-breakpoint-xl': '88em', + }, + }, + }, +}; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 69a156e..7e15919 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,4 +1,5 @@ import { useEffect, useState, useCallback } from 'react' +import { Center, Box, Stack, Text, Code, Alert, Loader } from '@mantine/core' import { DashboardShell } from './components/DashboardShell' import { useFilterState } from './hooks/useFilterState' import type { DashboardConfig } from './types' @@ -21,7 +22,7 @@ interface DashboardInfo { current: boolean } -const dummyConfig: DashboardConfig = { settings: { title: 'Dev Mode', refresh: '30s', width: 1280, height: 800, columns: 12 }, theme: 'dark', queries: {}, filters: {}, sections: [] } +const dummyConfig: DashboardConfig = { settings: { title: 'Dev Mode', refresh: '30s', width: 1280, height: 800, columns: 12, layout: 'scrollable' }, theme: 'dark', queries: {}, filters: {}, sections: [] } // Import bindings — they call window.go which only exists inside Wails WebView const bindings = await import('./wailsjs/go/main/App').catch(() => null) @@ -64,22 +65,26 @@ export default function App() { if (error) { return ( -
-
-

Dashboard Error

-
-            {error}
-          
-
-
+
+ + + + {error} + + + +
) } if (!config || switching) { return ( -
-

{switching ? 'Switching dashboard...' : 'Loading dashboard...'}

-
+
+ + + {switching ? 'Switching dashboard...' : 'Loading dashboard...'} + +
) } @@ -93,10 +98,6 @@ function DashboardInner({ config, dashboards, onSwitch }: { }) { const { values, setValue, reset } = useFilterState(config.filters ?? {}) - useEffect(() => { - document.documentElement.setAttribute('data-theme', config.theme || 'dark') - }, [config.theme]) - const getData = useCallback(async (widgetID: string, filters: FilterValues) => { return GetWidgetData(widgetID, filters) }, []) diff --git a/frontend/src/app.css b/frontend/src/app.css index a506abc..0d203c6 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -1,176 +1,3 @@ -@import "tailwindcss"; - -/* ========== DARK (default) — deep blue-grey ========== */ -:root, -[data-theme="dark"] { - --background: oklch(8% 0.015 260); - --foreground: oklch(95% 0.01 260); - --muted: oklch(18% 0.02 260); - --muted-foreground: oklch(60% 0.02 260); - --border: oklch(15% 0.01 260); - --primary: oklch(65% 0.22 260); - --primary-foreground: oklch(98% 0.01 260); - --secondary: oklch(20% 0.02 260); - --secondary-foreground: oklch(95% 0.01 260); - --accent: oklch(18% 0.03 260); - --accent-foreground: oklch(95% 0.01 260); - --destructive: oklch(55% 0.22 25); - --destructive-foreground: oklch(98% 0.01 260); - --card: oklch(11% 0.015 260); - --card-foreground: oklch(95% 0.01 260); - --popover: oklch(12% 0.015 260); - --popover-foreground: oklch(95% 0.01 260); - --ring: oklch(65% 0.22 260); - --input: oklch(22% 0.02 260); - --radius: 0.5rem; - --success: oklch(65% 0.2 145); - --success-foreground: oklch(98% 0.01 145); - --chart-1: #3b82f6; - --chart-2: #10b981; - --chart-3: #f59e0b; - --chart-4: #ef4444; - --chart-5: #8b5cf6; -} - -/* ========== EMERALD — rich green, gold accents ========== */ -[data-theme="emerald"] { - --background: oklch(6% 0.03 155); - --foreground: oklch(92% 0.03 155); - --muted: oklch(15% 0.04 155); - --muted-foreground: oklch(58% 0.04 155); - --border: oklch(13% 0.03 155); - --primary: oklch(70% 0.22 155); - --primary-foreground: oklch(10% 0.03 155); - --secondary: oklch(18% 0.04 155); - --secondary-foreground: oklch(90% 0.03 155); - --accent: oklch(16% 0.05 155); - --accent-foreground: oklch(90% 0.03 155); - --destructive: oklch(55% 0.22 25); - --destructive-foreground: oklch(98% 0.01 260); - --card: oklch(9% 0.03 155); - --card-foreground: oklch(92% 0.03 155); - --popover: oklch(10% 0.04 155); - --popover-foreground: oklch(92% 0.03 155); - --ring: oklch(70% 0.22 155); - --input: oklch(20% 0.04 155); - --success: oklch(70% 0.22 155); - --success-foreground: oklch(10% 0.03 155); - --chart-1: #10b981; - --chart-2: #f59e0b; - --chart-3: #06b6d4; - --chart-4: #8b5cf6; - --chart-5: #ec4899; -} - -/* ========== AMBER — warm dark, orange/amber accent ========== */ -[data-theme="amber"] { - --background: oklch(7% 0.02 55); - --foreground: oklch(93% 0.02 55); - --muted: oklch(16% 0.03 55); - --muted-foreground: oklch(58% 0.03 55); - --border: oklch(14% 0.025 55); - --primary: oklch(72% 0.2 65); - --primary-foreground: oklch(10% 0.02 55); - --secondary: oklch(18% 0.03 55); - --secondary-foreground: oklch(90% 0.02 55); - --accent: oklch(16% 0.04 55); - --accent-foreground: oklch(90% 0.02 55); - --destructive: oklch(55% 0.22 25); - --destructive-foreground: oklch(98% 0.01 260); - --card: oklch(10% 0.025 55); - --card-foreground: oklch(93% 0.02 55); - --popover: oklch(11% 0.03 55); - --popover-foreground: oklch(93% 0.02 55); - --ring: oklch(72% 0.2 65); - --input: oklch(20% 0.03 55); - --success: oklch(65% 0.2 145); - --success-foreground: oklch(98% 0.01 145); - --chart-1: #f59e0b; - --chart-2: #ef4444; - --chart-3: #3b82f6; - --chart-4: #10b981; - --chart-5: #ec4899; -} - -/* ========== ROSE — dark with pink/rose accent ========== */ -[data-theme="rose"] { - --background: oklch(7% 0.02 350); - --foreground: oklch(93% 0.015 350); - --muted: oklch(16% 0.03 350); - --muted-foreground: oklch(58% 0.025 350); - --border: oklch(14% 0.025 350); - --primary: oklch(65% 0.22 350); - --primary-foreground: oklch(98% 0.01 350); - --secondary: oklch(18% 0.03 350); - --secondary-foreground: oklch(90% 0.015 350); - --accent: oklch(16% 0.04 350); - --accent-foreground: oklch(90% 0.015 350); - --destructive: oklch(55% 0.22 25); - --destructive-foreground: oklch(98% 0.01 260); - --card: oklch(10% 0.025 350); - --card-foreground: oklch(93% 0.015 350); - --popover: oklch(11% 0.03 350); - --popover-foreground: oklch(93% 0.015 350); - --ring: oklch(65% 0.22 350); - --input: oklch(20% 0.03 350); - --success: oklch(65% 0.2 145); - --success-foreground: oklch(98% 0.01 145); - --chart-1: #ec4899; - --chart-2: #8b5cf6; - --chart-3: #3b82f6; - --chart-4: #f59e0b; - --chart-5: #10b981; -} - -/* ========== LIGHT — clean light theme ========== */ -[data-theme="light"] { - --background: oklch(98% 0.005 260); - --foreground: oklch(15% 0.01 260); - --muted: oklch(93% 0.01 260); - --muted-foreground: oklch(45% 0.01 260); - --border: oklch(88% 0.01 260); - --primary: oklch(50% 0.22 260); - --primary-foreground: oklch(98% 0.01 260); - --secondary: oklch(94% 0.01 260); - --secondary-foreground: oklch(20% 0.01 260); - --accent: oklch(95% 0.01 260); - --accent-foreground: oklch(20% 0.01 260); - --destructive: oklch(50% 0.22 25); - --destructive-foreground: oklch(98% 0.01 260); - --card: oklch(100% 0 0); - --card-foreground: oklch(15% 0.01 260); - --popover: oklch(100% 0 0); - --popover-foreground: oklch(15% 0.01 260); - --ring: oklch(50% 0.22 260); - --input: oklch(88% 0.01 260); - --success: oklch(50% 0.2 145); - --success-foreground: oklch(98% 0.01 145); - --chart-1: #2563eb; - --chart-2: #059669; - --chart-3: #d97706; - --chart-4: #dc2626; - --chart-5: #7c3aed; -} - body { - background-color: var(--background); - color: var(--foreground); - font-family: 'Geist Variable', system-ui, -apple-system, sans-serif; -webkit-font-smoothing: antialiased; } - -/* Remove card borders for seamless look on dark themes */ -[data-theme="dark"] [data-slot="card"], -[data-theme="emerald"] [data-slot="card"], -[data-theme="amber"] [data-slot="card"], -[data-theme="rose"] [data-slot="card"] { - border: none; - box-shadow: none; -} - -/* Light theme keeps subtle card shadows */ -[data-theme="light"] [data-slot="card"] { - border: 1px solid var(--border); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06); -} - diff --git a/frontend/src/components/DashboardShell.tsx b/frontend/src/components/DashboardShell.tsx index 423a61f..c79693e 100644 --- a/frontend/src/components/DashboardShell.tsx +++ b/frontend/src/components/DashboardShell.tsx @@ -1,6 +1,7 @@ +import { Box, Group, Text, Stack } from '@mantine/core' import { FilterBar } from './FilterBar' import { Section } from './Section' -import { SimpleSelect } from '@fn_library' +import { Select } from '@fn_library' import type { DashboardConfig } from '../types' import type { FilterValues } from '../hooks/useFilterState' @@ -23,40 +24,57 @@ interface DashboardShellProps { } export function DashboardShell({ config, filters, onFilterChange, onFilterReset, getData, dashboards, onSwitchDashboard }: DashboardShellProps) { - return ( -
- {/* Header */} -
-
-

{config.settings.title}

- {dashboards && dashboards.length > 1 && onSwitchDashboard && ( - d.current)?.file ?? ''} - onValueChange={(v) => onSwitchDashboard(v)} - options={dashboards.map(d => ({ value: d.file, label: `${d.title} (${d.theme})` }))} - /> - )} -
- -
+ const isSingleView = config.settings.layout === 'single_view' - {/* Sections */} - {(config.sections ?? []).map(section => ( -
- ))} -
+ return ( + + + {/* Header */} + + + {config.settings.title} + {dashboards && dashboards.length > 1 && onSwitchDashboard && ( + onChange(id, v ?? '')} + data={def.options?.map(opt => ({ value: opt.value, label: opt.label })) ?? []} + size="sm" /> - + ) } @@ -67,24 +66,21 @@ function DateRangeFilter({ id, def, value, onChange }: { id: string; def: Filter const currentFrom = value?.from ?? '' return ( -
- -
+ + {def.label} + {presets.map((preset: FilterPreset) => ( - + ))} -
-
+
+ ) } @@ -105,15 +101,15 @@ function TextFilter({ id, def, value, onChange }: { id: string; def: FilterDef; }, [id, onChange, debounce]) return ( -
- - + {def.label} + -
+ ) } diff --git a/frontend/src/components/Section.tsx b/frontend/src/components/Section.tsx index dba559a..1762d9e 100644 --- a/frontend/src/components/Section.tsx +++ b/frontend/src/components/Section.tsx @@ -1,5 +1,6 @@ import { useState } from 'react' -import { ChevronDown, ChevronRight } from 'lucide-react' +import { Box, UnstyledButton, Group, Text } from '@mantine/core' +import { IconChevronDown, IconChevronRight } from '@tabler/icons-react' import { WidgetRenderer } from './WidgetRenderer' import type { SectionDef, QueryDef } from '../types' import type { FilterValues } from '../hooks/useFilterState' @@ -10,42 +11,47 @@ interface SectionProps { filters: FilterValues globalColumns: number getData: (widgetID: string, filters: FilterValues) => Promise[]> + fillHeight?: boolean } -export function Section({ section, queries, filters, globalColumns, getData }: SectionProps) { +export function Section({ section, queries, filters, globalColumns, getData, fillHeight }: SectionProps) { const [collapsed, setCollapsed] = useState(false) const columns = section.columns || globalColumns return ( -
- + + {section.collapsible && ( + collapsed + ? + : + )} + + {section.title} + + + {!collapsed && ( -
{section.widgets.map(widget => ( -
-
+ ))} -
+ )} -
+
) } diff --git a/frontend/src/components/WidgetRenderer.tsx b/frontend/src/components/WidgetRenderer.tsx index 40b4315..8ee0638 100644 --- a/frontend/src/components/WidgetRenderer.tsx +++ b/frontend/src/components/WidgetRenderer.tsx @@ -1,4 +1,5 @@ import { useEffect, useState, useCallback, useRef } from 'react' +import { Box, Text } from '@mantine/core' import { Card, CardContent, CardHeader, CardTitle } from '@fn_library' import { getWidget } from './widget-registry' import type { WidgetDef, QueryDef } from '../types' @@ -71,23 +72,34 @@ export function WidgetRenderer({ widget, queryDef, filters, getData }: WidgetRen return ( - {widget.title} + {widget.title} -

+ Unknown widget type: {widget.type} -

+
) } return ( -
+ - + {countdown}s - -
+ + ) } diff --git a/frontend/src/components/widgets/AreaChartWidget.tsx b/frontend/src/components/widgets/AreaChartWidget.tsx index 06be241..75c934c 100644 --- a/frontend/src/components/widgets/AreaChartWidget.tsx +++ b/frontend/src/components/widgets/AreaChartWidget.tsx @@ -1,13 +1,14 @@ +import { Center, Text, Loader } from '@mantine/core' import { Card, CardContent, CardHeader, CardTitle } from '@fn_library' import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, - Legend, ResponsiveContainer, + Legend, } from 'recharts' import type { WidgetProps } from '../../types' const COLORS = [ - 'var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)', - 'var(--chart-4)', 'var(--chart-5)', 'var(--chart-6, #ec4899)', + '#3b82f6', '#10b981', '#f59e0b', + '#ef4444', '#8b5cf6', '#ec4899', ] export function AreaChartWidget({ widget, data, loading, error }: WidgetProps) { @@ -25,47 +26,46 @@ export function AreaChartWidget({ widget, data, loading, error }: WidgetProps) { : yKey ? [{ dataKey: yKey, name: yKey, color: COLORS[0] }] : [] return ( - + - - {widget.title} + + {widget.title} {loading && !data ? ( -
Loading...
+
) : error ? ( -
{error.message}
+
{error.message}
) : ( - - - {options.show_grid !== false && } - - - - {!!options.show_legend && } - - {areas.map(area => ( - - - - - ))} - + + {options.show_grid !== false && } + + + + {!!options.show_legend && } + {areas.map(area => ( - + + + + ))} - - + + {areas.map(area => ( + + ))} + )}
diff --git a/frontend/src/components/widgets/BarChartWidget.tsx b/frontend/src/components/widgets/BarChartWidget.tsx index 85cb5a0..615713b 100644 --- a/frontend/src/components/widgets/BarChartWidget.tsx +++ b/frontend/src/components/widgets/BarChartWidget.tsx @@ -1,13 +1,14 @@ +import { Center, Text, Loader } from '@mantine/core' import { Card, CardContent, CardHeader, CardTitle } from '@fn_library' import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, - Legend, ResponsiveContainer, + Legend, } from 'recharts' import type { WidgetProps } from '../../types' const COLORS = [ - 'var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)', - 'var(--chart-4)', 'var(--chart-5)', 'var(--chart-6, #ec4899)', + '#3b82f6', '#10b981', '#f59e0b', + '#ef4444', '#8b5cf6', '#ec4899', ] export function BarChartWidget({ widget, data, loading, error }: WidgetProps) { @@ -27,51 +28,52 @@ export function BarChartWidget({ widget, data, loading, error }: WidgetProps) { const isHorizontal = !!options.horizontal return ( - - - - {widget.title} + + + + {widget.title} {loading && !data ? ( -
Loading...
+
) : error ? ( -
{error.message}
+
{error.message}
) : ( - - - {options.show_grid !== false && } - {isHorizontal ? ( - <> - - - - ) : ( - <> - - - - )} - - {!!options.show_legend && } - {bars.map(bar => ( - - ))} - - + + {options.show_grid !== false && } + {isHorizontal ? ( + <> + + + + ) : ( + <> + + + + )} + + {!!options.show_legend && } + {bars.map(bar => ( + + ))} + )}
diff --git a/frontend/src/components/widgets/KPIWidget.tsx b/frontend/src/components/widgets/KPIWidget.tsx index 0d66157..466f88d 100644 --- a/frontend/src/components/widgets/KPIWidget.tsx +++ b/frontend/src/components/widgets/KPIWidget.tsx @@ -55,7 +55,7 @@ export function KPIWidget({ widget, data, loading }: WidgetProps) { /> ) : undefined} size="default" - className="border-0 shadow-none" + style={{ border: 'none', boxShadow: 'none' }} /> ) } diff --git a/frontend/src/components/widgets/LineChartWidget.tsx b/frontend/src/components/widgets/LineChartWidget.tsx index 10d18a7..f1e4a5e 100644 --- a/frontend/src/components/widgets/LineChartWidget.tsx +++ b/frontend/src/components/widgets/LineChartWidget.tsx @@ -1,13 +1,14 @@ +import { Center, Text, Loader } from '@mantine/core' import { Card, CardContent, CardHeader, CardTitle } from '@fn_library' import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, - Legend, Brush, ResponsiveContainer, + Legend, Brush, } from 'recharts' import type { WidgetProps } from '../../types' const COLORS = [ - 'var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)', - 'var(--chart-4)', 'var(--chart-5)', 'var(--chart-6, #ec4899)', + '#3b82f6', '#10b981', '#f59e0b', + '#ef4444', '#8b5cf6', '#ec4899', ] export function LineChartWidget({ widget, data, loading, error }: WidgetProps) { @@ -25,40 +26,39 @@ export function LineChartWidget({ widget, data, loading, error }: WidgetProps) { : yKey ? [{ dataKey: yKey, name: yKey, stroke: COLORS[0] }] : [] return ( - + - - {widget.title} + + {widget.title} {loading && !data ? ( -
Loading...
+
) : error ? ( -
{error.message}
+
{error.message}
) : ( - - - {options.show_grid !== false && } - - - - {!!options.show_legend && } - {lines.map(line => ( - - ))} - {!!options.zoomable && } - - + + {options.show_grid !== false && } + + + + {!!options.show_legend && } + {lines.map(line => ( + + ))} + {!!options.zoomable && } + )}
diff --git a/frontend/src/components/widgets/PieChartWidget.tsx b/frontend/src/components/widgets/PieChartWidget.tsx index d000dc3..5175f7f 100644 --- a/frontend/src/components/widgets/PieChartWidget.tsx +++ b/frontend/src/components/widgets/PieChartWidget.tsx @@ -1,14 +1,15 @@ +import { Center, Text, Loader } from '@mantine/core' import { Card, CardContent, CardHeader, CardTitle } from '@fn_library' import { - PieChart, Pie, Cell, Tooltip, Legend, ResponsiveContainer, + PieChart, Pie, Cell, Tooltip, Legend, } from 'recharts' import type { PieLabelRenderProps } from 'recharts' import type { WidgetProps } from '../../types' const COLORS = [ - 'var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)', - 'var(--chart-4)', 'var(--chart-5)', 'var(--chart-6, #ec4899)', - 'var(--chart-7, #06b6d4)', 'var(--chart-8, #f97316)', + '#3b82f6', '#10b981', '#f59e0b', + '#ef4444', '#8b5cf6', '#ec4899', + '#06b6d4', '#f97316', ] function renderLabel(props: PieLabelRenderProps): string { @@ -30,47 +31,46 @@ export function PieChartWidget({ widget, data, loading, error }: WidgetProps) { })) return ( - - - - {widget.title} + + + + {widget.title} {loading && !data ? ( -
Loading...
+
) : error ? ( -
{error.message}
+
{error.message}
) : ( - - - - {pieData.map((_, i) => ( - - ))} - - - {options.show_legend !== false && ( - - )} - - + + + {pieData.map((_, i) => ( + + ))} + + + {options.show_legend !== false && ( + + )} + )}
diff --git a/frontend/src/components/widgets/SparklineWidget.tsx b/frontend/src/components/widgets/SparklineWidget.tsx index ea1bf7b..ccdb18b 100644 --- a/frontend/src/components/widgets/SparklineWidget.tsx +++ b/frontend/src/components/widgets/SparklineWidget.tsx @@ -1,3 +1,4 @@ +import { Center, Text, Loader } from '@mantine/core' import { Card, CardContent } from '@fn_library' import { Sparkline } from '@fn_library' import type { WidgetProps } from '../../types' @@ -10,11 +11,11 @@ export function SparklineWidget({ widget, data, loading }: WidgetProps) { const values = (data ?? []).map(row => Number(row[valueKey]) || 0) return ( - - -

{widget.title}

+ + + {widget.title} {loading && values.length === 0 ? ( -
Loading...
+
) : ( - - - {widget.title} + + + + {widget.title} {loading && !data ? ( -
Loading...
+
) : error ? ( -
{error.message}
+
{error.message}
) : ( -
- - - + +
+ + {effectiveColumns.map(col => ( - + ))} - - - + + + {(data ?? []).map((row, i) => ( - + {effectiveColumns.map(col => ( - + ))} - + ))} - -
+ {col.label} -
{formatCell(row[col.key], col.format)} -
+ + {(!data || data.length === 0) && ( -

No data

+ No data )} -
+ )}
@@ -92,7 +107,7 @@ export function TableWidget({ widget, data, loading, error }: WidgetProps) { } function formatCell(value: unknown, format?: string): string { - if (value == null) return '—' + if (value == null) return '\u2014' if (!format) return String(value) const num = Number(value) diff --git a/frontend/src/env.d.ts b/frontend/src/env.d.ts index 1b81eff..81596de 100644 --- a/frontend/src/env.d.ts +++ b/frontend/src/env.d.ts @@ -3,6 +3,7 @@ // Types for @fn_library — resolved at build time via Vite alias to frontend/functions/ui/ declare module '@fn_library' { import type { FC } from 'react' + import type { SelectProps as MantineSelectProps } from '@mantine/core' export const Card: FC export const CardContent: FC export const CardHeader: FC @@ -13,6 +14,6 @@ declare module '@fn_library' { export const Button: FC export const Input: FC export const Skeleton: FC - export interface SimpleSelectOption { value: string; label: string; disabled?: boolean } - export function SimpleSelect(props: { value: string; onValueChange: (value: string) => void; options: SimpleSelectOption[]; placeholder?: string; disabled?: boolean; size?: 'sm' | 'default'; className?: string }): React.ReactElement + export interface SelectProps extends MantineSelectProps {} + export function Select(props: SelectProps): React.ReactElement } diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 7d02351..a98268c 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,10 +1,39 @@ +import '@mantine/core/styles.css' +import '@mantine/charts/styles.css' +import '@mantine/notifications/styles.css' + import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' +import { MantineProvider, createTheme, type MantineColorsTuple } from '@mantine/core' +import { Notifications } from '@mantine/notifications' import './app.css' import App from './App' +const brand: MantineColorsTuple = [ + '#e5f0ff', + '#cddeff', + '#9abbff', + '#6495ff', + '#3874fe', + '#1d60fe', + '#0953ff', + '#0046e4', + '#003dcd', + '#0034b5', +] + +const theme = createTheme({ + colors: { brand }, + primaryColor: 'brand', + defaultRadius: 'md', + fontFamily: "'Geist Variable', system-ui, -apple-system, sans-serif", +}) + createRoot(document.getElementById('root')!).render( - + + + + , ) diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 10154f1..d3af995 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -14,6 +14,7 @@ export interface Settings { width: number height: number columns: number + layout: 'scrollable' | 'single_view' } export interface QueryDef { diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index afa62ca..e2ce3f2 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,11 +1,9 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' import { resolve } from 'path' - export default defineConfig({ - plugins: [react(), tailwindcss()], + plugins: [react()], resolve: { alias: { '@': resolve(__dirname, './src'), @@ -14,6 +12,9 @@ export default defineConfig({ }, dedupe: ['react', 'react-dom'], }, + css: { + postcss: resolve(__dirname, './postcss.config.cjs'), + }, server: { port: 5173, }, diff --git a/main.go b/main.go index c7a3b90..5e98845 100644 --- a/main.go +++ b/main.go @@ -122,9 +122,9 @@ func main() { engine := NewQueryEngine(cfg, pool) app := NewApp(cfg, engine, pool, dashDir, *dashboardPath) - log.Printf("starting wails — title=%q width=%d height=%d dashDir=%q", cfg.Settings.Title, cfg.Settings.Width, cfg.Settings.Height, dashDir) + log.Printf("starting wails — title=%q width=%d height=%d layout=%q dashDir=%q", cfg.Settings.Title, cfg.Settings.Width, cfg.Settings.Height, cfg.Settings.Layout, dashDir) - runErr := wails.Run(&options.App{ + wailsOpts := &options.App{ Title: cfg.Settings.Title, Width: cfg.Settings.Width, Height: cfg.Settings.Height, @@ -136,7 +136,17 @@ func main() { Bind: []interface{}{ app, }, - }) + } + + if cfg.Settings.Layout == "single_view" { + wailsOpts.MaxWidth = cfg.Settings.Width + wailsOpts.MaxHeight = cfg.Settings.Height + wailsOpts.MinWidth = cfg.Settings.Width + wailsOpts.MinHeight = cfg.Settings.Height + wailsOpts.DisableResize = true + } + + runErr := wails.Run(wailsOpts) if runErr != nil { log.Printf("ERROR wails.Run: %v", runErr)