diff --git a/biome.json b/biome.json
index c96170e..87b3337 100644
--- a/biome.json
+++ b/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/2.3.7/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
@@ -44,6 +44,11 @@
}
}
},
+ "css": {
+ "parser": {
+ "tailwindDirectives": true
+ }
+ },
"files": {
"includes": [
"client/**/*",
diff --git a/client/package.json b/client/package.json
index 1fdc78f..ff61367 100644
--- a/client/package.json
+++ b/client/package.json
@@ -32,16 +32,19 @@
"@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
- "@semoss/sdk": "1.0.0-beta.31",
+ "@semoss/sdk": "1.0.0-beta.32",
"@tailwindcss/postcss": "^4.1.17",
+ "@tailwindcss/vite": "^4.1.17",
"autoprefixer": "^10.4.22",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-react": "^0.553.0",
+ "next-themes": "^0.4.6",
"postcss": "^8.5.6",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^7.9.6",
+ "sonner": "^2.0.7",
"tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
"tw-animate-css": "^1.4.0"
@@ -52,6 +55,6 @@
"@types/react-dom": "^18.3.7",
"@vitejs/plugin-react": "^5.1.1",
"typescript": "^5.9.3",
- "vite": "^7.2.4"
+ "vite": "^7.2.6"
}
}
diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml
index 1d4505c..4416840 100644
--- a/client/pnpm-lock.yaml
+++ b/client/pnpm-lock.yaml
@@ -87,11 +87,14 @@ importers:
specifier: ^1.2.8
version: 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@semoss/sdk':
- specifier: 1.0.0-beta.31
- version: 1.0.0-beta.31(react@18.3.1)
+ specifier: 1.0.0-beta.32
+ version: 1.0.0-beta.32(react@18.3.1)
'@tailwindcss/postcss':
specifier: ^4.1.17
version: 4.1.17
+ '@tailwindcss/vite':
+ specifier: ^4.1.17
+ version: 4.1.17(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0))
autoprefixer:
specifier: ^10.4.22
version: 10.4.22(postcss@8.5.6)
@@ -104,6 +107,9 @@ importers:
lucide-react:
specifier: ^0.553.0
version: 0.553.0(react@18.3.1)
+ next-themes:
+ specifier: ^0.4.6
+ version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
postcss:
specifier: ^8.5.6
version: 8.5.6
@@ -116,6 +122,9 @@ importers:
react-router-dom:
specifier: ^7.9.6
version: 7.9.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
+ sonner:
+ specifier: ^2.0.7
+ version: 2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
tailwind-merge:
specifier: ^3.4.0
version: 3.4.0
@@ -137,13 +146,13 @@ importers:
version: 18.3.7(@types/react@18.3.27)
'@vitejs/plugin-react':
specifier: ^5.1.1
- version: 5.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0))
+ version: 5.1.1(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0))
typescript:
specifier: ^5.9.3
version: 5.9.3
vite:
- specifier: ^7.2.4
- version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)
+ specifier: ^7.2.6
+ version: 7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)
packages:
@@ -1180,8 +1189,8 @@ packages:
cpu: [x64]
os: [win32]
- '@semoss/sdk@1.0.0-beta.31':
- resolution: {integrity: sha512-JIo4TvJvYhkw1aa3DsQ1rEC4zJXF9Qp7ImcdyrRTZpTXC1mxzFB0tqUC4hCGSwrbXN79q20Qr+nxo2fyO7H2Rg==}
+ '@semoss/sdk@1.0.0-beta.32':
+ resolution: {integrity: sha512-645fPMDQZxwbmzwXHlJi/JhxHT/upMRQHpHd9wrm3cfgdfjvG5MDDdPGGUlhk5xFPKANUsjnTx8WNQv9QzqvVQ==}
peerDependencies:
react: 18.3.1
peerDependenciesMeta:
@@ -1276,6 +1285,11 @@ packages:
'@tailwindcss/postcss@4.1.17':
resolution: {integrity: sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==}
+ '@tailwindcss/vite@4.1.17':
+ resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==}
+ peerDependencies:
+ vite: ^5.2.0 || ^6 || ^7
+
'@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@@ -1327,8 +1341,8 @@ packages:
peerDependencies:
postcss: ^8.1.0
- baseline-browser-mapping@2.8.31:
- resolution: {integrity: sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==}
+ baseline-browser-mapping@2.8.32:
+ resolution: {integrity: sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==}
hasBin: true
browserslist@4.28.0:
@@ -1355,8 +1369,8 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
- cookie@1.0.2:
- resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
+ cookie@1.1.1:
+ resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
engines: {node: '>=18'}
csstype@3.2.3:
@@ -1378,8 +1392,8 @@ packages:
detect-node-es@1.1.0:
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
- electron-to-chromium@1.5.260:
- resolution: {integrity: sha512-ov8rBoOBhVawpzdre+Cmz4FB+y66Eqrk6Gwqd8NGxuhv99GQ8XqMAr351KEkOt7gukXWDg6gJWEMKgL2RLMPtA==}
+ electron-to-chromium@1.5.263:
+ resolution: {integrity: sha512-DrqJ11Knd+lo+dv+lltvfMDLU27g14LMdH2b0O3Pio4uk0x+z7OR+JrmyacTPN2M8w3BrZ7/RTwG3R9B7irPlg==}
enhanced-resolve@5.18.3:
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
@@ -1532,6 +1546,12 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ next-themes@0.4.6:
+ resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
+ peerDependencies:
+ react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+
node-releases@2.0.27:
resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==}
@@ -1572,8 +1592,8 @@ packages:
'@types/react':
optional: true
- react-remove-scroll@2.7.1:
- resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==}
+ react-remove-scroll@2.7.2:
+ resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': '*'
@@ -1628,6 +1648,12 @@ packages:
set-cookie-parser@2.7.2:
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
+ sonner@2.0.7:
+ resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==}
+ peerDependencies:
+ react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+ react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
+
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
@@ -1703,8 +1729,8 @@ packages:
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- vite@7.2.4:
- resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==}
+ vite@7.2.6:
+ resolution: {integrity: sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -2141,7 +2167,7 @@ snapshots:
aria-hidden: 1.2.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- react-remove-scroll: 2.7.1(@types/react@18.3.27)(react@18.3.1)
+ react-remove-scroll: 2.7.2(@types/react@18.3.27)(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.27
'@types/react-dom': 18.3.7(@types/react@18.3.27)
@@ -2251,7 +2277,7 @@ snapshots:
aria-hidden: 1.2.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- react-remove-scroll: 2.7.1(@types/react@18.3.27)(react@18.3.1)
+ react-remove-scroll: 2.7.2(@types/react@18.3.27)(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.27
'@types/react-dom': 18.3.7(@types/react@18.3.27)
@@ -2314,7 +2340,7 @@ snapshots:
aria-hidden: 1.2.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- react-remove-scroll: 2.7.1(@types/react@18.3.27)(react@18.3.1)
+ react-remove-scroll: 2.7.2(@types/react@18.3.27)(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.27
'@types/react-dom': 18.3.7(@types/react@18.3.27)
@@ -2461,7 +2487,7 @@ snapshots:
aria-hidden: 1.2.6
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
- react-remove-scroll: 2.7.1(@types/react@18.3.27)(react@18.3.1)
+ react-remove-scroll: 2.7.2(@types/react@18.3.27)(react@18.3.1)
optionalDependencies:
'@types/react': 18.3.27
'@types/react-dom': 18.3.7(@types/react@18.3.27)
@@ -2725,7 +2751,7 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.53.3':
optional: true
- '@semoss/sdk@1.0.0-beta.31(react@18.3.1)':
+ '@semoss/sdk@1.0.0-beta.32(react@18.3.1)':
optionalDependencies:
react: 18.3.1
@@ -2798,6 +2824,13 @@ snapshots:
postcss: 8.5.6
tailwindcss: 4.1.17
+ '@tailwindcss/vite@4.1.17(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0))':
+ dependencies:
+ '@tailwindcss/node': 4.1.17
+ '@tailwindcss/oxide': 4.1.17
+ tailwindcss: 4.1.17
+ vite: 7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)
+
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.28.5
@@ -2836,7 +2869,7 @@ snapshots:
'@types/prop-types': 15.7.15
csstype: 3.2.3
- '@vitejs/plugin-react@5.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0))':
+ '@vitejs/plugin-react@5.1.1(vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5)
@@ -2844,7 +2877,7 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-beta.47
'@types/babel__core': 7.20.5
react-refresh: 0.18.0
- vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)
+ vite: 7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)
transitivePeerDependencies:
- supports-color
@@ -2865,13 +2898,13 @@ snapshots:
postcss: 8.5.6
postcss-value-parser: 4.2.0
- baseline-browser-mapping@2.8.31: {}
+ baseline-browser-mapping@2.8.32: {}
browserslist@4.28.0:
dependencies:
- baseline-browser-mapping: 2.8.31
+ baseline-browser-mapping: 2.8.32
caniuse-lite: 1.0.30001757
- electron-to-chromium: 1.5.260
+ electron-to-chromium: 1.5.263
node-releases: 2.0.27
update-browserslist-db: 1.1.4(browserslist@4.28.0)
@@ -2891,7 +2924,7 @@ snapshots:
convert-source-map@2.0.0: {}
- cookie@1.0.2: {}
+ cookie@1.1.1: {}
csstype@3.2.3: {}
@@ -2903,7 +2936,7 @@ snapshots:
detect-node-es@1.1.0: {}
- electron-to-chromium@1.5.260: {}
+ electron-to-chromium@1.5.263: {}
enhanced-resolve@5.18.3:
dependencies:
@@ -3033,6 +3066,11 @@ snapshots:
nanoid@3.3.11: {}
+ next-themes@0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+
node-releases@2.0.27: {}
normalize-range@0.1.2: {}
@@ -3065,7 +3103,7 @@ snapshots:
optionalDependencies:
'@types/react': 18.3.27
- react-remove-scroll@2.7.1(@types/react@18.3.27)(react@18.3.1):
+ react-remove-scroll@2.7.2(@types/react@18.3.27)(react@18.3.1):
dependencies:
react: 18.3.1
react-remove-scroll-bar: 2.3.8(@types/react@18.3.27)(react@18.3.1)
@@ -3084,7 +3122,7 @@ snapshots:
react-router@7.9.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
- cookie: 1.0.2
+ cookie: 1.1.1
react: 18.3.1
set-cookie-parser: 2.7.2
optionalDependencies:
@@ -3138,6 +3176,11 @@ snapshots:
set-cookie-parser@2.7.2: {}
+ sonner@2.0.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ dependencies:
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+
source-map-js@1.2.1: {}
source-map-support@0.5.21:
@@ -3201,7 +3244,7 @@ snapshots:
dependencies:
react: 18.3.1
- vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0):
+ vite@7.2.6(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.3)
diff --git a/client/src/App.tsx b/client/src/App.tsx
index 8809b9f..b730c71 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -1,5 +1,6 @@
import { Env } from "@semoss/sdk";
import { InsightProvider } from "@semoss/sdk/react";
+import { Toaster } from "sonner";
import { AppContextProvider } from "./contexts";
import { Router } from "./pages";
@@ -26,6 +27,9 @@ export const App = () => {
This component is custom to this project, and can be edited in Router.tsx */}
+
+ {/* Toaster for displaying toast notifications */}
+
);
};
diff --git a/client/src/components/base/LoadingScreen.tsx b/client/src/components/base/LoadingScreen.tsx
index 46b996a..aa7bbc1 100644
--- a/client/src/components/base/LoadingScreen.tsx
+++ b/client/src/components/base/LoadingScreen.tsx
@@ -1,12 +1,21 @@
import { Spinner } from "@/components/ui/spinner";
+interface LoadingScreenProps {
+ /** Whether to overlay the loading screen on top of existing content */
+ overlay?: boolean;
+}
+
/**
* Returns a loading screen with a centered circular progress indicator
*
* @component
*/
-export const LoadingScreen = () => (
-
+export const LoadingScreen = ({ overlay = false }: LoadingScreenProps) => (
+
);
diff --git a/client/src/components/base/MainNavigation.tsx b/client/src/components/base/MainNavigation.tsx
index 6cacc8a..aa0e44d 100644
--- a/client/src/components/base/MainNavigation.tsx
+++ b/client/src/components/base/MainNavigation.tsx
@@ -1,5 +1,4 @@
import { useInsight } from "@semoss/sdk/react";
-import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { SemossBlueLogo } from "@/assets";
import { Button } from "@/components/ui/button";
@@ -25,11 +24,6 @@ export const MainNavigation = () => {
const { isAuthorized } = useInsight(); // Read whether the user is authorized, so that buttons only work if they are
const navigate = useNavigate();
- /**
- * State
- */
- const [userMenuOpen, setUserMenuOpen] = useState(false);
-
return (
@@ -77,12 +71,7 @@ export const MainNavigation = () => {
{/* If the user is logged in, allow them to see their info */}
- {isAuthorized && (
-
- )}
+ {isAuthorized &&
}
);
diff --git a/client/src/components/base/MessageSnackbar.tsx b/client/src/components/base/MessageSnackbar.tsx
deleted file mode 100644
index afffd87..0000000
--- a/client/src/components/base/MessageSnackbar.tsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import { AlertCircle, AlertTriangle, CheckCircle, Info, X } from "lucide-react";
-import { useEffect } from "react";
-import { Alert } from "@/components/ui/alert";
-import { Button } from "@/components/ui/button";
-import { useAppContext } from "@/contexts";
-
-export interface MessageSnackbarProps {
- message: string;
- severity: "success" | "error" | "info" | "warning";
- open: boolean;
-}
-
-/**
- * Renders a snackbar for displaying messages, typically used for error or success notifications
- *
- * @component
- */
-export const MessageSnackbar = ({
- open,
- severity,
- message,
-}: MessageSnackbarProps) => {
- const { setMessageSnackbarProps } = useAppContext();
-
- /**
- * Functions
- */
- const handleClose = () => {
- setMessageSnackbarProps((prev) => ({
- ...prev,
- open: false,
- }));
- };
-
- // Auto close after 5 seconds
- useEffect(() => {
- if (open) {
- const timer = setTimeout(() => {
- setMessageSnackbarProps((prev) => ({
- ...prev,
- open: false,
- }));
- }, 5000);
- return () => clearTimeout(timer);
- }
- }, [open, setMessageSnackbarProps]);
-
- const getIcon = () => {
- switch (severity) {
- case "success":
- return ;
- case "error":
- return ;
- case "warning":
- return ;
- default:
- return ;
- }
- };
-
- const getVariant = () => {
- switch (severity) {
- case "error":
- return "destructive" as const;
- default:
- return "default" as const;
- }
- };
-
- const getColors = () => {
- switch (severity) {
- case "success":
- return "border-green-500/50 text-green-600 bg-green-50 dark:border-green-500 [&>svg]:text-green-600";
- case "warning":
- return "border-yellow-500/50 text-yellow-600 bg-yellow-50 dark:border-yellow-500 [&>svg]:text-yellow-600";
- case "info":
- return "border-blue-500/50 text-blue-600 bg-blue-50 dark:border-blue-500 [&>svg]:text-blue-600";
- default:
- return "";
- }
- };
-
- if (!open) return null;
-
- return (
-
-
- {getIcon()}
- {message}
-
-
-
-
-
- );
-};
diff --git a/client/src/components/base/UserProfileMenu.tsx b/client/src/components/base/UserProfileMenu.tsx
index c21c5eb..6019857 100644
--- a/client/src/components/base/UserProfileMenu.tsx
+++ b/client/src/components/base/UserProfileMenu.tsx
@@ -9,42 +9,26 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { useAppContext } from "@/contexts";
-import { useLoadingState } from "@/hooks";
-
-export interface UserProfileMenuProps {
- open: boolean;
- onOpenChange?: (open: boolean) => void;
-}
/**
* Renders a menu showing users their name and allowing them to log out
*
* @component
*/
-export const UserProfileMenu = ({
- open,
- onOpenChange,
-}: UserProfileMenuProps) => {
+export const UserProfileMenu = () => {
const { logout, userLoginName } = useAppContext();
- /**
- * State
- */
- const [isLogoutLoading, setIsLogoutLoading] = useLoadingState();
-
/**
* Functions
*/
const handleLogout = async () => {
- const loadingKey = setIsLogoutLoading(true);
const success = await logout();
if (success) localStorage.clear();
window.location.reload();
- setIsLogoutLoading(false, loadingKey);
};
return (
-
+
@@ -56,12 +40,9 @@ export const UserProfileMenu = ({
{userLoginName}
-
+
- {isLogoutLoading ? "Logging out..." : "Logout"}
+ Logout
diff --git a/client/src/components/base/index.ts b/client/src/components/base/index.ts
index 75b5cfc..65eb876 100644
--- a/client/src/components/base/index.ts
+++ b/client/src/components/base/index.ts
@@ -1,3 +1,2 @@
export * from "./LoadingScreen";
export * from "./MainNavigation";
-export * from "./MessageSnackbar";
diff --git a/client/src/components/examples/ExampleComponent.tsx b/client/src/components/examples/ExampleComponent.tsx
index 224e57a..c3cb71e 100644
--- a/client/src/components/examples/ExampleComponent.tsx
+++ b/client/src/components/examples/ExampleComponent.tsx
@@ -1,3 +1,4 @@
+import { useInsight } from "@semoss/sdk/react";
import { useState } from "react";
import { Input } from "@/components/ui/input";
import { useLoadingPixel } from "@/hooks";
@@ -16,6 +17,7 @@ export const ExampleComponent = () => {
/**
* Library hooks
*/
+ const { tool } = useInsight();
const [helloUserResponse, isLoadingHelloUser] =
useLoadingPixel("HelloUser()");
const [callPythonResponse, isLoadingCallPython] = useLoadingPixel(
@@ -68,6 +70,16 @@ export const ExampleComponent = () => {
+
+ Tool call sent from Playground:
+
+
);
};
diff --git a/client/src/components/ui/alert.tsx b/client/src/components/ui/alert.tsx
index e4ec228..7e2c69c 100644
--- a/client/src/components/ui/alert.tsx
+++ b/client/src/components/ui/alert.tsx
@@ -1,15 +1,16 @@
+import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
-import type * as React from "react";
+
import { cn } from "@/lib/utils";
const alertVariants = cva(
- "relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
+ "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
{
variants: {
variant: {
- default: "bg-card text-card-foreground",
+ default: "bg-background text-foreground",
destructive:
- "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90",
+ "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
@@ -18,48 +19,44 @@ const alertVariants = cva(
},
);
-function Alert({
- className,
- variant,
- ...props
-}: React.ComponentProps<"div"> & VariantProps) {
- return (
-
- );
-}
+const Alert = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes & VariantProps
+>(({ className, variant, ...props }, ref) => (
+
+));
+Alert.displayName = "Alert";
-function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
+const AlertTitle = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+AlertTitle.displayName = "AlertTitle";
-function AlertDescription({
- className,
- ...props
-}: React.ComponentProps<"div">) {
- return (
-
- );
-}
+const AlertDescription = React.forwardRef<
+ HTMLParagraphElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+AlertDescription.displayName = "AlertDescription";
export { Alert, AlertTitle, AlertDescription };
diff --git a/client/src/components/ui/badge.tsx b/client/src/components/ui/badge.tsx
index cdc838a..86bed41 100644
--- a/client/src/components/ui/badge.tsx
+++ b/client/src/components/ui/badge.tsx
@@ -1,21 +1,20 @@
-import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
+
import { cn } from "@/lib/utils";
const badgeVariants = cva(
- "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
+ "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {
default:
- "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
+ "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
secondary:
- "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
destructive:
- "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
- outline:
- "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
+ "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
+ outline: "text-foreground",
},
},
defaultVariants: {
@@ -24,21 +23,13 @@ const badgeVariants = cva(
},
);
-function Badge({
- className,
- variant,
- asChild = false,
- ...props
-}: React.ComponentProps<"span"> &
- VariantProps & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "span";
+export interface BadgeProps
+ extends React.HTMLAttributes,
+ VariantProps {}
+function Badge({ className, variant, ...props }: BadgeProps) {
return (
-
+
);
}
diff --git a/client/src/components/ui/button.tsx b/client/src/components/ui/button.tsx
index 46a3e82..714ffea 100644
--- a/client/src/components/ui/button.tsx
+++ b/client/src/components/ui/button.tsx
@@ -1,31 +1,30 @@
+import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
-import * as React from "react";
+
import { cn } from "@/lib/utils";
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all cursor-pointer disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
- "bg-[var(--primary)] text-[var(--primary-foreground)] hover:bg-[var(--primary)]/90",
+ "bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
- "bg-[var(--destructive)] text-white hover:bg-[var(--destructive)]/90 focus-visible:ring-[var(--destructive)]/20 dark:focus-visible:ring-[var(--destructive)]/40 dark:bg-[var(--destructive)]/60",
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
- "border bg-[var(--background)] shadow-xs hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)] dark:bg-[var(--input)]/30 dark:border-[var(--input)] dark:hover:bg-[var(--input)]/50",
+ "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
- "bg-[var(--secondary)] text-[var(--secondary-foreground)] hover:bg-[var(--secondary)]/80",
- ghost: "hover:bg-[var(--accent)] hover:text-[var(--accent-foreground)] dark:hover:bg-[var(--accent)]/50",
- link: "text-[var(--primary)] underline-offset-4 hover:underline",
+ "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
+ ghost: "hover:bg-accent hover:text-accent-foreground",
+ link: "text-primary underline-offset-4 hover:underline",
},
size: {
- default: "h-9 px-4 py-2 has-[>svg]:px-3",
- sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
- lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
- icon: "size-9",
- "icon-sm": "size-8",
- "icon-lg": "size-10",
+ default: "h-9 px-4 py-2",
+ sm: "h-8 rounded-md px-3 text-xs",
+ lg: "h-10 rounded-md px-8",
+ icon: "h-9 w-9",
},
},
defaultVariants: {
@@ -35,25 +34,24 @@ const buttonVariants = cva(
},
);
-const Button = React.forwardRef<
- HTMLButtonElement,
- React.ComponentProps<"button"> &
- VariantProps & {
- asChild?: boolean;
- }
->(({ className, variant, size, asChild = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "button";
-
- return (
-
- );
-});
+export interface ButtonProps
+ extends React.ButtonHTMLAttributes,
+ VariantProps {
+ asChild?: boolean;
+}
+const Button = React.forwardRef(
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
+ const Comp = asChild ? Slot : "button";
+ return (
+
+ );
+ },
+);
Button.displayName = "Button";
export { Button, buttonVariants };
diff --git a/client/src/components/ui/card.tsx b/client/src/components/ui/card.tsx
index 507e687..6cee7ed 100644
--- a/client/src/components/ui/card.tsx
+++ b/client/src/components/ui/card.tsx
@@ -1,91 +1,83 @@
-import type * as React from "react";
-import { cn } from "@/lib/utils";
+import * as React from "react";
-function Card({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
+import { cn } from "@/lib/utils";
-function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
+const Card = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+Card.displayName = "Card";
-function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
+const CardHeader = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardHeader.displayName = "CardHeader";
-function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
+const CardTitle = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardTitle.displayName = "CardTitle";
-function CardAction({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
+const CardDescription = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardDescription.displayName = "CardDescription";
-function CardContent({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
+const CardContent = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardContent.displayName = "CardContent";
-function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
- return (
-
- );
-}
+const CardFooter = React.forwardRef<
+ HTMLDivElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+));
+CardFooter.displayName = "CardFooter";
export {
Card,
CardHeader,
CardFooter,
CardTitle,
- CardAction,
CardDescription,
CardContent,
};
diff --git a/client/src/components/ui/checkbox.tsx b/client/src/components/ui/checkbox.tsx
index 3510a63..3436456 100644
--- a/client/src/components/ui/checkbox.tsx
+++ b/client/src/components/ui/checkbox.tsx
@@ -1,29 +1,28 @@
+import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
-import { CheckIcon } from "lucide-react";
-import type * as React from "react";
+import { Check } from "lucide-react";
+
import { cn } from "@/lib/utils";
-function Checkbox({
- className,
- ...props
-}: React.ComponentProps) {
- return (
- ,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
-
-
-
-
- );
-}
+
+
+
+));
+Checkbox.displayName = CheckboxPrimitive.Root.displayName;
export { Checkbox };
diff --git a/client/src/components/ui/dialog.tsx b/client/src/components/ui/dialog.tsx
index 13c2e8d..3bb871c 100644
--- a/client/src/components/ui/dialog.tsx
+++ b/client/src/components/ui/dialog.tsx
@@ -1,31 +1,16 @@
-import * as DialogPrimitive from "@radix-ui/react-dialog";
-import { XIcon } from "lucide-react";
import * as React from "react";
+import * as DialogPrimitive from "@radix-ui/react-dialog";
+import { X } from "lucide-react";
+
import { cn } from "@/lib/utils";
-function Dialog({
- ...props
-}: React.ComponentProps) {
- return ;
-}
+const Dialog = DialogPrimitive.Root;
-function DialogTrigger({
- ...props
-}: React.ComponentProps) {
- return ;
-}
+const DialogTrigger = DialogPrimitive.Trigger;
-function DialogPortal({
- ...props
-}: React.ComponentProps) {
- return ;
-}
+const DialogPortal = DialogPrimitive.Portal;
-function DialogClose({
- ...props
-}: React.ComponentProps) {
- return ;
-}
+const DialogClose = DialogPrimitive.Close;
const DialogOverlay = React.forwardRef<
React.ElementRef,
@@ -33,119 +18,103 @@ const DialogOverlay = React.forwardRef<
>(({ className, ...props }, ref) => (
));
-
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef<
React.ElementRef,
- React.ComponentPropsWithoutRef & {
- showCloseButton?: boolean;
- }
->(({ className, children, showCloseButton = true, ...props }, ref) => (
-
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
{children}
- {showCloseButton && (
-
-
- Close
-
- )}
+
+
+ Close
+
));
-
DialogContent.displayName = DialogPrimitive.Content.displayName;
-const DialogHeader = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
+const DialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
-));
-
+);
DialogHeader.displayName = "DialogHeader";
-const DialogFooter = React.forwardRef<
- HTMLDivElement,
- React.HTMLAttributes
->(({ className, ...props }, ref) => (
+const DialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
-));
-
+);
DialogFooter.displayName = "DialogFooter";
-function DialogTitle({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
+const DialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogTitle.displayName = DialogPrimitive.Title.displayName;
-function DialogDescription({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
+const DialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogDescription.displayName = DialogPrimitive.Description.displayName;
export {
Dialog,
+ DialogPortal,
+ DialogOverlay,
+ DialogTrigger,
DialogClose,
DialogContent,
- DialogDescription,
- DialogFooter,
DialogHeader,
- DialogOverlay,
- DialogPortal,
+ DialogFooter,
DialogTitle,
- DialogTrigger,
+ DialogDescription,
};
diff --git a/client/src/components/ui/dropdown-menu.tsx b/client/src/components/ui/dropdown-menu.tsx
index dee435a..8d1c990 100644
--- a/client/src/components/ui/dropdown-menu.tsx
+++ b/client/src/components/ui/dropdown-menu.tsx
@@ -1,262 +1,202 @@
+import * as React from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
-import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
-import type * as React from "react";
-import { cn } from "@/lib/utils";
-
-function DropdownMenu({
- ...props
-}: React.ComponentProps) {
- return ;
-}
-
-function DropdownMenuPortal({
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
+import { Check, ChevronRight, Circle } from "lucide-react";
-function DropdownMenuTrigger({
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-function DropdownMenuContent({
- className,
- sideOffset = 4,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- );
-}
-
-function DropdownMenuGroup({
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-function DropdownMenuItem({
- className,
- inset,
- variant = "default",
- ...props
-}: React.ComponentProps & {
- inset?: boolean;
- variant?: "default" | "destructive";
-}) {
- return (
-
- );
-}
-
-function DropdownMenuCheckboxItem({
- className,
- children,
- checked,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- );
-}
-
-function DropdownMenuRadioGroup({
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-function DropdownMenuRadioItem({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- );
-}
+import { cn } from "@/lib/utils";
-function DropdownMenuLabel({
- className,
- inset,
- ...props
-}: React.ComponentProps & {
- inset?: boolean;
-}) {
- return (
- ,
+ React.ComponentPropsWithoutRef & {
+ inset?: boolean;
+ }
+>(({ className, inset, children, ...props }, ref) => (
+
+ {children}
+
+
+));
+DropdownMenuSubTrigger.displayName =
+ DropdownMenuPrimitive.SubTrigger.displayName;
+
+const DropdownMenuSubContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DropdownMenuSubContent.displayName =
+ DropdownMenuPrimitive.SubContent.displayName;
+
+const DropdownMenuContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, sideOffset = 4, ...props }, ref) => (
+
+
- );
-}
-
-function DropdownMenuSeparator({
+
+));
+DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
+
+const DropdownMenuItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+ svg]:size-4 [&>svg]:shrink-0",
+ inset && "pl-8",
+ className,
+ )}
+ {...props}
+ />
+));
+DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
+
+const DropdownMenuCheckboxItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, checked, ...props }, ref) => (
+
+
+
+
+
+
+ {children}
+
+));
+DropdownMenuCheckboxItem.displayName =
+ DropdownMenuPrimitive.CheckboxItem.displayName;
+
+const DropdownMenuRadioItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ {children}
+
+));
+DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
+
+const DropdownMenuLabel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef & {
+ inset?: boolean;
+ }
+>(({ className, inset, ...props }, ref) => (
+
+));
+DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
+
+const DropdownMenuSeparator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
+
+const DropdownMenuShortcut = ({
className,
...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-function DropdownMenuShortcut({
- className,
- ...props
-}: React.ComponentProps<"span">) {
+}: React.HTMLAttributes) => {
return (
);
-}
-
-function DropdownMenuSub({
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-function DropdownMenuSubTrigger({
- className,
- inset,
- children,
- ...props
-}: React.ComponentProps & {
- inset?: boolean;
-}) {
- return (
-
- {children}
-
-
- );
-}
-
-function DropdownMenuSubContent({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
+};
+DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {
DropdownMenu,
- DropdownMenuPortal,
DropdownMenuTrigger,
DropdownMenuContent,
- DropdownMenuGroup,
- DropdownMenuLabel,
DropdownMenuItem,
DropdownMenuCheckboxItem,
- DropdownMenuRadioGroup,
DropdownMenuRadioItem,
+ DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
+ DropdownMenuGroup,
+ DropdownMenuPortal,
DropdownMenuSub,
- DropdownMenuSubTrigger,
DropdownMenuSubContent,
+ DropdownMenuSubTrigger,
+ DropdownMenuRadioGroup,
};
diff --git a/client/src/components/ui/input.tsx b/client/src/components/ui/input.tsx
index ab7bee0..875315a 100644
--- a/client/src/components/ui/input.tsx
+++ b/client/src/components/ui/input.tsx
@@ -1,20 +1,22 @@
-import type * as React from "react";
+import * as React from "react";
+
import { cn } from "@/lib/utils";
-function Input({ className, type, ...props }: React.ComponentProps<"input">) {
- return (
-
- );
-}
+const Input = React.forwardRef>(
+ ({ className, type, ...props }, ref) => {
+ return (
+
+ );
+ },
+);
+Input.displayName = "Input";
export { Input };
diff --git a/client/src/components/ui/label.tsx b/client/src/components/ui/label.tsx
index d7c9c5d..82a8f37 100644
--- a/client/src/components/ui/label.tsx
+++ b/client/src/components/ui/label.tsx
@@ -1,21 +1,24 @@
+import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
-import type * as React from "react";
+import { cva, type VariantProps } from "class-variance-authority";
+
import { cn } from "@/lib/utils";
-function Label({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
+const labelVariants = cva(
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
+);
+
+const Label = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, ...props }, ref) => (
+
+));
+Label.displayName = LabelPrimitive.Root.displayName;
export { Label };
diff --git a/client/src/components/ui/select.tsx b/client/src/components/ui/select.tsx
index 2c01866..417f5eb 100644
--- a/client/src/components/ui/select.tsx
+++ b/client/src/components/ui/select.tsx
@@ -1,190 +1,157 @@
+import * as React from "react";
import * as SelectPrimitive from "@radix-ui/react-select";
-import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
-import type * as React from "react";
+import { Check, ChevronDown, ChevronUp } from "lucide-react";
+
import { cn } from "@/lib/utils";
-function Select({
- ...props
-}: React.ComponentProps) {
- return ;
-}
+const Select = SelectPrimitive.Root;
+
+const SelectGroup = SelectPrimitive.Group;
+
+const SelectValue = SelectPrimitive.Value;
-function SelectGroup({
- ...props
-}: React.ComponentProps) {
- return ;
-}
+const SelectTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+ span]:line-clamp-1",
+ className,
+ )}
+ {...props}
+ >
+ {children}
+
+
+
+
+));
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
-function SelectValue({
- ...props
-}: React.ComponentProps) {
- return ;
-}
+const SelectScrollUpButton = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+));
+SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
-function SelectTrigger({
- className,
- size = "default",
- children,
- ...props
-}: React.ComponentProps & {
- size?: "sm" | "default";
-}) {
- return (
- ,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+));
+SelectScrollDownButton.displayName =
+ SelectPrimitive.ScrollDownButton.displayName;
+
+const SelectContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, position = "popper", ...props }, ref) => (
+
+
- {children}
-
-
-
-
- );
-}
-
-function SelectContent({
- className,
- children,
- position = "popper",
- align = "center",
- ...props
-}: React.ComponentProps) {
- return (
-
-
+
-
-
- {children}
-
-
-
-
- );
-}
+ {children}
+
+
+
+
+));
+SelectContent.displayName = SelectPrimitive.Content.displayName;
-function SelectLabel({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
+const SelectLabel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+SelectLabel.displayName = SelectPrimitive.Label.displayName;
-function SelectItem({
- className,
- children,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
-
-
-
- {children}
-
- );
-}
-
-function SelectSeparator({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
- );
-}
-
-function SelectScrollUpButton({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- );
-}
+const SelectItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+ {children}
+
+));
+SelectItem.displayName = SelectPrimitive.Item.displayName;
-function SelectScrollDownButton({
- className,
- ...props
-}: React.ComponentProps) {
- return (
-
-
-
- );
-}
+const SelectSeparator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
export {
Select,
- SelectContent,
SelectGroup,
- SelectItem,
+ SelectValue,
+ SelectTrigger,
+ SelectContent,
SelectLabel,
- SelectScrollDownButton,
- SelectScrollUpButton,
+ SelectItem,
SelectSeparator,
- SelectTrigger,
- SelectValue,
+ SelectScrollUpButton,
+ SelectScrollDownButton,
};
diff --git a/client/src/components/ui/separator.tsx b/client/src/components/ui/separator.tsx
index 556bfb8..28ad171 100644
--- a/client/src/components/ui/separator.tsx
+++ b/client/src/components/ui/separator.tsx
@@ -1,25 +1,31 @@
+import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
-import type * as React from "react";
+
import { cn } from "@/lib/utils";
-function Separator({
- className,
- orientation = "horizontal",
- decorative = true,
- ...props
-}: React.ComponentProps) {
- return (
+const Separator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(
+ (
+ { className, orientation = "horizontal", decorative = true, ...props },
+ ref,
+ ) => (
- );
-}
+ ),
+);
+Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator };
diff --git a/client/src/components/ui/sonner.tsx b/client/src/components/ui/sonner.tsx
new file mode 100644
index 0000000..1e5bfde
--- /dev/null
+++ b/client/src/components/ui/sonner.tsx
@@ -0,0 +1,28 @@
+import { useTheme } from "next-themes";
+import { Toaster as Sonner } from "sonner";
+
+type ToasterProps = React.ComponentProps;
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = "system" } = useTheme();
+
+ return (
+
+ );
+};
+
+export { Toaster };
diff --git a/client/src/components/ui/spinner.tsx b/client/src/components/ui/spinner.tsx
index 2c29440..884069e 100644
--- a/client/src/components/ui/spinner.tsx
+++ b/client/src/components/ui/spinner.tsx
@@ -1,4 +1,5 @@
import { Loader2Icon } from "lucide-react";
+
import { cn } from "@/lib/utils";
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
diff --git a/client/src/components/ui/textarea.tsx b/client/src/components/ui/textarea.tsx
index fe4f570..9af86df 100644
--- a/client/src/components/ui/textarea.tsx
+++ b/client/src/components/ui/textarea.tsx
@@ -1,4 +1,5 @@
import * as React from "react";
+
import { cn } from "@/lib/utils";
const Textarea = React.forwardRef<
@@ -7,9 +8,8 @@ const Textarea = React.forwardRef<
>(({ className, ...props }, ref) => {
return (
);
});
-
Textarea.displayName = "Textarea";
export { Textarea };
diff --git a/client/src/contexts/AppContext.tsx b/client/src/contexts/AppContext.tsx
index 89e598b..389604d 100644
--- a/client/src/contexts/AppContext.tsx
+++ b/client/src/contexts/AppContext.tsx
@@ -1,22 +1,15 @@
-import {
- getSystemConfig,
- Insight,
- runPixel as runPixelSemossSdk,
-} from "@semoss/sdk";
+import { getSystemConfig, runPixel as runPixelSemossSdk } from "@semoss/sdk";
import { useInsight } from "@semoss/sdk/react";
import {
createContext,
- type Dispatch,
type PropsWithChildren,
- type SetStateAction,
useCallback,
useContext,
useEffect,
useState,
} from "react";
-import type { MessageSnackbarProps } from "@/components";
+import { toast } from "sonner";
import { useLoadingState } from "@/hooks";
-import type { MCPToolRequest } from "@/types";
export interface AppContextType {
runPixel: (
@@ -32,10 +25,8 @@ export interface AppContextType {
logout: () => Promise;
userLoginName: string;
isAppDataLoading: boolean;
+ isUserLoginLoading: boolean;
exampleStateData?: number;
- messageSnackbarProps: MessageSnackbarProps;
- setMessageSnackbarProps: Dispatch>;
- tool: MCPToolRequest;
}
const AppContext = createContext(undefined);
@@ -69,15 +60,9 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
/**
* State
*/
+ const [isUserLoginLoading, setIsUserLoginLoading] = useLoadingState(false);
const [isAppDataLoading, setIsAppDataLoading] = useLoadingState(true);
const [userLoginName, setUserLoginName] = useState(null);
- const [tool, setTool] = useState(null);
- const [messageSnackbarProps, setMessageSnackbarProps] =
- useState({
- open: false,
- message: "",
- severity: "info",
- });
// Example state variable to store the result of a pixel operation
const [exampleStateData, setExampleStateData] = useState();
@@ -117,19 +102,11 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
.join(", "),
);
if (successMessage) {
- setMessageSnackbarProps({
- open: true,
- message: successMessage,
- severity: "success",
- });
+ toast.success(successMessage);
}
return response.pixelReturn[0].output;
} catch (error) {
- setMessageSnackbarProps({
- open: true,
- message: `${error.message ?? "Error during operation"}`,
- severity: "error",
- });
+ toast.error(`${error.message ?? "Error during operation"}`);
throw error;
}
},
@@ -149,11 +126,7 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
throw new Error("No output from MCP tool");
return response.output;
} catch (error) {
- setMessageSnackbarProps({
- open: true,
- message: `${error.message ?? "Error during operation"}`,
- severity: "error",
- });
+ toast.error(`${error.message ?? "Error during operation"}`);
throw error;
}
},
@@ -163,6 +136,7 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
// Allow users to log in, and grab their name when they do
const login = useCallback(
async (username: string, password: string) => {
+ const loadingKey = setIsUserLoginLoading(true);
try {
await actions.login({
type: "native",
@@ -178,21 +152,26 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
return true;
} catch {
return false;
+ } finally {
+ setIsUserLoginLoading(false, loadingKey);
}
},
- [actions],
+ [actions, setIsUserLoginLoading],
);
// Allow users to log out, and clear their name when they do
const logout = useCallback(async () => {
+ const loadingKey = setIsUserLoginLoading(true);
try {
await actions.logout();
setUserLoginName(null);
return true;
} catch {
return false;
+ } finally {
+ setIsUserLoginLoading(false, loadingKey);
}
- }, [actions]);
+ }, [actions, setIsUserLoginLoading]);
/**
* Effects
@@ -220,11 +199,6 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
},
setter: (response) => setExampleStateData(response),
} satisfies LoadSetPair,
- {
- loader: async () => await new Insight().initialize(),
- // Optionally handle the result or remove the setter if not needed
- setter: (initConfig) => setTool(initConfig.tool),
- } satisfies LoadSetPair<{ tool: MCPToolRequest }>,
];
// Execute all loaders in parallel and wait for them all to complete
@@ -244,11 +218,9 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
);
} catch (e) {
// If any loader fails, display an error message
- setMessageSnackbarProps({
- open: true,
- message: `Error initializing app data${e.message ? `: ${e.message}` : ""}`,
- severity: "error",
- });
+ toast.error(
+ `Error initializing app data${e.message ? `: ${e.message}` : ""}`,
+ );
}
};
@@ -273,12 +245,10 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => {
runMCPTool,
exampleStateData,
isAppDataLoading,
- messageSnackbarProps,
- setMessageSnackbarProps,
login,
logout,
userLoginName,
- tool,
+ isUserLoginLoading,
}}
>
{children}
diff --git a/client/src/globals.css b/client/src/globals.css
index 0da058a..afc058d 100644
--- a/client/src/globals.css
+++ b/client/src/globals.css
@@ -1,189 +1,123 @@
-@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&display=swap");
-@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&display=swap");
-
@import "tailwindcss";
+@import "tw-animate-css";
+
+@custom-variant dark (&:is(.dark *));
:root {
- --font-sans: "IBM Plex Sans", ui-sans-serif, system-ui, sans-serif;
- --font-mono: "IBM Plex Mono", ui-monospace, monospace;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.205 0 0);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --destructive-foreground: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
--radius: 0.625rem;
- --background: rgba(255, 255, 255, 1);
- --secondary-background: rgba(255, 255, 255, 1);
- --foreground: rgba(10, 10, 10, 1);
- --card: rgba(255, 255, 255, 1);
- --card-foreground: rgba(10, 10, 10, 1);
- --popover: rgba(255, 255, 255, 1);
- --popover-foreground: rgba(10, 10, 10, 1);
- --primary: rgba(5, 112, 240, 1);
- --primary-foreground: rgba(250, 250, 250, 1);
- --secondary: rgba(245, 245, 245, 1);
- --secondary-foreground: rgba(23, 23, 23, 1);
- --muted: rgba(245, 245, 245, 1);
- --muted-foreground: rgba(115, 115, 115, 1);
- --accent: rgba(245, 245, 245, 1);
- --accent-foreground: rgba(23, 23, 23, 1);
- --destructive: rgba(219, 38, 38, 1);
- --destructive-foreground: rgba(255, 242, 242, 1);
- --border: rgba(230, 230, 230, 1);
- --input: rgba(230, 230, 230, 1);
- --ring: rgba(163, 163, 163, 1);
- --ring-offset: rgba(255, 255, 255, 1);
- --chart-1: rgba(235, 89, 13, 1);
- --chart-2: rgba(13, 148, 135, 1);
- --chart-3: rgba(23, 79, 99, 1);
- --chart-4: rgba(250, 191, 36, 1);
- --chart-5: rgba(245, 158, 10, 1);
- --sidebar: rgba(250, 250, 250, 1);
- --sidebar-foreground: rgba(10, 10, 10, 1);
- --sidebar-primary-foreground: rgba(250, 250, 250, 1);
- --sidebar-primary: rgba(23, 23, 23, 1);
- --sidebar-accent: rgba(245, 245, 245, 1);
- --sidebar-accent-foreground: rgba(23, 23, 23, 1);
- --sidebar-border: rgba(230, 230, 230, 1);
- --sidebar-ring: rgba(163, 163, 163, 1);
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
}
.dark {
- --background: rgba(10, 10, 10, 1);
- --secondary-background: rgba(38, 38, 38, 1);
- --foreground: rgba(250, 250, 250, 1);
- --card: rgba(23, 23, 23, 1);
- --card-foreground: rgba(250, 250, 250, 1);
- --popover: rgba(38, 38, 38, 1);
- --popover-foreground: rgba(250, 250, 250, 1);
- --primary: rgba(5, 112, 240, 1);
- --primary-foreground: rgba(250, 250, 250, 1);
- --secondary: rgba(38, 38, 38, 1);
- --secondary-foreground: rgba(250, 250, 250, 1);
- --muted: rgba(38, 38, 38, 1);
- --muted-foreground: rgba(163, 163, 163, 1);
- --accent: rgba(64, 64, 64, 1);
- --accent-foreground: rgba(250, 250, 250, 1);
- --destructive: rgba(247, 112, 112, 1);
- --destructive-foreground: rgba(255, 242, 242, 1);
- --border: rgba(255, 255, 255, 0.1);
- --input: rgba(255, 255, 255, 0.15);
- --ring: rgba(115, 115, 115, 1);
- --ring-offset: rgba(10, 10, 10, 1);
- --chart-1: rgba(28, 79, 217, 1);
- --chart-2: rgba(15, 186, 130, 1);
- --chart-3: rgba(245, 158, 10, 1);
- --chart-4: rgba(168, 84, 247, 1);
- --chart-5: rgba(245, 64, 94, 1);
- --sidebar: rgba(23, 23, 23, 1);
- --sidebar-foreground: rgba(250, 250, 250, 1);
- --sidebar-primary-foreground: rgba(23, 23, 23, 1);
- --sidebar-primary: rgba(250, 250, 250, 1);
- --sidebar-accent: rgba(38, 38, 38, 1);
- --sidebar-accent-foreground: rgba(250, 250, 250, 1);
- --sidebar-border: rgba(255, 255, 255, 0.1);
- --sidebar-ring: rgba(82, 82, 82, 1);
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.145 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.145 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.985 0 0);
+ --primary-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.269 0 0);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.396 0.141 25.723);
+ --destructive-foreground: oklch(0.637 0.237 25.331);
+ --border: oklch(0.269 0 0);
+ --input: oklch(0.269 0 0);
+ --ring: oklch(0.439 0 0);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.696 0.17 162.48);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(0.269 0 0);
+ --sidebar-ring: oklch(0.439 0 0);
}
-/* Custom */
+@theme inline {
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-destructive-foreground: var(--destructive-foreground);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
+}
@layer base {
* {
- border-color: var(--border);
- outline-color: rgb(from var(--ring) r g b / 0.5);
+ @apply border-border outline-ring/50;
}
body {
- background-color: var(--background);
- color: var(--foreground);
- font-family: var(--font-sans);
- }
-
- button:not([disabled]),
- [role="button"]:not([disabled]) {
- cursor: pointer;
- }
- button {
- cursor: pointer;
- }
-
- .heading-xl {
- font-family: var(--font-sans);
- font-size: 3rem;
- line-height: 1;
- font-weight: 700;
- letter-spacing: -0.01em;
- }
- .heading-lg {
- font-family: var(--font-sans);
- font-size: 2.25rem;
- line-height: 1.111;
- font-weight: 700;
- letter-spacing: -0.01em;
- }
- .heading-md {
- font-family: var(--font-sans);
- font-size: 1.875rem;
- line-height: 1.2;
- font-weight: 700;
- letter-spacing: -0.01em;
- }
- .heading-sm {
- font-family: var(--font-sans);
- font-size: 1.5rem;
- line-height: 1.333;
- font-weight: 700;
- letter-spacing: -0.01em;
- }
- .container-padding-x {
- padding-inline: 1.5rem;
- }
- .section-padding-y {
- padding-block: 6rem;
- }
- .section-title-gap-xl {
- gap: 1.5rem;
- }
- .section-title-gap-lg {
- gap: 1.25rem;
- }
- .section-title-gap-md {
- gap: 1.25rem;
- }
- .section-title-gap-sm {
- gap: 1rem;
- }
-}
-
-/* ---break ---*/
-
-@media (max-width: 64rem) {
- .heading-xl {
- font-size: 1.875rem;
- line-height: 1.2;
- }
- .heading-lg {
- font-size: 1.875rem;
- line-height: 1.2;
- }
- .heading-md {
- font-size: 1.5rem;
- line-height: 1.2;
- }
- .heading-sm {
- font-size: 1.5rem;
- line-height: 1.333;
- }
- .container-padding-x {
- padding-inline: 1.5rem;
- }
- .section-padding-y {
- padding-block: 4rem;
- }
- .section-title-gap-xl {
- gap: 1rem;
- }
- .section-title-gap-lg {
- gap: 1rem;
- }
- .section-title-gap-md {
- gap: 1rem;
- }
- .section-title-gap-sm {
- gap: 1rem;
+ @apply bg-background text-foreground;
}
}
diff --git a/client/src/index.css b/client/src/index.css
new file mode 100644
index 0000000..832038e
--- /dev/null
+++ b/client/src/index.css
@@ -0,0 +1,3 @@
+@import "./globals.css";
+
+@source "./**/*.{ts,tsx}";
diff --git a/client/src/pages/layouts/AuthorizedLayout.tsx b/client/src/pages/layouts/AuthorizedLayout.tsx
index 841359a..6ff692c 100644
--- a/client/src/pages/layouts/AuthorizedLayout.tsx
+++ b/client/src/pages/layouts/AuthorizedLayout.tsx
@@ -13,7 +13,7 @@ export const AuthorizedLayout = () => {
const { isAuthorized } = useInsight(); // Read whether the user is authorized
// Get the curent route, so that if we are trying to log the user in, we can take them to where they were trying to go
const { pathname } = useLocation();
- const { isAppDataLoading } = useAppContext();
+ const { isAppDataLoading, isUserLoginLoading } = useAppContext();
// If the user is not authorized, take them to the login page, and pass their intended route
if (!isAuthorized)
@@ -25,5 +25,10 @@ export const AuthorizedLayout = () => {
if (isAppDataLoading) return ;
// Outlet is a react router component; it allows the router to choose the child based on the route
- return ;
+ return (
+ <>
+ {isUserLoginLoading && }
+
+ >
+ );
};
diff --git a/client/src/pages/layouts/InitializedLayout.tsx b/client/src/pages/layouts/InitializedLayout.tsx
index 2e42542..c00485a 100644
--- a/client/src/pages/layouts/InitializedLayout.tsx
+++ b/client/src/pages/layouts/InitializedLayout.tsx
@@ -1,7 +1,6 @@
import { useInsight } from "@semoss/sdk/react";
import { Outlet } from "react-router-dom";
-import { LoadingScreen, MainNavigation, MessageSnackbar } from "@/components";
-import { useAppContext } from "@/contexts";
+import { LoadingScreen, MainNavigation } from "@/components";
/**
* Renders a loading wheel if SEMOSS is not initialized.
@@ -13,16 +12,12 @@ export const InitializedLayout = () => {
* Library hooks
*/
const { isInitialized } = useInsight();
- const { messageSnackbarProps } = useAppContext();
return (
{/* Allow users to navigate around the app */}
- {/* Show message snackbar with notifications */}
-
-
{isInitialized ? (
// If initialized, set up padding and scroll
diff --git a/client/src/types.d.ts b/client/src/types.d.ts
index 3216278..e69de29 100644
--- a/client/src/types.d.ts
+++ b/client/src/types.d.ts
@@ -1,17 +0,0 @@
-export interface MCPToolRequest {
- type: "MCP";
- message: string;
- id: string;
- name: string;
- parameters: Record;
- roomId: string;
-}
-
-export interface MCPToolResponse {
- type: "MCP";
- message: string;
- id: string;
- name: string;
- response: string;
- roomId: string;
-}
diff --git a/client/vite.config.ts b/client/vite.config.ts
index c0c794b..0431c11 100644
--- a/client/vite.config.ts
+++ b/client/vite.config.ts
@@ -1,6 +1,7 @@
import { resolve } from "node:path";
import react from "@vitejs/plugin-react";
import { defineConfig, loadEnv } from "vite";
+import tailwindcss from "@tailwindcss/vite";
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "") as {
@@ -37,6 +38,6 @@ export default defineConfig(({ mode }) => {
outDir: "../../portals",
emptyOutDir: true,
},
- plugins: [react()],
+ plugins: [react(), tailwindcss()],
};
});
diff --git a/package.json b/package.json
index 9dd6b70..5efc243 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"javadoc": "mvn clean javadoc:javadoc && mvn site && pnpm exec http-server target/site/apidocs -p 1227 -a localhost -o"
},
"devDependencies": {
- "@biomejs/biome": "2.3.7",
+ "@biomejs/biome": "2.3.8",
"http-server": "^14.1.1",
"husky": "^9.1.7",
"lint-staged": "^16.2.7"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8a95e27..e32c807 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,8 +9,8 @@ importers:
.:
devDependencies:
'@biomejs/biome':
- specifier: 2.3.7
- version: 2.3.7
+ specifier: 2.3.8
+ version: 2.3.8
http-server:
specifier: ^14.1.1
version: 14.1.1
@@ -23,55 +23,55 @@ importers:
packages:
- '@biomejs/biome@2.3.7':
- resolution: {integrity: sha512-CTbAS/jNAiUc6rcq94BrTB8z83O9+BsgWj2sBCQg9rD6Wkh2gjfR87usjx0Ncx0zGXP1NKgT7JNglay5Zfs9jw==}
+ '@biomejs/biome@2.3.8':
+ resolution: {integrity: sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA==}
engines: {node: '>=14.21.3'}
hasBin: true
- '@biomejs/cli-darwin-arm64@2.3.7':
- resolution: {integrity: sha512-LirkamEwzIUULhXcf2D5b+NatXKeqhOwilM+5eRkbrnr6daKz9rsBL0kNZ16Hcy4b8RFq22SG4tcLwM+yx/wFA==}
+ '@biomejs/cli-darwin-arm64@2.3.8':
+ resolution: {integrity: sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
- '@biomejs/cli-darwin-x64@2.3.7':
- resolution: {integrity: sha512-Q4TO633kvrMQkKIV7wmf8HXwF0dhdTD9S458LGE24TYgBjSRbuhvio4D5eOQzirEYg6eqxfs53ga/rbdd8nBKg==}
+ '@biomejs/cli-darwin-x64@2.3.8':
+ resolution: {integrity: sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
- '@biomejs/cli-linux-arm64-musl@2.3.7':
- resolution: {integrity: sha512-/afy8lto4CB8scWfMdt+NoCZtatBUF62Tk3ilWH2w8ENd5spLhM77zKlFZEvsKJv9AFNHknMl03zO67CiklL2Q==}
+ '@biomejs/cli-linux-arm64-musl@2.3.8':
+ resolution: {integrity: sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-arm64@2.3.7':
- resolution: {integrity: sha512-inHOTdlstUBzgjDcx0ge71U4SVTbwAljmkfi3MC5WzsYCRhancqfeL+sa4Ke6v2ND53WIwCFD5hGsYExoI3EZQ==}
+ '@biomejs/cli-linux-arm64@2.3.8':
+ resolution: {integrity: sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
- '@biomejs/cli-linux-x64-musl@2.3.7':
- resolution: {integrity: sha512-CQUtgH1tIN6e5wiYSJqzSwJumHYolNtaj1dwZGCnZXm2PZU1jOJof9TsyiP3bXNDb+VOR7oo7ZvY01If0W3iFQ==}
+ '@biomejs/cli-linux-x64-musl@2.3.8':
+ resolution: {integrity: sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-linux-x64@2.3.7':
- resolution: {integrity: sha512-fJMc3ZEuo/NaMYo5rvoWjdSS5/uVSW+HPRQujucpZqm2ZCq71b8MKJ9U4th9yrv2L5+5NjPF0nqqILCl8HY/fg==}
+ '@biomejs/cli-linux-x64@2.3.8':
+ resolution: {integrity: sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
- '@biomejs/cli-win32-arm64@2.3.7':
- resolution: {integrity: sha512-aJAE8eCNyRpcfx2JJAtsPtISnELJ0H4xVVSwnxm13bzI8RwbXMyVtxy2r5DV1xT3WiSP+7LxORcApWw0LM8HiA==}
+ '@biomejs/cli-win32-arm64@2.3.8':
+ resolution: {integrity: sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
- '@biomejs/cli-win32-x64@2.3.7':
- resolution: {integrity: sha512-pulzUshqv9Ed//MiE8MOUeeEkbkSHVDVY5Cz5wVAnH1DUqliCQG3j6s1POaITTFqFfo7AVIx2sWdKpx/GS+Nqw==}
+ '@biomejs/cli-win32-x64@2.3.8':
+ resolution: {integrity: sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
@@ -408,46 +408,46 @@ packages:
resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==}
engines: {node: '>=18'}
- yaml@2.8.1:
- resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==}
+ yaml@2.8.2:
+ resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==}
engines: {node: '>= 14.6'}
hasBin: true
snapshots:
- '@biomejs/biome@2.3.7':
+ '@biomejs/biome@2.3.8':
optionalDependencies:
- '@biomejs/cli-darwin-arm64': 2.3.7
- '@biomejs/cli-darwin-x64': 2.3.7
- '@biomejs/cli-linux-arm64': 2.3.7
- '@biomejs/cli-linux-arm64-musl': 2.3.7
- '@biomejs/cli-linux-x64': 2.3.7
- '@biomejs/cli-linux-x64-musl': 2.3.7
- '@biomejs/cli-win32-arm64': 2.3.7
- '@biomejs/cli-win32-x64': 2.3.7
-
- '@biomejs/cli-darwin-arm64@2.3.7':
+ '@biomejs/cli-darwin-arm64': 2.3.8
+ '@biomejs/cli-darwin-x64': 2.3.8
+ '@biomejs/cli-linux-arm64': 2.3.8
+ '@biomejs/cli-linux-arm64-musl': 2.3.8
+ '@biomejs/cli-linux-x64': 2.3.8
+ '@biomejs/cli-linux-x64-musl': 2.3.8
+ '@biomejs/cli-win32-arm64': 2.3.8
+ '@biomejs/cli-win32-x64': 2.3.8
+
+ '@biomejs/cli-darwin-arm64@2.3.8':
optional: true
- '@biomejs/cli-darwin-x64@2.3.7':
+ '@biomejs/cli-darwin-x64@2.3.8':
optional: true
- '@biomejs/cli-linux-arm64-musl@2.3.7':
+ '@biomejs/cli-linux-arm64-musl@2.3.8':
optional: true
- '@biomejs/cli-linux-arm64@2.3.7':
+ '@biomejs/cli-linux-arm64@2.3.8':
optional: true
- '@biomejs/cli-linux-x64-musl@2.3.7':
+ '@biomejs/cli-linux-x64-musl@2.3.8':
optional: true
- '@biomejs/cli-linux-x64@2.3.7':
+ '@biomejs/cli-linux-x64@2.3.8':
optional: true
- '@biomejs/cli-win32-arm64@2.3.7':
+ '@biomejs/cli-win32-arm64@2.3.8':
optional: true
- '@biomejs/cli-win32-x64@2.3.7':
+ '@biomejs/cli-win32-x64@2.3.8':
optional: true
ansi-escapes@7.2.0:
@@ -625,7 +625,7 @@ snapshots:
nano-spawn: 2.0.0
pidtree: 0.6.0
string-argv: 0.3.2
- yaml: 2.8.1
+ yaml: 2.8.2
listr2@9.0.5:
dependencies:
@@ -775,4 +775,4 @@ snapshots:
string-width: 7.2.0
strip-ansi: 7.1.2
- yaml@2.8.1: {}
+ yaml@2.8.2: {}