local-operator-ui 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index-BJAGPaLC.js","./fonts-ChEL5asK.js","./fonts-B9KBGB-g.css","./index-DTD3Qh6P.js","./pug-By0kVCfm.js","./javascript-C3MnDRiU.js"])))=>i.map(i=>d[i]);
2
- import { c as createStyled, r as resolveProps, u as useTheme, a as reactExports, b as clsx, d as useForkRef, e as extendSxProp, j as jsxRuntimeExports, h as handleBreakpoints, f as resolveBreakpointValues, g as createUnarySpacing, i as deepmerge, m as mergeBreakpointsInOrder, k as composeClasses, l as generateUtilityClass, n as createTheme$1, o as getValue, R as React, p as getDefaultExportFromCjs, q as requireReactDom, s as React$1, t as generateUtilityClasses, v as useDefaultProps, w as styled$1, x as capitalize, y as memoTheme, _ as _inheritsLoose, z as _objectWithoutPropertiesLoose$i, T as TransitionGroupContext, A as duration, B as useTheme$1, C as useTimeout, D as useId, E as ButtonBase, F as alpha$1, G as createSimplePaletteValueFilter, H as CircularProgress, P as Paper, I as darken, J as lighten, K as useEventCallback, L as useEnhancedEffect, M as useRtl, N as globalCss, O as formatMuiErrorMessage, Q as rootShouldForwardProp, S as Typography, U as getPath$2, V as isFocusVisible, W as typographyClasses, X as slotShouldForwardProp, Y as css$1, Z as keyframes, $ as clamp, a0 as emphasize, a1 as Timeout, a2 as Button, a3 as Box, a4 as FontAwesomeIcon, a5 as faExclamationTriangle, a6 as faEllipsisVertical, a7 as faComment, a8 as faGear, a9 as faFileExport, aa as faBroom, ab as faTrash, ac as DEFAULT_THEME, ad as faChevronLeft, ae as faChevronRight, af as faRobot, ag as faCheck, ah as faTimes, ai as faEraser, aj as faPen, ak as faFileImport, al as faUpload, am as faPlus, an as faSearch, ao as requireReact, ap as LinearProgress, aq as faComments, ar as faInfoCircle, as as faServer, at as faStar, au as faTag, av as faIdCard, aw as faCalendarAlt, ax as faCodeBranch, ay as faShieldAlt, az as faArrowLeft, aA as faClock, aB as faHome, aC as faDownload, aD as faFileAlt, aE as faDesktop, aF as faImage, aG as faMusic, aH as faVideo, aI as faLaptop, aJ as faUsers, aK as faDatabase, aL as faBoxOpen, aM as faBook, aN as faHdd, aO as faBox, aP as faArchive, aQ as faNetworkWired, aR as faFolder, aS as faFolderOpen, aT as faFolderTree, aU as faChevronDown, aV as faTools, aW as _extends$u, aX as faSliders, aY as faArrowDown, aZ as faPaperclip, a_ as faStop, a$ as faPaperPlane, b0 as faChevronUp, b1 as faQuestion, b2 as faFile, b3 as faExclamationCircle, b4 as faLightbulb, b5 as faCode, b6 as faCommentDots, b7 as faEdit, b8 as faPencilAlt, b9 as faUser, ba as faCopy, bb as isDevelopmentMode, bc as faCommentSlash, bd as faArrowRight, be as faMagicWandSparkles, bf as faBrain, bg as faWandMagicSparkles, bh as faExternalLinkAlt, bi as faKey, bj as radientTheme, bk as faGlobe, bl as commonjsGlobal, bm as PropTypes, bn as faLock, bo as faSignOut, bp as faAdjust, bq as faSave, br as themes, bs as faMoon, bt as faSun, bu as faHexagonNodes, bv as faSkull, bw as faLeaf, bx as faMountain, by as faFire, bz as faIcicles, bA as faEnvelope, bB as faHistory, bC as faListAlt, bD as faCreditCard, bE as faPlusCircle, bF as faChartLine, bG as faShield, bH as library$1, bI as icons$1, bJ as CssBaseline, bK as ThemeProvider$1, bL as getTheme, bM as ReactDOM$1, bN as ErrorBoundary } from "./fonts-ChEL5asK.js";
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index-DG_vMIJB.js","./fonts-BpQHnoYe.js","./fonts-B9KBGB-g.css","./index-DMTU6W8a.js","./pug-By0kVCfm.js","./javascript-C3MnDRiU.js"])))=>i.map(i=>d[i]);
2
+ import { c as createStyled, r as resolveProps, u as useTheme, a as reactExports, b as clsx, d as useForkRef, e as extendSxProp, j as jsxRuntimeExports, h as handleBreakpoints, f as resolveBreakpointValues, g as createUnarySpacing, i as deepmerge, m as mergeBreakpointsInOrder, k as composeClasses, l as generateUtilityClass, n as createTheme$1, o as getValue, R as React, p as getDefaultExportFromCjs, q as requireReactDom, s as React$1, t as generateUtilityClasses, v as useDefaultProps, w as styled$1, x as capitalize, y as memoTheme, _ as _inheritsLoose, z as _objectWithoutPropertiesLoose$i, T as TransitionGroupContext, A as duration, B as useTheme$1, C as useTimeout, D as useId, E as ButtonBase, F as alpha$1, G as createSimplePaletteValueFilter, H as CircularProgress, P as Paper, I as darken, J as lighten, K as useEventCallback, L as useEnhancedEffect, M as useRtl, N as globalCss, O as formatMuiErrorMessage, Q as rootShouldForwardProp, S as Typography, U as getPath$2, V as isFocusVisible, W as typographyClasses, X as slotShouldForwardProp, Y as css$1, Z as keyframes, $ as clamp, a0 as emphasize, a1 as Timeout, a2 as Button, a3 as Box, a4 as FontAwesomeIcon, a5 as faExclamationTriangle, a6 as faEllipsisVertical, a7 as faComment, a8 as faGear, a9 as faFileExport, aa as faBroom, ab as faTrash, ac as DEFAULT_THEME, ad as faChevronLeft, ae as faChevronRight, af as faRobot, ag as faCheck, ah as faTimes, ai as faEraser, aj as faPen, ak as faFileImport, al as faUpload, am as faPlus, an as faSearch, ao as requireReact, ap as LinearProgress, aq as faComments, ar as faInfoCircle, as as faServer, at as faStar, au as faTag, av as faIdCard, aw as faCalendarAlt, ax as faCodeBranch, ay as faShieldAlt, az as faArrowLeft, aA as faClock, aB as faHome, aC as faDownload, aD as faFileAlt, aE as faDesktop, aF as faImage, aG as faMusic, aH as faVideo, aI as faLaptop, aJ as faUsers, aK as faDatabase, aL as faBoxOpen, aM as faBook, aN as faHdd, aO as faBox, aP as faArchive, aQ as faNetworkWired, aR as faFolder, aS as faFolderOpen, aT as faFolderTree, aU as faChevronDown, aV as faTools, aW as _extends$u, aX as faSliders, aY as faArrowDown, aZ as faPaperclip, a_ as faStop, a$ as faPaperPlane, b0 as faChevronUp, b1 as faQuestion, b2 as faFile, b3 as faExclamationCircle, b4 as faLightbulb, b5 as faCode, b6 as faCommentDots, b7 as faShare, b8 as faEdit, b9 as faPencilAlt, ba as faUser, bb as faCopy, bc as isDevelopmentMode, bd as faCommentSlash, be as faArrowRight, bf as faMagicWandSparkles, bg as faBrain, bh as faWandMagicSparkles, bi as faExternalLinkAlt, bj as faKey, bk as radientTheme, bl as faGlobe, bm as commonjsGlobal, bn as PropTypes, bo as faLock, bp as faSignOut, bq as faAdjust, br as faSave, bs as themes, bt as faMoon, bu as faSun, bv as faHexagonNodes, bw as faSkull, bx as faLeaf, by as faMountain, bz as faFire, bA as faIcicles, bB as faEnvelope, bC as faHistory, bD as faListAlt, bE as faCreditCard, bF as faPlusCircle, bG as faChartLine, bH as faShield, bI as library$1, bJ as icons$1, bK as CssBaseline, bL as ThemeProvider$1, bM as getTheme, bN as ReactDOM$1, bO as ErrorBoundary } from "./fonts-BpQHnoYe.js";
3
3
  const styled = createStyled();
4
4
  function getThemeProps(params) {
5
5
  const {
@@ -34079,7 +34079,9 @@ const DividerFlexItem = styled$1(Box)({
34079
34079
  flexShrink: 0,
34080
34080
  zIndex: 10
34081
34081
  });
34082
- const DividerHoverArea = styled$1(Box)(({ $active, $side }) => ({
34082
+ const DividerHoverArea = styled$1(Box, {
34083
+ shouldForwardProp: (prop) => prop !== "$active" && prop !== "$side"
34084
+ })(({ $active, $side }) => ({
34083
34085
  position: "absolute",
34084
34086
  top: 0,
34085
34087
  [$side]: 0,
@@ -34092,7 +34094,9 @@ const DividerHoverArea = styled$1(Box)(({ $active, $side }) => ({
34092
34094
  zIndex: 11,
34093
34095
  transition: "width 0.2s cubic-bezier(0.4,0,0.2,1)"
34094
34096
  }));
34095
- const DividerLine = styled$1(Box)(
34097
+ const DividerLine = styled$1(Box, {
34098
+ shouldForwardProp: (prop) => prop !== "$active" && prop !== "$side"
34099
+ })(
34096
34100
  ({ theme: theme2, $side, $active }) => ({
34097
34101
  position: "absolute",
34098
34102
  top: 0,
@@ -34107,7 +34111,9 @@ const DividerLine = styled$1(Box)(
34107
34111
  transition: "width 0.2s cubic-bezier(0.4,0,0.2,1), background 0.2s, opacity 0.2s"
34108
34112
  })
34109
34113
  );
34110
- const DragHandle = styled$1(Box)(({ theme: theme2, $active }) => ({
34114
+ const DragHandle = styled$1(Box, {
34115
+ shouldForwardProp: (prop) => prop !== "$active"
34116
+ })(({ theme: theme2, $active }) => ({
34111
34117
  position: "absolute",
34112
34118
  left: "50%",
34113
34119
  top: "50%",
@@ -34279,37 +34285,80 @@ const useDeferredUpdatesStore = create$1()(
34279
34285
  const CheckForUpdatesButton = () => {
34280
34286
  const [checking, setChecking] = reactExports.useState(false);
34281
34287
  const [snackbarOpen, setSnackbarOpen] = reactExports.useState(false);
34288
+ const [snackbarMessage, setSnackbarMessage] = reactExports.useState(null);
34289
+ const [snackbarSeverity, setSnackbarSeverity] = reactExports.useState("info");
34282
34290
  const [manualUpdateInfo, setManualUpdateInfo] = reactExports.useState(null);
34291
+ const manualCheckRef = reactExports.useRef(false);
34283
34292
  const { clearDeferredUpdate } = useDeferredUpdatesStore();
34284
34293
  reactExports.useEffect(() => {
34285
- const removeManualUpdateListener = window.api.updater.onUpdateError(
34294
+ const removeUpdateErrorListener = window.api.updater.onUpdateError(
34286
34295
  (message2) => {
34296
+ if (!manualCheckRef.current) return;
34297
+ const suppressedPatterns = [
34298
+ "ENOENT: no such file or directory, open",
34299
+ // e.g. missing update yml
34300
+ "Could not get code signature for running application",
34301
+ // macOS spurious
34302
+ "Cannot find latest.yml"
34303
+ // electron-updater
34304
+ ];
34305
+ const isSuppressed = suppressedPatterns.some(
34306
+ (pat) => message2.includes(pat)
34307
+ );
34287
34308
  if (message2.includes("manually")) {
34288
34309
  setManualUpdateInfo({
34289
34310
  message: "Please update the local-operator package manually using pip.",
34290
34311
  command: "pip install --upgrade local-operator"
34291
34312
  });
34313
+ setSnackbarSeverity("warning");
34314
+ setSnackbarOpen(true);
34315
+ } else if (!isSuppressed) {
34316
+ setSnackbarMessage(message2);
34317
+ setSnackbarSeverity("error");
34292
34318
  setSnackbarOpen(true);
34293
34319
  }
34294
34320
  }
34295
34321
  );
34322
+ const removeUpdateNotAvailableListener = window.api.updater.onUpdateNotAvailable(() => {
34323
+ if (!manualCheckRef.current) return;
34324
+ setSnackbarMessage("No updates available. You are up to date!");
34325
+ setSnackbarSeverity("success");
34326
+ setSnackbarOpen(true);
34327
+ });
34328
+ const removeBackendUpdateNotAvailableListener = window.api.updater.onBackendUpdateNotAvailable(() => {
34329
+ if (!manualCheckRef.current) return;
34330
+ setSnackbarMessage("No server updates available. You are up to date!");
34331
+ setSnackbarSeverity("success");
34332
+ setSnackbarOpen(true);
34333
+ });
34296
34334
  return () => {
34297
- removeManualUpdateListener();
34335
+ removeUpdateErrorListener();
34336
+ removeUpdateNotAvailableListener();
34337
+ removeBackendUpdateNotAvailableListener();
34298
34338
  };
34299
34339
  }, []);
34300
34340
  const checkForUpdates = async () => {
34301
34341
  try {
34302
34342
  setChecking(true);
34343
+ manualCheckRef.current = true;
34303
34344
  clearDeferredUpdate();
34304
34345
  await window.api.updater.checkForAllUpdates();
34305
34346
  } catch (error) {
34306
- console.error("Error checking for updates:", error);
34347
+ setSnackbarMessage(
34348
+ `Error checking for updates: ${error instanceof Error ? error.message : String(error)}`
34349
+ );
34350
+ setSnackbarSeverity("error");
34351
+ setSnackbarOpen(true);
34307
34352
  } finally {
34308
34353
  setChecking(false);
34354
+ setTimeout(() => {
34355
+ manualCheckRef.current = false;
34356
+ }, 2e3);
34309
34357
  }
34310
34358
  };
34311
34359
  const handleSnackbarClose = () => {
34312
34360
  setSnackbarOpen(false);
34361
+ setSnackbarMessage(null);
34313
34362
  };
34314
34363
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
34315
34364
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -34355,6 +34404,24 @@ const CheckForUpdatesButton = () => {
34355
34404
  }
34356
34405
  )
34357
34406
  }
34407
+ ),
34408
+ snackbarMessage && /* @__PURE__ */ jsxRuntimeExports.jsx(
34409
+ Snackbar,
34410
+ {
34411
+ open: snackbarOpen,
34412
+ autoHideDuration: 6e3,
34413
+ onClose: handleSnackbarClose,
34414
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
34415
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
34416
+ Alert,
34417
+ {
34418
+ onClose: handleSnackbarClose,
34419
+ severity: snackbarSeverity,
34420
+ sx: { width: "100%" },
34421
+ children: snackbarMessage
34422
+ }
34423
+ )
34424
+ }
34358
34425
  )
34359
34426
  ] });
34360
34427
  };
@@ -35353,7 +35420,7 @@ const useModels = ({ autoFetch = true } = {}) => {
35353
35420
  fetchModels(baseUrl);
35354
35421
  }
35355
35422
  }, [hasConnectivityIssue, autoFetch, isInitialized, baseUrl, fetchModels]);
35356
- const refreshModels = async () => {
35423
+ const refreshModels = reactExports.useCallback(async () => {
35357
35424
  if (shouldEnableQuery({ bypassInternetCheck: true })) {
35358
35425
  await fetchModels(baseUrl, true);
35359
35426
  } else {
@@ -35362,7 +35429,7 @@ const useModels = ({ autoFetch = true } = {}) => {
35362
35429
  throw error2;
35363
35430
  }
35364
35431
  }
35365
- };
35432
+ }, [baseUrl, fetchModels, shouldEnableQuery, getConnectivityError]);
35366
35433
  const getModelById = (modelId) => {
35367
35434
  return models.find((model) => model.id === modelId);
35368
35435
  };
@@ -35848,14 +35915,14 @@ function jwtDecode(token2, options) {
35848
35915
  throw new InvalidTokenError(`Invalid token specified: invalid json for part #${pos + 1} (${e3.message})`);
35849
35916
  }
35850
35917
  }
35851
- function joinUrl(baseUrl, path2) {
35918
+ function joinUrl$1(baseUrl, path2) {
35852
35919
  const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
35853
35920
  const normalizedPath = path2.startsWith("/") ? path2.slice(1) : path2;
35854
35921
  return normalizedBaseUrl + normalizedPath;
35855
35922
  }
35856
35923
  async function exchangeToken(baseUrl, provider, tokens2, clientId) {
35857
35924
  const endpoint = provider === "google" ? "/v1/auth/google" : "/v1/auth/microsoft";
35858
- const url = joinUrl(baseUrl, endpoint);
35925
+ const url = joinUrl$1(baseUrl, endpoint);
35859
35926
  const body2 = {
35860
35927
  id_token: tokens2.idToken,
35861
35928
  access_token: tokens2.accessToken,
@@ -35876,7 +35943,7 @@ async function exchangeToken(baseUrl, provider, tokens2, clientId) {
35876
35943
  return response.json();
35877
35944
  }
35878
35945
  async function createApplication(baseUrl, tenantId, accessToken, applicationData) {
35879
- const url = joinUrl(baseUrl, `/v1/tenants/${tenantId}/applications`);
35946
+ const url = joinUrl$1(baseUrl, `/v1/tenants/${tenantId}/applications`);
35880
35947
  const response = await fetch(url, {
35881
35948
  method: "POST",
35882
35949
  headers: {
@@ -35899,7 +35966,7 @@ async function exchangeMicrosoftToken(baseUrl, tokens2, clientId) {
35899
35966
  return exchangeToken(baseUrl, "microsoft", tokens2, clientId);
35900
35967
  }
35901
35968
  async function getUserInfo(baseUrl, accessToken) {
35902
- const url = joinUrl(baseUrl, "/v1/me");
35969
+ const url = joinUrl$1(baseUrl, "/v1/me");
35903
35970
  const response = await fetch(url, {
35904
35971
  method: "GET",
35905
35972
  headers: {
@@ -35914,7 +35981,7 @@ async function getUserInfo(baseUrl, accessToken) {
35914
35981
  return response.json();
35915
35982
  }
35916
35983
  async function provisionAccount(baseUrl, accessToken) {
35917
- const url = joinUrl(baseUrl, "/v1/provision");
35984
+ const url = joinUrl$1(baseUrl, "/v1/provision");
35918
35985
  const response = await fetch(url, {
35919
35986
  method: "POST",
35920
35987
  headers: {
@@ -35931,7 +35998,7 @@ async function provisionAccount(baseUrl, accessToken) {
35931
35998
  return response.json();
35932
35999
  }
35933
36000
  async function refreshToken(baseUrl, refreshToken2, clientId) {
35934
- const url = joinUrl(baseUrl, "/v1/auth/token");
36001
+ const url = joinUrl$1(baseUrl, "/v1/auth/token");
35935
36002
  const body2 = {
35936
36003
  refresh_token: refreshToken2,
35937
36004
  grant_type: "refresh_token",
@@ -35952,7 +36019,7 @@ async function refreshToken(baseUrl, refreshToken2, clientId) {
35952
36019
  return response.json();
35953
36020
  }
35954
36021
  async function revokeToken(baseUrl, token2, tokenType) {
35955
- const url = joinUrl(baseUrl, "/v1/auth/revoke");
36022
+ const url = joinUrl$1(baseUrl, "/v1/auth/revoke");
35956
36023
  const response = await fetch(url, {
35957
36024
  method: "POST",
35958
36025
  headers: {
@@ -36009,6 +36076,46 @@ const BillingApiImpl = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defi
36009
36076
  __proto__: null,
36010
36077
  getCreditBalance
36011
36078
  }, Symbol.toStringTag, { value: "Module" }));
36079
+ function joinUrl(baseUrl, path2) {
36080
+ const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
36081
+ const normalizedPath = path2.startsWith("/") ? path2.slice(1) : path2;
36082
+ return normalizedBaseUrl + normalizedPath;
36083
+ }
36084
+ const fetchPrices = async (baseUrl) => {
36085
+ const url = joinUrl(baseUrl, "/v1/prices");
36086
+ try {
36087
+ const response = await fetch(url, {
36088
+ method: "GET",
36089
+ headers: {
36090
+ // No Authorization needed for this public endpoint
36091
+ "Content-Type": "application/json"
36092
+ },
36093
+ credentials: "same-origin"
36094
+ // Match credentials policy from auth-api
36095
+ });
36096
+ if (!response.ok) {
36097
+ const errorText = await response.text();
36098
+ console.error(
36099
+ `Error fetching Radient prices: ${response.status} ${errorText}`
36100
+ );
36101
+ throw new Error(
36102
+ errorText || `Failed to fetch Radient prices: ${response.status}`
36103
+ );
36104
+ }
36105
+ const apiResponse = await response.json();
36106
+ return apiResponse.result;
36107
+ } catch (error) {
36108
+ console.error("Error during fetchPrices execution:", error);
36109
+ if (error instanceof Error) {
36110
+ throw error;
36111
+ }
36112
+ throw new Error("An unknown error occurred while fetching prices");
36113
+ }
36114
+ };
36115
+ const PricesApiImpl = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
36116
+ __proto__: null,
36117
+ fetchPrices
36118
+ }, Symbol.toStringTag, { value: "Module" }));
36012
36119
  const getUsageRollup = async (baseUrl, tenantId, accessToken, params) => {
36013
36120
  const endpointUrl = `${baseUrl}/v1/tenants/${tenantId}/usage/rollup`;
36014
36121
  const queryParams = new URLSearchParams();
@@ -36076,6 +36183,12 @@ class RadientClient {
36076
36183
  get usage() {
36077
36184
  return this.bindBaseUrlToApi(UsageApiImpl);
36078
36185
  }
36186
+ /**
36187
+ * Get the Prices API client with methods bound to the base URL
36188
+ */
36189
+ get prices() {
36190
+ return this.bindBaseUrlToApi(PricesApiImpl);
36191
+ }
36079
36192
  /**
36080
36193
  * Bind the base URL to all methods of an API module
36081
36194
  *
@@ -36213,34 +36326,57 @@ async function updateAccessToken(accessToken, expiresIn, newRefreshToken) {
36213
36326
  const expiry = Date.now() + expiresIn * 1e3;
36214
36327
  await window.api.session.storeSession(accessToken, expiry, refreshToken2);
36215
36328
  }
36216
- const queryClient = new QueryClient({
36217
- defaultOptions: {
36218
- queries: {
36219
- // Default stale time of 5 minutes
36220
- staleTime: 5 * 60 * 1e3,
36221
- // Default cache time of 10 minutes
36222
- gcTime: 10 * 60 * 1e3,
36223
- // Default retry configuration
36224
- retry: 1,
36225
- // Default refetch configuration
36226
- refetchOnWindowFocus: true,
36227
- refetchOnMount: true,
36228
- // Don't wait for reconnect to refetch - we handle offline status separately
36229
- refetchOnReconnect: false,
36230
- // Continue to run queries even when offline
36231
- networkMode: "always"
36232
- },
36233
- mutations: {
36234
- // Retry mutations once by default
36235
- retry: 1,
36236
- // Continue to run mutations even when offline
36237
- networkMode: "always"
36238
- }
36239
- }
36240
- });
36241
- const resetQueryCache = () => {
36242
- queryClient.clear();
36329
+ const DEFAULT_PROFILE = {
36330
+ name: "User",
36331
+ email: "user@example.com"
36243
36332
  };
36333
+ const useUserStore = create$1()(
36334
+ persist(
36335
+ (set) => ({
36336
+ profile: DEFAULT_PROFILE,
36337
+ isSigningOut: false,
36338
+ // Default value
36339
+ updateName: (name2) => {
36340
+ set((state) => ({
36341
+ profile: {
36342
+ ...state.profile,
36343
+ name: name2
36344
+ }
36345
+ }));
36346
+ },
36347
+ updateEmail: (email2) => {
36348
+ set((state) => ({
36349
+ profile: {
36350
+ ...state.profile,
36351
+ email: email2
36352
+ }
36353
+ }));
36354
+ },
36355
+ updateProfile: (profile) => {
36356
+ set((state) => ({
36357
+ profile: {
36358
+ ...state.profile,
36359
+ ...profile
36360
+ }
36361
+ }));
36362
+ },
36363
+ setIsSigningOut: (status) => {
36364
+ set({ isSigningOut: status });
36365
+ },
36366
+ clearProfile: () => {
36367
+ set({
36368
+ profile: {
36369
+ name: "",
36370
+ email: ""
36371
+ }
36372
+ });
36373
+ }
36374
+ }),
36375
+ {
36376
+ name: "user-profile-storage"
36377
+ }
36378
+ )
36379
+ );
36244
36380
  const radientUserKeys = {
36245
36381
  all: ["radient-user"],
36246
36382
  user: () => [...radientUserKeys.all, "user"],
@@ -36249,6 +36385,7 @@ const radientUserKeys = {
36249
36385
  };
36250
36386
  const useRadientUserQuery = () => {
36251
36387
  const queryClient2 = useQueryClient();
36388
+ const { setIsSigningOut } = useUserStore();
36252
36389
  const radientClient2 = createRadientClient(
36253
36390
  apiConfig.radientBaseUrl,
36254
36391
  apiConfig.radientClientId
@@ -36369,6 +36506,9 @@ const useRadientUserQuery = () => {
36369
36506
  const hasLocalSession = !!sessionQuery.data && !sessionQuery.isLoading;
36370
36507
  const isAuthenticated = !!userQuery.data && !userQuery.isLoading;
36371
36508
  const signOutMutation = useMutation({
36509
+ onMutate: () => {
36510
+ setIsSigningOut(true);
36511
+ },
36372
36512
  mutationFn: async () => {
36373
36513
  const session = sessionQuery.data;
36374
36514
  if (session?.refreshToken) {
@@ -36381,16 +36521,20 @@ const useRadientUserQuery = () => {
36381
36521
  console.error("Failed to revoke refresh token:", error);
36382
36522
  }
36383
36523
  }
36384
- clearSession();
36524
+ await clearSession();
36385
36525
  return true;
36386
36526
  },
36387
- onSuccess: () => {
36388
- resetQueryCache();
36527
+ onSuccess: async () => {
36528
+ await clearSession();
36529
+ queryClient2.removeQueries({ queryKey: radientUserKeys.all });
36530
+ refreshTokenMutation.reset();
36389
36531
  showSuccessToast("Successfully signed out");
36532
+ setIsSigningOut(false);
36390
36533
  },
36391
36534
  onError: (error) => {
36392
36535
  const errorMessage = error instanceof Error ? error.message : String(error);
36393
36536
  showErrorToast(`Failed to sign out: ${errorMessage}`);
36537
+ setIsSigningOut(false);
36394
36538
  }
36395
36539
  });
36396
36540
  const refreshUserMutation = useMutation({
@@ -36471,7 +36615,7 @@ const radientClient = createRadientClient(
36471
36615
  apiConfig.radientClientId
36472
36616
  );
36473
36617
  const useOidcAuth = (options) => {
36474
- const { onSuccess } = options || {};
36618
+ const { onSuccess, onAfterCredentialUpdate } = options || {};
36475
36619
  const [loading, setLoading] = reactExports.useState(true);
36476
36620
  const [error, setError] = reactExports.useState(null);
36477
36621
  const [status, setStatus] = reactExports.useState({
@@ -36538,6 +36682,13 @@ const useOidcAuth = (options) => {
36538
36682
  key: "RADIENT_API_KEY",
36539
36683
  value: appResponse.result.api_key
36540
36684
  });
36685
+ if (onAfterCredentialUpdate) {
36686
+ try {
36687
+ onAfterCredentialUpdate();
36688
+ } catch (err) {
36689
+ console.error("Error in onAfterCredentialUpdate callback:", err);
36690
+ }
36691
+ }
36541
36692
  try {
36542
36693
  await updateConfig({
36543
36694
  hosting: "radient",
@@ -36566,9 +36717,59 @@ const useOidcAuth = (options) => {
36566
36717
  showErrorToast(msg || "Authentication failed");
36567
36718
  }
36568
36719
  },
36569
- [queryClient2, updateConfig, onSuccess]
36570
- // Added onSuccess dependency
36720
+ [queryClient2, updateConfig, onSuccess, onAfterCredentialUpdate]
36571
36721
  );
36722
+ const signInWithGoogle = reactExports.useCallback(async () => {
36723
+ setLoading(true);
36724
+ setError(null);
36725
+ try {
36726
+ const result = await window.api.oauth.login("google");
36727
+ if (!result.success) {
36728
+ throw new Error(result.error || "Failed to initiate Google login");
36729
+ }
36730
+ } catch (err) {
36731
+ const msg = err instanceof Error ? err.message : String(err);
36732
+ console.error("Error initiating Google sign-in:", msg);
36733
+ setError(msg);
36734
+ showErrorToast(msg);
36735
+ setLoading(false);
36736
+ }
36737
+ }, []);
36738
+ const signInWithMicrosoft = reactExports.useCallback(async () => {
36739
+ setLoading(true);
36740
+ setError(null);
36741
+ try {
36742
+ const result = await window.api.oauth.login("microsoft");
36743
+ if (!result.success) {
36744
+ throw new Error(result.error || "Failed to initiate Microsoft login");
36745
+ }
36746
+ } catch (err) {
36747
+ const msg = err instanceof Error ? err.message : String(err);
36748
+ console.error("Error initiating Microsoft sign-in:", msg);
36749
+ setError(msg);
36750
+ showErrorToast(msg);
36751
+ setLoading(false);
36752
+ }
36753
+ }, []);
36754
+ const logout = reactExports.useCallback(async () => {
36755
+ setLoading(true);
36756
+ setError(null);
36757
+ try {
36758
+ const result = await window.api.oauth.logout();
36759
+ if (!result.success) {
36760
+ throw new Error(result.error || "Logout failed");
36761
+ }
36762
+ await window.api.session.clearSession();
36763
+ queryClient2.invalidateQueries({ queryKey: radientUserKeys.all });
36764
+ showSuccessToast("Successfully signed out.");
36765
+ } catch (err) {
36766
+ const msg = err instanceof Error ? err.message : String(err);
36767
+ console.error("Error during logout:", msg);
36768
+ setError(msg);
36769
+ showErrorToast(msg);
36770
+ setLoading(false);
36771
+ }
36772
+ }, [queryClient2]);
36572
36773
  reactExports.useEffect(() => {
36573
36774
  const cleanup = window.api.oauth.onStatusUpdate((newStatus) => {
36574
36775
  setStatus(newStatus);
@@ -36627,57 +36828,6 @@ const useOidcAuth = (options) => {
36627
36828
  };
36628
36829
  checkInitialStatus();
36629
36830
  }, []);
36630
- const signInWithGoogle = reactExports.useCallback(async () => {
36631
- setLoading(true);
36632
- setError(null);
36633
- try {
36634
- const result = await window.api.oauth.login("google");
36635
- if (!result.success) {
36636
- throw new Error(result.error || "Failed to initiate Google login");
36637
- }
36638
- } catch (err) {
36639
- const msg = err instanceof Error ? err.message : String(err);
36640
- console.error("Error initiating Google sign-in:", msg);
36641
- setError(msg);
36642
- showErrorToast(msg);
36643
- setLoading(false);
36644
- }
36645
- }, []);
36646
- const signInWithMicrosoft = reactExports.useCallback(async () => {
36647
- setLoading(true);
36648
- setError(null);
36649
- try {
36650
- const result = await window.api.oauth.login("microsoft");
36651
- if (!result.success) {
36652
- throw new Error(result.error || "Failed to initiate Microsoft login");
36653
- }
36654
- } catch (err) {
36655
- const msg = err instanceof Error ? err.message : String(err);
36656
- console.error("Error initiating Microsoft sign-in:", msg);
36657
- setError(msg);
36658
- showErrorToast(msg);
36659
- setLoading(false);
36660
- }
36661
- }, []);
36662
- const logout = reactExports.useCallback(async () => {
36663
- setLoading(true);
36664
- setError(null);
36665
- try {
36666
- const result = await window.api.oauth.logout();
36667
- if (!result.success) {
36668
- throw new Error(result.error || "Logout failed");
36669
- }
36670
- await window.api.session.clearSession();
36671
- queryClient2.invalidateQueries({ queryKey: radientUserKeys.all });
36672
- showSuccessToast("Successfully signed out.");
36673
- } catch (err) {
36674
- const msg = err instanceof Error ? err.message : String(err);
36675
- console.error("Error during logout:", msg);
36676
- setError(msg);
36677
- showErrorToast(msg);
36678
- setLoading(false);
36679
- }
36680
- }, [queryClient2]);
36681
36831
  return {
36682
36832
  signInWithGoogle,
36683
36833
  signInWithMicrosoft,
@@ -36710,56 +36860,15 @@ const usePaginationParams = () => {
36710
36860
  isView: (view) => location2.pathname.startsWith(`/${view}`)
36711
36861
  };
36712
36862
  };
36713
- const DEFAULT_PROFILE = {
36714
- name: "User",
36715
- email: "user@example.com"
36716
- };
36717
- const useUserStore = create$1()(
36718
- persist(
36719
- (set) => ({
36720
- profile: DEFAULT_PROFILE,
36721
- updateName: (name2) => {
36722
- set((state) => ({
36723
- profile: {
36724
- ...state.profile,
36725
- name: name2
36726
- }
36727
- }));
36728
- },
36729
- updateEmail: (email2) => {
36730
- set((state) => ({
36731
- profile: {
36732
- ...state.profile,
36733
- email: email2
36734
- }
36735
- }));
36736
- },
36737
- updateProfile: (profile) => {
36738
- set((state) => ({
36739
- profile: {
36740
- ...state.profile,
36741
- ...profile
36742
- }
36743
- }));
36744
- }
36745
- }),
36746
- {
36747
- name: "user-profile-storage"
36748
- }
36749
- )
36750
- );
36751
36863
  const useRadientAuth = () => {
36752
36864
  const userStore = useUserStore();
36753
36865
  const {
36754
36866
  user: radientUser,
36755
36867
  session,
36756
36868
  isLoading,
36757
- // Combined loading state from useRadientUserQuery
36758
36869
  error,
36759
36870
  isAuthenticated,
36760
- // Backend validated flag from useRadientUserQuery
36761
36871
  hasLocalSession,
36762
- // Local token exists flag from useRadientUserQuery
36763
36872
  signOut,
36764
36873
  refreshUser,
36765
36874
  refreshToken: refreshToken2
@@ -36773,7 +36882,7 @@ const useRadientAuth = () => {
36773
36882
  authStatus = "unauthenticated";
36774
36883
  }
36775
36884
  reactExports.useEffect(() => {
36776
- if (!radientUser?.account) {
36885
+ if (!isAuthenticated || !radientUser?.account) {
36777
36886
  return;
36778
36887
  }
36779
36888
  const { account } = radientUser;
@@ -36787,31 +36896,23 @@ const useRadientAuth = () => {
36787
36896
  email: account.email || currentEmail
36788
36897
  });
36789
36898
  }
36790
- }, [radientUser, userStore]);
36899
+ }, [isAuthenticated, radientUser, userStore]);
36791
36900
  return {
36792
36901
  // Authentication state
36793
36902
  authStatus,
36794
- // Use the new combined status
36795
36903
  isAuthenticated,
36796
- // Keep backend-validated flag for detailed checks if needed
36797
36904
  hasLocalSession,
36798
- // Expose this flag
36799
36905
  isLoading,
36800
- // Keep the combined loading flag
36801
36906
  error,
36802
- // User information (from Radient or fallback to user store)
36803
- user: {
36804
- name: radientUser?.account?.name || userStore.profile.name,
36805
- email: radientUser?.account?.email || userStore.profile.email,
36806
- // Include the full Radient user object if available
36907
+ // User information: only return if authenticated, otherwise null
36908
+ user: isAuthenticated && radientUser?.account ? {
36909
+ name: radientUser.account.name,
36910
+ email: radientUser.account.email,
36807
36911
  radientUser
36808
- // Added type assertion for clarity
36809
- },
36912
+ } : null,
36810
36913
  // Session token for API calls
36811
36914
  sessionToken: session?.accessToken,
36812
- // Expose the full session for advanced use cases
36813
36915
  session,
36814
- // Token refresh function
36815
36916
  refreshToken: refreshToken2,
36816
36917
  // Actions
36817
36918
  refreshUser,
@@ -37950,20 +38051,18 @@ const FieldContainer$3 = styled$1(Box)({
37950
38051
  marginBottom: 16
37951
38052
  // Reduced margin
37952
38053
  });
37953
- const FieldLabel$4 = styled$1(Typography)(({ theme: theme2 }) => ({
37954
- marginBottom: 6,
37955
- // Reduced margin
38054
+ const FieldLabel$4 = styled$1("label")(({ theme: theme2 }) => ({
37956
38055
  display: "flex",
37957
38056
  alignItems: "center",
38057
+ marginBottom: 6,
37958
38058
  color: theme2.palette.text.secondary,
37959
38059
  fontWeight: 500,
37960
- // Slightly less bold
37961
- fontSize: "0.875rem"
37962
- // Small text size
38060
+ fontSize: "0.875rem",
38061
+ fontFamily: theme2.typography.fontFamily,
38062
+ lineHeight: theme2.typography.body2.lineHeight
37963
38063
  }));
37964
38064
  const LabelIcon$4 = styled$1(Box)({
37965
38065
  marginRight: 8,
37966
- // Reduced margin
37967
38066
  opacity: 0.9,
37968
38067
  display: "flex",
37969
38068
  alignItems: "center"
@@ -37972,233 +38071,156 @@ const StyledTextField$4 = styled$1(TextField)(
37972
38071
  ({ theme: theme2, multiline }) => ({
37973
38072
  "& .MuiOutlinedInput-root": {
37974
38073
  borderRadius: 6,
37975
- // Slightly less rounded
37976
38074
  backgroundColor: theme2.palette.background.paper,
37977
- // Use paper background
37978
38075
  border: `1px solid ${theme2.palette.divider}`,
37979
- // Use divider color for border
37980
38076
  padding: 0,
37981
- // Remove root padding
37982
38077
  minHeight: multiline ? "auto" : "36px",
37983
- // Target height
37984
38078
  height: multiline ? "auto" : "36px",
37985
- // Explicit height
37986
38079
  alignItems: multiline ? "flex-start" : "center",
37987
38080
  transition: "border-color 0.2s ease, box-shadow 0.2s ease",
37988
38081
  "&:hover": {
37989
38082
  borderColor: theme2.palette.text.secondary,
37990
- // Darker border on hover
37991
38083
  backgroundColor: theme2.palette.background.paper
37992
- // Keep background consistent
37993
38084
  },
37994
38085
  "&.Mui-focused": {
37995
38086
  backgroundColor: theme2.palette.background.paper,
37996
- // Keep background consistent
37997
38087
  borderColor: theme2.palette.primary.main,
37998
- // Primary border color on focus
37999
38088
  boxShadow: `0 0 0 2px ${theme2.palette.primary.main}33`
38000
- // Subtle focus ring like shadcn
38001
38089
  },
38002
- // Remove default outline
38003
38090
  "& .MuiOutlinedInput-notchedOutline": {
38004
38091
  border: "none"
38005
38092
  }
38006
38093
  },
38007
38094
  "& .MuiInputBase-input": {
38008
38095
  padding: multiline ? "8px 12px" : "4px 12px",
38009
- // Target inner padding (vertical 4px)
38010
38096
  fontSize: "0.875rem",
38011
- // Small text size
38012
38097
  lineHeight: 1.5,
38013
- // Adjusted line height
38014
38098
  fontFamily: "inherit",
38015
38099
  height: multiline ? "auto" : "calc(36px - 8px)",
38016
- // Adjust height based on padding
38017
- // Ensure text doesn't overflow container
38018
38100
  overflow: "hidden",
38019
38101
  textOverflow: "ellipsis",
38020
38102
  whiteSpace: multiline ? "pre-wrap" : "nowrap",
38021
38103
  wordBreak: "break-word",
38022
- // Keep break-word for multiline
38023
38104
  alignSelf: multiline ? "flex-start" : "center"
38024
- // Center single line text vertically
38025
38105
  },
38026
- // Style placeholder
38027
38106
  "& .MuiInputBase-input::placeholder": {
38028
38107
  color: theme2.palette.text.disabled,
38029
38108
  opacity: 1
38030
- // Ensure placeholder is visible
38031
38109
  }
38032
38110
  })
38033
38111
  );
38034
38112
  const ActionButtonsContainer = styled$1(Box)({
38035
38113
  position: "absolute",
38036
38114
  top: "50%",
38037
- // Center vertically
38038
38115
  transform: "translateY(-50%)",
38039
- // Adjust vertical centering
38040
38116
  right: 6,
38041
- // Position from right
38042
38117
  display: "flex",
38043
38118
  alignItems: "center",
38044
- // Align items vertically
38045
38119
  gap: 4,
38046
38120
  zIndex: 10
38047
38121
  });
38048
38122
  const ActionIconButton = styled$1(IconButton)(({ theme: theme2 }) => ({
38049
38123
  padding: 4,
38050
- // Smaller padding
38051
38124
  borderRadius: 4,
38052
- // Slightly rounded corners
38053
38125
  height: 24,
38054
- // Smaller height
38055
38126
  width: 24,
38056
- // Smaller width
38057
38127
  color: theme2.palette.text.secondary,
38058
- // Default color
38059
38128
  "&:hover": {
38060
38129
  backgroundColor: theme2.palette.action.hover,
38061
- // Subtle hover background
38062
38130
  color: theme2.palette.text.primary
38063
38131
  }
38064
38132
  }));
38065
38133
  const SaveButton = styled$1(ActionIconButton)(({ theme: theme2 }) => ({
38066
38134
  color: theme2.palette.success.main,
38067
- // Green color for save
38068
38135
  "&:hover": {
38069
38136
  backgroundColor: `${theme2.palette.success.main}1A`,
38070
- // Lighter green background on hover
38071
38137
  color: theme2.palette.success.dark
38072
38138
  }
38073
38139
  }));
38074
38140
  const CancelButton = styled$1(ActionIconButton)(({ theme: theme2 }) => ({
38075
38141
  color: theme2.palette.error.main,
38076
- // Red color for cancel/close
38077
38142
  "&:hover": {
38078
38143
  backgroundColor: `${theme2.palette.error.main}1A`,
38079
- // Lighter red background on hover
38080
38144
  color: theme2.palette.error.dark
38081
38145
  }
38082
38146
  }));
38083
38147
  const ClearButton = styled$1(Button)(({ theme: theme2 }) => ({
38084
38148
  backgroundColor: theme2.palette.action.selected,
38085
- // Use a subtle background
38086
38149
  color: theme2.palette.error.main,
38087
- // Destructive text color
38088
38150
  minWidth: "auto",
38089
38151
  height: 24,
38090
- // Match icon button height
38091
38152
  padding: "0 8px",
38092
- // Horizontal padding
38093
38153
  fontSize: "0.75rem",
38094
- // Smaller text
38095
38154
  borderRadius: 4,
38096
38155
  textTransform: "none",
38097
- // No uppercase
38098
38156
  boxShadow: "none",
38099
38157
  border: `1px solid ${theme2.palette.action.disabledBackground}`,
38100
- // Subtle border
38101
38158
  marginLeft: 4,
38102
- // Add some space from icons
38103
38159
  marginRight: 16,
38104
38160
  "&:hover": {
38105
38161
  backgroundColor: theme2.palette.action.hover,
38106
- // Consistent hover
38107
38162
  borderColor: theme2.palette.error.light,
38108
38163
  boxShadow: "none"
38109
38164
  },
38110
- // Adjust icon size and margin
38111
38165
  "& .MuiButton-startIcon": {
38112
38166
  marginRight: 4,
38113
38167
  marginLeft: -2,
38114
38168
  "& > *:nth-of-type(1)": {
38115
- // Target the FontAwesomeIcon
38116
38169
  fontSize: "0.8rem"
38117
38170
  }
38118
38171
  }
38119
38172
  }));
38120
- const DisplayContainer = styled$1(Button, {
38173
+ const DisplayContainer = styled$1("button", {
38121
38174
  shouldForwardProp: (prop) => prop !== "multiline"
38122
- // Explicitly type the props passed to the styled Button
38123
38175
  })(({ theme: theme2, multiline }) => ({
38124
38176
  padding: multiline ? "8px 12px" : "4px 12px",
38125
- // Match input padding
38126
38177
  borderRadius: 6,
38127
- // Match input border radius
38128
38178
  backgroundColor: theme2.palette.background.paper,
38129
- // Match input background
38130
38179
  border: `1px solid ${theme2.palette.divider}`,
38131
- // Match input border
38132
38180
  position: "relative",
38133
38181
  minHeight: multiline ? "auto" : "36px",
38134
- // Match input height
38135
38182
  height: multiline ? "auto" : "36px",
38136
- // Explicit height
38137
38183
  display: "flex",
38138
38184
  alignItems: multiline ? "flex-start" : "center",
38139
- // Align text
38140
38185
  transition: "border-color 0.2s ease, background-color 0.2s ease",
38141
38186
  cursor: "pointer",
38142
38187
  boxSizing: "border-box",
38143
- // Ensure padding/border are included in height
38144
- // Button specific resets/styles
38145
38188
  width: "100%",
38146
- // Ensure it takes full width like the input
38147
38189
  textAlign: "left",
38148
- // Align text to the left
38149
38190
  textTransform: "none",
38150
- // Reset button text transform
38151
38191
  justifyContent: "flex-start",
38152
- // Align content (icon, text) to the start
38153
38192
  color: theme2.palette.text.primary,
38154
- // Ensure text color matches input text
38155
38193
  fontWeight: "normal",
38156
- // Reset button font weight
38157
38194
  fontFamily: "inherit",
38158
- // Use default font
38159
- "&:hover": {
38195
+ outline: "none",
38196
+ "&:hover, &:focus": {
38160
38197
  borderColor: theme2.palette.text.secondary,
38161
- // Match input hover border
38162
- backgroundColor: theme2.palette.action.hover,
38163
- // Subtle background change on hover
38164
- "& .edit-button": {
38165
- opacity: 1
38166
- // Show edit button on hover
38167
- }
38198
+ backgroundColor: theme2.palette.action.hover
38199
+ },
38200
+ "&:focus-visible": {
38201
+ outline: `2px solid ${theme2.palette.primary.main}`
38168
38202
  }
38169
38203
  }));
38170
38204
  const DisplayText = styled$1(Typography, {
38171
38205
  shouldForwardProp: (prop) => prop !== "multiline"
38172
38206
  })(({ multiline }) => ({
38173
38207
  fontSize: "0.875rem",
38174
- // Match input text size
38175
38208
  lineHeight: 1.5,
38176
- // Match input line height
38177
38209
  fontFamily: "inherit",
38178
- // Use standard font
38179
38210
  whiteSpace: multiline ? "pre-wrap" : "nowrap",
38180
38211
  wordBreak: "break-word",
38181
38212
  paddingRight: 30,
38182
- // Space for the edit button
38183
38213
  overflow: "hidden",
38184
- // Prevent overflow
38185
38214
  textOverflow: "ellipsis",
38186
- // Add ellipsis if text is too long
38187
38215
  flexGrow: 1,
38188
- // Allow text to take available space
38189
38216
  alignSelf: multiline ? "flex-start" : "center"
38190
- // Center single line text vertically
38191
38217
  }));
38192
38218
  const PlaceholderText = styled$1(Typography)(({ theme: theme2 }) => ({
38193
38219
  color: theme2.palette.text.disabled,
38194
38220
  fontStyle: "normal",
38195
- // Remove italic
38196
38221
  fontSize: "0.875rem",
38197
- // Match input text size
38198
38222
  lineHeight: 1.5,
38199
- // Match input line height
38200
38223
  paddingRight: 30,
38201
- // Space for the edit button
38202
38224
  overflow: "hidden",
38203
38225
  textOverflow: "ellipsis",
38204
38226
  whiteSpace: "nowrap",
@@ -38207,28 +38229,18 @@ const PlaceholderText = styled$1(Typography)(({ theme: theme2 }) => ({
38207
38229
  const EditButton = styled$1(IconButton)(({ theme: theme2 }) => ({
38208
38230
  position: "absolute",
38209
38231
  top: "50%",
38210
- // Center vertically
38211
38232
  transform: "translateY(-50%)",
38212
- // Adjust vertical centering
38213
38233
  right: 6,
38214
- // Position from right
38215
38234
  color: theme2.palette.text.secondary,
38216
- // Use secondary text color
38217
38235
  opacity: 0,
38218
- // Hidden by default
38219
38236
  transition: "opacity 0.2s ease, background-color 0.2s ease, color 0.2s ease",
38220
38237
  padding: 4,
38221
- // Match other icon buttons
38222
38238
  borderRadius: 4,
38223
- // Match other icon buttons
38224
38239
  height: 24,
38225
- // Match other icon buttons
38226
38240
  width: 24,
38227
- // Match other icon buttons
38228
38241
  marginLeft: 4,
38229
38242
  "&:hover": {
38230
38243
  backgroundColor: theme2.palette.action.hover,
38231
- // Subtle hover background
38232
38244
  color: theme2.palette.text.primary
38233
38245
  }
38234
38246
  }));
@@ -38411,62 +38423,64 @@ const EditableField = ({
38411
38423
  }
38412
38424
  )
38413
38425
  ] }) })
38414
- ] }) : (
38415
- // Using Box with role="button" is acceptable for MUI, but ensure accessibility attributes are correct
38416
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
38426
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { position: "relative", width: "100%" }, children: [
38427
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
38417
38428
  DisplayContainer,
38418
38429
  {
38430
+ type: "button",
38419
38431
  onClick: handleEdit,
38420
38432
  multiline,
38421
38433
  "aria-label": `Current value: ${displayValue || placeholder2}. Click to edit.`,
38422
- tabIndex: 0,
38423
38434
  onKeyDown: handleDisplayContainerKeyDown,
38424
- children: [
38425
- displayValue ? /* @__PURE__ */ jsxRuntimeExports.jsx(DisplayText, { multiline, children: displayValue }) : /* @__PURE__ */ jsxRuntimeExports.jsx(PlaceholderText, { children: placeholder2 }),
38426
- /* @__PURE__ */ jsxRuntimeExports.jsx(
38427
- EditButton,
38428
- {
38429
- className: "edit-button",
38430
- size: "small",
38431
- onClick: (e3) => {
38432
- e3.stopPropagation();
38433
- handleEdit();
38434
- },
38435
- title: "Edit",
38436
- "aria-label": `Edit ${label}`,
38437
- tabIndex: -1,
38438
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPen, size: "xs" })
38439
- }
38440
- ),
38441
- showClearButton && /* @__PURE__ */ jsxRuntimeExports.jsx(
38442
- ClearButton,
38443
- {
38444
- className: "edit-button",
38445
- sx: {
38446
- position: "absolute",
38447
- top: "50%",
38448
- transform: "translateY(-50%)",
38449
- // Position next to edit icon, adjust based on icon size/padding
38450
- right: 30,
38451
- opacity: 0,
38452
- // Hidden by default
38453
- transition: "opacity 0.2s ease",
38454
- pointerEvents: "auto"
38455
- // Ensure it's clickable when visible
38456
- },
38457
- size: "small",
38458
- onClick: clearField,
38459
- title: "Clear field",
38460
- "aria-label": `Clear ${label}`,
38461
- startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faEraser }),
38462
- tabIndex: -1,
38463
- children: "Clear"
38464
- }
38465
- )
38466
- ]
38435
+ children: displayValue ? /* @__PURE__ */ jsxRuntimeExports.jsx(DisplayText, { multiline, children: displayValue }) : /* @__PURE__ */ jsxRuntimeExports.jsx(PlaceholderText, { children: placeholder2 })
38436
+ }
38437
+ ),
38438
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
38439
+ EditButton,
38440
+ {
38441
+ className: "edit-button",
38442
+ size: "small",
38443
+ sx: {
38444
+ position: "absolute",
38445
+ top: "50%",
38446
+ right: 6,
38447
+ transform: "translateY(-50%)",
38448
+ opacity: 0,
38449
+ transition: "opacity 0.2s ease",
38450
+ pointerEvents: "auto",
38451
+ "&:hover, &:focus, button:focus + &": { opacity: 1 }
38452
+ },
38453
+ onClick: handleEdit,
38454
+ title: "Edit",
38455
+ "aria-label": `Edit ${label}`,
38456
+ tabIndex: -1,
38457
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPen, size: "xs" })
38458
+ }
38459
+ ),
38460
+ showClearButton && /* @__PURE__ */ jsxRuntimeExports.jsx(
38461
+ ClearButton,
38462
+ {
38463
+ className: "edit-button",
38464
+ sx: {
38465
+ position: "absolute",
38466
+ top: "50%",
38467
+ right: 36,
38468
+ transform: "translateY(-50%)",
38469
+ opacity: 0,
38470
+ transition: "opacity 0.2s ease",
38471
+ pointerEvents: "auto",
38472
+ "&:hover, &:focus, button:focus + &": { opacity: 1 }
38473
+ },
38474
+ size: "small",
38475
+ onClick: clearField,
38476
+ title: "Clear field",
38477
+ "aria-label": `Clear ${label}`,
38478
+ startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faEraser }),
38479
+ tabIndex: -1,
38480
+ children: "Clear"
38467
38481
  }
38468
38482
  )
38469
- )
38483
+ ] })
38470
38484
  ] });
38471
38485
  };
38472
38486
  const StyledIcon$1 = styled$1(FontAwesomeIcon)(({ theme: theme2 }) => ({
@@ -46311,10 +46325,13 @@ const HostingSelect = ({
46311
46325
  },
46312
46326
  getOptionLabel: (option2) => option2.name,
46313
46327
  isOptionEqualToValue: (option2, value2) => option2.id === value2.id,
46314
- renderOption: (props2, option2) => /* @__PURE__ */ jsxRuntimeExports.jsx("li", { ...props2, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(OptionContainer$1, { children: [
46315
- /* @__PURE__ */ jsxRuntimeExports.jsx(OptionLabel$1, { children: option2.name }),
46316
- option2.description && /* @__PURE__ */ jsxRuntimeExports.jsx(OptionDescription$1, { children: option2.description })
46317
- ] }) }),
46328
+ renderOption: (props2, option2) => {
46329
+ const { key, ...rest } = props2;
46330
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("li", { ...rest, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(OptionContainer$1, { children: [
46331
+ /* @__PURE__ */ jsxRuntimeExports.jsx(OptionLabel$1, { children: option2.name }),
46332
+ option2.description && /* @__PURE__ */ jsxRuntimeExports.jsx(OptionDescription$1, { children: option2.description })
46333
+ ] }) }, key);
46334
+ },
46318
46335
  freeSolo: allowCustom,
46319
46336
  renderInput: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx(
46320
46337
  TextField,
@@ -55915,16 +55932,15 @@ const ModelSelect = ({
55915
55932
  return void 0;
55916
55933
  }, [hostingId, refreshModels, isModelsLoading]);
55917
55934
  const modelOptions = reactExports.useMemo(() => {
55918
- const options = [
55919
- {
55920
- id: "",
55921
- name: "Default",
55922
- description: "Clear model selection",
55923
- model: void 0
55924
- }
55925
- ];
55935
+ const optionsMap = /* @__PURE__ */ new Map();
55936
+ optionsMap.set("", {
55937
+ id: "",
55938
+ name: "Default",
55939
+ description: "Clear model selection",
55940
+ model: void 0
55941
+ });
55926
55942
  for (const model of availableModels) {
55927
- options.push({
55943
+ optionsMap.set(model.id, {
55928
55944
  id: model.id,
55929
55945
  name: model.name,
55930
55946
  description: model.description,
@@ -55932,30 +55948,15 @@ const ModelSelect = ({
55932
55948
  recommended: model.recommended
55933
55949
  });
55934
55950
  }
55935
- const modelExists = availableModels.some((model) => {
55936
- if (model.id === value) {
55937
- return true;
55938
- }
55939
- if (value?.includes("/")) {
55940
- return model.id?.endsWith(value.split("/")[1]);
55941
- }
55942
- if (value && !value.includes("/")) {
55943
- if (model.id.includes("/")) {
55944
- return model.id.endsWith(`/${value}`);
55945
- }
55946
- return model.id === value;
55947
- }
55948
- return false;
55949
- });
55950
- if (value && value.trim() !== "" && !modelExists) {
55951
- options.push({
55951
+ if (value && value.trim() !== "" && !optionsMap.has(value)) {
55952
+ optionsMap.set(value, {
55952
55953
  id: value,
55953
55954
  name: value,
55954
55955
  description: "Custom model",
55955
55956
  model: void 0
55956
55957
  });
55957
55958
  }
55958
- return options;
55959
+ return Array.from(optionsMap.values());
55959
55960
  }, [availableModels, value]);
55960
55961
  const helperText = reactExports.useMemo(() => {
55961
55962
  if (availableModels.length === 0 && hostingId) {
@@ -56158,19 +56159,20 @@ const ModelSelect = ({
56158
56159
  ] });
56159
56160
  };
56160
56161
  const FieldContainer = styled$1(Box)({
56161
- marginBottom: 24,
56162
- position: "relative"
56162
+ position: "relative",
56163
+ marginBottom: 16
56163
56164
  });
56164
- const FieldLabel$1 = styled$1(Typography)(({ theme: theme2 }) => ({
56165
+ const FieldLabel$1 = styled$1("div")(({ theme: theme2 }) => ({
56166
+ fontFamily: theme2.typography.fontFamily,
56167
+ fontSize: "0.875rem",
56168
+ // Small text size
56169
+ fontWeight: 500,
56170
+ // Slightly less bold
56171
+ color: theme2.palette.text.secondary,
56165
56172
  marginBottom: 6,
56166
56173
  // Reduced margin
56167
56174
  display: "flex",
56168
- alignItems: "center",
56169
- color: theme2.palette.text.secondary,
56170
- fontWeight: 500,
56171
- // Slightly less bold
56172
- fontSize: "0.875rem"
56173
- // Small text size
56175
+ alignItems: "center"
56174
56176
  }));
56175
56177
  const LabelIcon$1 = styled$1(Box)({
56176
56178
  marginRight: 8,
@@ -56202,42 +56204,57 @@ const TitleIcon$2 = styled$1(FontAwesomeIcon)(({ theme: theme2 }) => ({
56202
56204
  }));
56203
56205
  const InfoCard = styled$1(Box)(({ theme: theme2 }) => ({
56204
56206
  display: "flex",
56205
- // Keep flex for vertical alignment if needed
56206
56207
  alignItems: "center",
56207
- // Align text vertically
56208
56208
  height: "36px",
56209
- // Match input height
56210
56209
  padding: theme2.spacing(0.5, 1.5),
56211
- // Match input padding (4px 12px)
56212
56210
  borderRadius: 4,
56213
- // Less rounded corners
56214
56211
  backgroundColor: theme2.palette.background.paper,
56215
- // Use paper background
56216
56212
  border: `1px solid ${theme2.palette.divider}`,
56217
- // Use divider color for border
56218
56213
  boxSizing: "border-box",
56219
56214
  width: "100%",
56220
- // Take full width of the grid item
56221
56215
  overflow: "hidden"
56222
- // Prevent text overflow
56223
56216
  }));
56224
56217
  const ValueText = styled$1(Typography)(({ theme: theme2 }) => ({
56225
- // Keep as Typography for consistency
56226
56218
  fontWeight: 400,
56227
- // Normal weight for value text inside the box
56228
56219
  fontSize: "0.875rem",
56229
56220
  color: theme2.palette.text.primary,
56230
56221
  whiteSpace: "nowrap",
56231
- // Prevent wrapping
56232
56222
  overflow: "hidden",
56233
- // Hide overflow
56234
56223
  textOverflow: "ellipsis"
56235
- // Add ellipsis
56236
56224
  }));
56237
56225
  const MonospaceValueText = styled$1(ValueText)(({ theme: theme2 }) => ({
56238
56226
  fontFamily: "monospace",
56239
56227
  color: theme2.palette.mode === "light" ? theme2.palette.grey[900] : theme2.palette.text.primary
56240
56228
  }));
56229
+ const ModelPlaceholderContainer = styled$1("div")(({ theme: theme2 }) => ({
56230
+ padding: "4px 12px",
56231
+ borderRadius: 6,
56232
+ backgroundColor: theme2.palette.background.paper,
56233
+ border: `1px solid ${theme2.palette.divider}`,
56234
+ position: "relative",
56235
+ minHeight: "36px",
56236
+ height: "36px",
56237
+ display: "flex",
56238
+ alignItems: "center",
56239
+ boxSizing: "border-box",
56240
+ width: "100%",
56241
+ textAlign: "left",
56242
+ justifyContent: "flex-start",
56243
+ color: theme2.palette.text.primary,
56244
+ fontWeight: "normal",
56245
+ fontFamily: "inherit"
56246
+ }));
56247
+ const ModelPlaceholderText = styled$1("div")(({ theme: theme2 }) => ({
56248
+ color: theme2.palette.text.disabled,
56249
+ fontStyle: "normal",
56250
+ fontSize: "0.875rem",
56251
+ lineHeight: 1.5,
56252
+ paddingRight: 30,
56253
+ overflow: "hidden",
56254
+ textOverflow: "ellipsis",
56255
+ whiteSpace: "nowrap",
56256
+ flexGrow: 1
56257
+ }));
56241
56258
  const GeneralSettings = ({
56242
56259
  selectedAgent,
56243
56260
  savingField,
@@ -56281,7 +56298,8 @@ const GeneralSettings = ({
56281
56298
  }
56282
56299
  }
56283
56300
  ) }),
56284
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Grid, { container: true, spacing: 2, children: [
56301
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Grid, { container: true, spacing: 2, alignItems: "center", children: [
56302
+ " ",
56285
56303
  /* @__PURE__ */ jsxRuntimeExports.jsx(Grid, { item: true, xs: 12, md: 6, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
56286
56304
  HostingSelect,
56287
56305
  {
@@ -56338,29 +56356,11 @@ const GeneralSettings = ({
56338
56356
  },
56339
56357
  `model-select-${currentHosting}`
56340
56358
  ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(FieldContainer, { children: [
56341
- /* @__PURE__ */ jsxRuntimeExports.jsxs(FieldLabel$1, { variant: "subtitle2", children: [
56359
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(FieldLabel$1, { children: [
56342
56360
  /* @__PURE__ */ jsxRuntimeExports.jsx(LabelIcon$1, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faRobot }) }),
56343
56361
  "Model"
56344
56362
  ] }),
56345
- /* @__PURE__ */ jsxRuntimeExports.jsx(
56346
- TextField,
56347
- {
56348
- placeholder: "Select a hosting provider first...",
56349
- variant: "outlined",
56350
- size: "small",
56351
- disabled: true,
56352
- fullWidth: true,
56353
- InputProps: {
56354
- sx: {
56355
- fontSize: "0.875rem",
56356
- lineHeight: 1.6,
56357
- backgroundColor: (theme2) => theme2.palette.inputField.background,
56358
- borderRadius: 2,
56359
- padding: "16px"
56360
- }
56361
- }
56362
- }
56363
- )
56363
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ModelPlaceholderContainer, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(ModelPlaceholderText, { children: "Select a hosting provider first..." }) })
56364
56364
  ] }) })
56365
56365
  ] })
56366
56366
  ] }),
@@ -57844,15 +57844,15 @@ const DirectoryIndicator = ({
57844
57844
  )
57845
57845
  ] }) });
57846
57846
  };
57847
- const UtilitiesContainer = styled$1(Box)(
57848
- ({ theme: theme2, expanded }) => ({
57849
- padding: theme2.spacing(1, 3),
57850
- backgroundColor: alpha$1(theme2.palette.background.paper, 0.4),
57851
- borderTop: `1px solid ${alpha$1(theme2.palette.divider, 0.1)}`,
57852
- // Apply minHeight only when collapsed to allow expansion
57853
- minHeight: expanded ? "auto" : 52
57854
- })
57855
- );
57847
+ const UtilitiesContainer = styled$1(Box, {
57848
+ shouldForwardProp: (prop) => prop !== "$expanded"
57849
+ })(({ theme: theme2, $expanded }) => ({
57850
+ padding: theme2.spacing(1, 3),
57851
+ backgroundColor: alpha$1(theme2.palette.background.paper, 0.4),
57852
+ borderTop: `1px solid ${alpha$1(theme2.palette.divider, 0.1)}`,
57853
+ // Apply minHeight only when collapsed to allow expansion
57854
+ minHeight: $expanded ? "auto" : 52
57855
+ }));
57856
57856
  const UtilitiesHeader = styled$1(Box)(({ theme: theme2 }) => ({
57857
57857
  display: "flex",
57858
57858
  alignItems: "center",
@@ -57880,7 +57880,7 @@ const ChatUtilities = ({
57880
57880
  setExpanded(!expanded);
57881
57881
  };
57882
57882
  if (!agentId) return null;
57883
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(UtilitiesContainer, { expanded, children: [
57883
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(UtilitiesContainer, { $expanded: expanded, children: [
57884
57884
  /* @__PURE__ */ jsxRuntimeExports.jsxs(UtilitiesHeader, { onClick: toggleExpanded, children: [
57885
57885
  /* @__PURE__ */ jsxRuntimeExports.jsx(
57886
57886
  IconButton,
@@ -76420,7 +76420,7 @@ const languages = [
76420
76420
  name: "Go",
76421
76421
  extensions: ["go"],
76422
76422
  load() {
76423
- return __vitePreload(() => import("./index-BJAGPaLC.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url).then((m2) => m2.go());
76423
+ return __vitePreload(() => import("./index-DG_vMIJB.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url).then((m2) => m2.go());
76424
76424
  }
76425
76425
  }),
76426
76426
  /* @__PURE__ */ LanguageDescription.of({
@@ -76597,7 +76597,7 @@ const languages = [
76597
76597
  alias: ["yml"],
76598
76598
  extensions: ["yaml", "yml"],
76599
76599
  load() {
76600
- return __vitePreload(() => import("./index-DTD3Qh6P.js"), true ? __vite__mapDeps([3,1,2]) : void 0, import.meta.url).then((m2) => m2.yaml());
76600
+ return __vitePreload(() => import("./index-DMTU6W8a.js"), true ? __vite__mapDeps([3,1,2]) : void 0, import.meta.url).then((m2) => m2.yaml());
76601
76601
  }
76602
76602
  }),
76603
76603
  // Legacy modes ported from CodeMirror 5
@@ -136129,10 +136129,10 @@ const AttachmentsPreview = ({
136129
136129
  ) })
136130
136130
  ] }, `${index2}-${attachment}`)) });
136131
136131
  };
136132
- const ButtonContainer$1 = styled$1(Box)(
136133
- ({
136134
- isChatUtilitiesExpanded
136135
- }) => ({
136132
+ const ButtonContainer$1 = styled$1(Box, {
136133
+ shouldForwardProp: (prop) => prop !== "isChatUtilitiesExpanded"
136134
+ })(
136135
+ ({ isChatUtilitiesExpanded }) => ({
136136
136136
  position: "absolute",
136137
136137
  bottom: isChatUtilitiesExpanded ? 260 : 200,
136138
136138
  zIndex: 1e3,
@@ -136454,7 +136454,7 @@ const MessageInput = ({
136454
136454
  const newAttachments = Array.from(e3.target.files).map((file) => {
136455
136455
  const filePath = file.path;
136456
136456
  if (filePath) {
136457
- return filePath;
136457
+ return normalizePath(filePath);
136458
136458
  }
136459
136459
  return URL.createObjectURL(file);
136460
136460
  });
@@ -174958,6 +174958,8 @@ const BackgroundBlock = ({
174958
174958
  return "Editing Content";
174959
174959
  case "READ":
174960
174960
  return "Reading Content";
174961
+ case "DELEGATE":
174962
+ return "Delegating Task";
174961
174963
  default:
174962
174964
  return executionType === "plan" ? "Planning" : executionType === "action" ? "Action" : "Reflection";
174963
174965
  }
@@ -174976,6 +174978,8 @@ const BackgroundBlock = ({
174976
174978
  return faEdit;
174977
174979
  case "READ":
174978
174980
  return faBook;
174981
+ case "DELEGATE":
174982
+ return faShare;
174979
174983
  default:
174980
174984
  return executionType === "plan" ? faLightbulb : executionType === "action" ? faCode : faCommentDots;
174981
174985
  }
@@ -179518,10 +179522,17 @@ const CreateAgentStep = () => {
179518
179522
  severity: "success",
179519
179523
  icon: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faCheck }),
179520
179524
  sx: successAlertSx,
179521
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
179522
- /* @__PURE__ */ jsxRuntimeExports.jsx(EmojiContainer, { sx: { mb: 0 }, children: "🎉" }),
179523
- " AI assistant created successfully!"
179524
- ] })
179525
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
179526
+ Box,
179527
+ {
179528
+ component: "span",
179529
+ sx: { display: "flex", alignItems: "center", gap: 1 },
179530
+ children: [
179531
+ /* @__PURE__ */ jsxRuntimeExports.jsx(EmojiContainer, { sx: { mb: 0 }, children: "🎉" }),
179532
+ " AI assistant created successfully!"
179533
+ ]
179534
+ }
179535
+ )
179525
179536
  }
179526
179537
  ),
179527
179538
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -180426,39 +180437,23 @@ const SignInButton = styled$1(Button)(({ theme: theme2 }) => ({
180426
180437
  display: "flex",
180427
180438
  alignItems: "center",
180428
180439
  justifyContent: "center",
180429
- // Center content
180430
180440
  padding: theme2.spacing(0.75, 2),
180431
- // Consistent padding
180432
180441
  borderRadius: theme2.shape.borderRadius * 0.75,
180433
- // Consistent radius
180434
180442
  fontSize: "0.875rem",
180435
- // Standard font size
180436
180443
  fontWeight: 500,
180437
- // Standard weight
180438
180444
  textTransform: "none",
180439
180445
  marginBottom: theme2.spacing(1.5),
180440
- // Reduced margin between buttons
180441
180446
  width: "100%",
180442
180447
  maxWidth: 320,
180443
- // Keep max width for centering effect
180444
180448
  border: `1px solid ${theme2.palette.divider}`,
180445
- // Standard border
180446
180449
  backgroundColor: theme2.palette.background.paper,
180447
- // Standard background
180448
180450
  color: theme2.palette.text.primary,
180449
- // Standard text color
180450
180451
  boxShadow: "none",
180451
- // Remove shadow
180452
180452
  transition: "background-color 0.2s ease-in-out, border-color 0.2s ease-in-out",
180453
- // Standard transition
180454
180453
  "&:hover": {
180455
180454
  backgroundColor: theme2.palette.action.hover,
180456
- // Standard hover
180457
180455
  borderColor: theme2.palette.divider,
180458
- // Keep border consistent on hover
180459
180456
  boxShadow: "none"
180460
- // Ensure no shadow on hover
180461
- // transform: "none", // Ensure no transform
180462
180457
  },
180463
180458
  "&:disabled": {
180464
180459
  borderColor: theme2.palette.divider,
@@ -180473,11 +180468,8 @@ const IconContainer = styled$1(Box)(({ theme: theme2 }) => ({
180473
180468
  alignItems: "center",
180474
180469
  justifyContent: "center",
180475
180470
  marginRight: theme2.spacing(1),
180476
- // Reduced margin
180477
180471
  fontSize: "1rem",
180478
- // Slightly smaller icon to fit button style
180479
180472
  width: 20,
180480
- // Explicit width/height for alignment
180481
180473
  height: 20
180482
180474
  }));
180483
180475
  const ButtonsContainer = styled$1(Box)(() => ({
@@ -180488,12 +180480,14 @@ const ButtonsContainer = styled$1(Box)(() => ({
180488
180480
  }));
180489
180481
  const RadientAuthButtons = ({
180490
180482
  onSignInSuccess,
180483
+ onAfterCredentialUpdate,
180491
180484
  titleText: titleText2 = "Sign in to Radient",
180492
180485
  descriptionText = "Choose your preferred sign-in method to access Radient services."
180493
180486
  }) => {
180494
180487
  const theme2 = useTheme$1();
180495
180488
  const { signInWithGoogle, signInWithMicrosoft, loading, error } = useOidcAuth(
180496
180489
  {
180490
+ onAfterCredentialUpdate,
180497
180491
  onSuccess: onSignInSuccess
180498
180492
  }
180499
180493
  );
@@ -180510,13 +180504,10 @@ const RadientAuthButtons = ({
180510
180504
  {
180511
180505
  sx: {
180512
180506
  fontSize: "1.125rem",
180513
- // ~18px
180514
180507
  fontWeight: 500,
180515
180508
  marginBottom: theme2.spacing(1),
180516
- // Reduced margin
180517
180509
  color: theme2.palette.text.primary,
180518
180510
  textAlign: "center"
180519
- // Center title
180520
180511
  },
180521
180512
  children: titleText2
180522
180513
  }
@@ -180526,13 +180517,10 @@ const RadientAuthButtons = ({
180526
180517
  {
180527
180518
  sx: {
180528
180519
  fontSize: "0.875rem",
180529
- // ~14px
180530
180520
  color: theme2.palette.text.secondary,
180531
180521
  marginBottom: theme2.spacing(3),
180532
- // Consistent margin
180533
180522
  lineHeight: 1.5,
180534
180523
  textAlign: "center"
180535
- // Center description
180536
180524
  },
180537
180525
  children: descriptionText
180538
180526
  }
@@ -180563,13 +180551,61 @@ const RadientAuthButtons = ({
180563
180551
  ] })
180564
180552
  ] });
180565
180553
  };
180554
+ const radientPricesKeys = {
180555
+ all: ["radient-prices"],
180556
+ prices: () => [...radientPricesKeys.all, "prices"]
180557
+ };
180558
+ const useRadientPricesQuery = () => {
180559
+ const radientClient2 = createRadientClient(
180560
+ apiConfig.radientBaseUrl,
180561
+ apiConfig.radientClientId
180562
+ // Not used by fetchPrices, but required by constructor
180563
+ );
180564
+ const pricesQuery = useQuery({
180565
+ // Use the defined query key
180566
+ queryKey: radientPricesKeys.prices(),
180567
+ // The query function calls the fetchPrices method from the client
180568
+ queryFn: async () => {
180569
+ try {
180570
+ const prices = await radientClient2.prices.fetchPrices();
180571
+ return prices;
180572
+ } catch (error) {
180573
+ console.error("Failed to fetch Radient prices:", error);
180574
+ throw error;
180575
+ }
180576
+ },
180577
+ // This data is fairly static, so we can set a longer stale time
180578
+ staleTime: 1e3 * 60 * 60,
180579
+ // 1 hour
180580
+ // Refetch only on mount or if stale, not on window focus or interval
180581
+ refetchOnWindowFocus: false,
180582
+ refetchOnMount: true,
180583
+ refetchInterval: false,
180584
+ // Retry on failure a few times
180585
+ retry: 3
180586
+ });
180587
+ return {
180588
+ // Prices data (default_new_credits, default_registration_credits)
180589
+ prices: pricesQuery.data,
180590
+ // Loading and error states from react-query
180591
+ isLoading: pricesQuery.isLoading,
180592
+ isFetching: pricesQuery.isFetching,
180593
+ error: pricesQuery.error,
180594
+ // Raw query object for advanced usage if needed
180595
+ pricesQuery
180596
+ };
180597
+ };
180566
180598
  const RadientSignInStep = ({
180567
180599
  onSignInSuccess
180568
- // This prop comes from OnboardingModal
180569
180600
  }) => {
180570
180601
  const theme2 = useTheme$1();
180602
+ const { prices, isLoading, error } = useRadientPricesQuery();
180603
+ const formatCurrency = (amount) => {
180604
+ if (typeof amount !== "number") return "$...";
180605
+ return `$${amount.toFixed(2)} USD`;
180606
+ };
180571
180607
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionContainer, { children: [
180572
- /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDescription$1, { sx: { mb: 3 }, children: "Sign in with your preferred method to get started with Radient Pass. This gives you access to web search, image generation, site crawling, and more." }),
180608
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SectionDescription$1, { sx: { mb: 3 }, children: "Sign in with your preferred method to get started with Radient Pass in a couple clicks. This gives you access to hundreds of models updated in real time, cost-saving with Radient Auto, web search, image generation, site crawling, and more all in Local Operator." }),
180573
180609
  /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionDescription$1, { sx: { mb: 3 }, children: [
180574
180610
  "Start with",
180575
180611
  " ",
@@ -180580,7 +180616,7 @@ const RadientSignInStep = ({
180580
180616
  fontWeight: "medium",
180581
180617
  color: theme2.palette.primary.main,
180582
180618
  sx: { fontSize: "inherit" },
180583
- children: "$1 USD"
180619
+ children: isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, { size: 16, sx: { mr: 0.5 } }) : formatCurrency(prices?.default_new_credits)
180584
180620
  }
180585
180621
  ),
180586
180622
  " ",
@@ -180593,11 +180629,12 @@ const RadientSignInStep = ({
180593
180629
  fontWeight: "medium",
180594
180630
  color: theme2.palette.primary.main,
180595
180631
  sx: { fontSize: "inherit" },
180596
- children: "$5 USD"
180632
+ children: isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, { size: 16, sx: { mr: 0.5 } }) : formatCurrency(prices?.default_registration_credits)
180597
180633
  }
180598
180634
  ),
180599
180635
  " ",
180600
- "more with your first payment."
180636
+ "more with your first payment.",
180637
+ error && /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { color: "error", variant: "caption", display: "block", mt: 1, children: "Could not load credit information." })
180601
180638
  ] }),
180602
180639
  /* @__PURE__ */ jsxRuntimeExports.jsx(
180603
180640
  Box,
@@ -181056,7 +181093,7 @@ const UserProfileStep = () => {
181056
181093
  };
181057
181094
  const stepTitles = {
181058
181095
  [OnboardingStep.RADIENT_CHOICE]: "Choose Your Setup Option",
181059
- [OnboardingStep.RADIENT_SIGNIN]: "Sign in with a Radient Pass",
181096
+ [OnboardingStep.RADIENT_SIGNIN]: "Set Up With Radient Pass",
181060
181097
  [OnboardingStep.USER_PROFILE]: "Set Up Your Profile",
181061
181098
  [OnboardingStep.MODEL_CREDENTIAL]: "Add Model Provider Credentials",
181062
181099
  [OnboardingStep.SEARCH_API]: "Enable Web Search (Recommended)",
@@ -205321,8 +205358,11 @@ const LoadingContainer$2 = styled$1(Box)({
205321
205358
  alignItems: "center",
205322
205359
  minHeight: 150
205323
205360
  });
205324
- const RadientAccountSection = () => {
205361
+ const RadientAccountSection = ({
205362
+ onAfterCredentialUpdate
205363
+ }) => {
205325
205364
  const { isAuthenticated, user, isLoading, error, signOut } = useRadientAuth();
205365
+ const isSigningOut = useUserStore((state) => state.isSigningOut);
205326
205366
  const handleSignOut = reactExports.useCallback(async () => {
205327
205367
  try {
205328
205368
  await signOut();
@@ -205331,7 +205371,7 @@ const RadientAccountSection = () => {
205331
205371
  }
205332
205372
  }, [signOut]);
205333
205373
  const accountInfoSection = reactExports.useMemo(() => {
205334
- if (!isAuthenticated || !user.radientUser) return null;
205374
+ if (!isAuthenticated || !user?.radientUser) return null;
205335
205375
  const { account, identity: identity3 } = user.radientUser;
205336
205376
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
205337
205377
  /* @__PURE__ */ jsxRuntimeExports.jsxs(InfoContainer, { children: [
@@ -205389,9 +205429,9 @@ const RadientAccountSection = () => {
205389
205429
  )
205390
205430
  ] })
205391
205431
  ] });
205392
- }, [isAuthenticated, user.radientUser, handleSignOut]);
205432
+ }, [isAuthenticated, user?.radientUser, handleSignOut]);
205393
205433
  const signInSection = reactExports.useMemo(() => {
205394
- if (isAuthenticated) return null;
205434
+ if (isAuthenticated && user) return null;
205395
205435
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { mt: 1 }, children: [
205396
205436
  " ",
205397
205437
  /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", color: "text.secondary", mb: 2.5, children: "You are not currently signed in to Radient. Sign in to access your account details or sign up to get free credits and unified access to models, tools, and more with Radient Pass." }),
@@ -205399,22 +205439,30 @@ const RadientAccountSection = () => {
205399
205439
  RadientAuthButtons,
205400
205440
  {
205401
205441
  titleText: "",
205442
+ onAfterCredentialUpdate,
205402
205443
  descriptionText: "",
205403
205444
  onSignInSuccess: () => {
205404
205445
  }
205405
205446
  }
205406
205447
  )
205407
205448
  ] });
205408
- }, [isAuthenticated]);
205449
+ }, [isAuthenticated, user, onAfterCredentialUpdate]);
205409
205450
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { children: [
205410
205451
  " ",
205411
- isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoadingContainer$2, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, {}) }) : error ? /* @__PURE__ */ jsxRuntimeExports.jsxs(Typography, { color: "error", variant: "body2", children: [
205412
- "Error loading account information:",
205413
- " ",
205414
- error instanceof Error ? error.message : String(error)
205415
- ] }) : (
205416
- // Render either the account info or the sign-in prompt
205417
- accountInfoSection || signInSection
205452
+ isLoading || isSigningOut ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoadingContainer$2, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, {}) }) : isAuthenticated && user?.radientUser ? (
205453
+ // If authenticated and user data exists, show account info
205454
+ accountInfoSection
205455
+ ) : (
205456
+ // If not loading and not authenticated (or user data missing), show sign-in section.
205457
+ // Display error above if it exists.
205458
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
205459
+ error && /* @__PURE__ */ jsxRuntimeExports.jsxs(Typography, { color: "error", variant: "body2", sx: { mb: 2 }, children: [
205460
+ "Error checking account status:",
205461
+ " ",
205462
+ error instanceof Error ? error.message : String(error)
205463
+ ] }),
205464
+ signInSection
205465
+ ] })
205418
205466
  )
205419
205467
  ] });
205420
205468
  };
@@ -206729,6 +206777,29 @@ const SettingsPage = () => {
206729
206777
  const [activeSection, setActiveSection] = reactExports.useState("general");
206730
206778
  const [isScrolling, setIsScrolling] = reactExports.useState(false);
206731
206779
  const scrollTimeoutRef = reactExports.useRef(null);
206780
+ const { data: credentialsData, refetch: refetchCredentials } = useCredentials();
206781
+ const { refreshModels } = useModels();
206782
+ const credentialKeys = reactExports.useMemo(
206783
+ () => credentialsData?.keys ? [...credentialsData.keys].sort() : [],
206784
+ [credentialsData?.keys]
206785
+ );
206786
+ const lastRefreshRef = reactExports.useRef({
206787
+ keys: "",
206788
+ hosting: void 0
206789
+ });
206790
+ reactExports.useEffect(() => {
206791
+ const keysString = credentialKeys.join(",");
206792
+ const hosting = config2?.values?.hosting;
206793
+ if (lastRefreshRef.current.keys !== keysString || lastRefreshRef.current.hosting !== hosting) {
206794
+ lastRefreshRef.current = { keys: keysString, hosting };
206795
+ refreshModels().catch((err) => {
206796
+ console.error(
206797
+ "Failed to refresh models after credentials or hosting change:",
206798
+ err
206799
+ );
206800
+ });
206801
+ }
206802
+ }, [credentialKeys, config2?.values?.hosting, refreshModels]);
206732
206803
  const sectionRefs = reactExports.useRef({
206733
206804
  general: reactExports.useRef(null),
206734
206805
  radient: reactExports.useRef(null),
@@ -207006,7 +207077,15 @@ const SettingsPage = () => {
207006
207077
  description: "Manage your Radient account, Radient Pass details, and credits.",
207007
207078
  cardRef: sectionRefs.radient,
207008
207079
  children: [
207009
- /* @__PURE__ */ jsxRuntimeExports.jsx(RadientAccountSection, {}),
207080
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
207081
+ RadientAccountSection,
207082
+ {
207083
+ onAfterCredentialUpdate: () => {
207084
+ refreshModels();
207085
+ refetchCredentials();
207086
+ }
207087
+ }
207088
+ ),
207010
207089
  isAuthenticated && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
207011
207090
  /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, { sx: { my: 3 } }),
207012
207091
  /* @__PURE__ */ jsxRuntimeExports.jsx(BillingInfo, {}),
@@ -207242,8 +207321,8 @@ const UserProfileSidebar = React.memo(
207242
207321
  const [anchorEl, setAnchorEl] = reactExports.useState(null);
207243
207322
  const open2 = Boolean(anchorEl);
207244
207323
  const { user, isAuthenticated, signOut } = useRadientAuth();
207245
- const userName = user.name;
207246
- const userEmail = user.email;
207324
+ const userName = user?.name ?? "User";
207325
+ const userEmail = user?.email ?? "";
207247
207326
  const handleClick = reactExports.useCallback(
207248
207327
  (event) => {
207249
207328
  if (useAuth) {
@@ -207567,6 +207646,109 @@ const App = () => {
207567
207646
  ] }) })
207568
207647
  ] });
207569
207648
  };
207649
+ const queryClient = new QueryClient({
207650
+ defaultOptions: {
207651
+ queries: {
207652
+ // Default stale time of 5 minutes
207653
+ staleTime: 5 * 60 * 1e3,
207654
+ // Default cache time of 10 minutes
207655
+ gcTime: 10 * 60 * 1e3,
207656
+ // Default retry configuration
207657
+ retry: 1,
207658
+ // Default refetch configuration
207659
+ refetchOnWindowFocus: true,
207660
+ refetchOnMount: true,
207661
+ // Don't wait for reconnect to refetch - we handle offline status separately
207662
+ refetchOnReconnect: false,
207663
+ // Continue to run queries even when offline
207664
+ networkMode: "always"
207665
+ },
207666
+ mutations: {
207667
+ // Retry mutations once by default
207668
+ retry: 1,
207669
+ // Continue to run mutations even when offline
207670
+ networkMode: "always"
207671
+ }
207672
+ }
207673
+ });
207674
+ const useRadientTokenRefresher = () => {
207675
+ const { authStatus, hasLocalSession } = useRadientAuth();
207676
+ const queryClient2 = useQueryClient();
207677
+ const refreshTimeout = reactExports.useRef(null);
207678
+ const radientClient2 = reactExports.useMemo(
207679
+ () => createRadientClient(apiConfig.radientBaseUrl, apiConfig.radientClientId),
207680
+ []
207681
+ );
207682
+ const clearRefreshTimeout = reactExports.useCallback(() => {
207683
+ if (refreshTimeout.current) {
207684
+ clearTimeout(refreshTimeout.current);
207685
+ refreshTimeout.current = null;
207686
+ }
207687
+ }, []);
207688
+ const refreshAccessToken = reactExports.useCallback(async () => {
207689
+ const session = await getSession();
207690
+ if (!session || !session.refreshToken) {
207691
+ return;
207692
+ }
207693
+ const currentAccessToken = session.accessToken;
207694
+ try {
207695
+ const response = await radientClient2.refreshToken(session.refreshToken);
207696
+ const newAccessToken = response.result.access_token;
207697
+ const newRefreshToken = response.result.refresh_token || session.refreshToken;
207698
+ await updateAccessToken(
207699
+ newAccessToken,
207700
+ response.result.expires_in,
207701
+ newRefreshToken
207702
+ );
207703
+ if (newAccessToken !== currentAccessToken) {
207704
+ queryClient2.invalidateQueries({ queryKey: radientUserKeys.session() });
207705
+ }
207706
+ } catch (err) {
207707
+ const errorMessage = err instanceof Error ? err.message : String(err);
207708
+ if (errorMessage.toLowerCase().includes("invalid_grant") || errorMessage.toLowerCase().includes("refresh token expired") || errorMessage.toLowerCase().includes("invalid refresh token")) {
207709
+ await clearSession();
207710
+ queryClient2.invalidateQueries({ queryKey: radientUserKeys.all });
207711
+ showErrorToast("Session expired. Please sign in again.");
207712
+ }
207713
+ }
207714
+ }, [queryClient2, radientClient2]);
207715
+ const schedulePeriodicRefresh = reactExports.useCallback(() => {
207716
+ clearRefreshTimeout();
207717
+ refreshTimeout.current = setTimeout(
207718
+ async () => {
207719
+ await refreshAccessToken();
207720
+ schedulePeriodicRefresh();
207721
+ },
207722
+ 5 * 60 * 1e3
207723
+ );
207724
+ }, [refreshAccessToken, clearRefreshTimeout]);
207725
+ reactExports.useEffect(() => {
207726
+ if (authStatus === "authenticated" || hasLocalSession) {
207727
+ refreshAccessToken();
207728
+ schedulePeriodicRefresh();
207729
+ const handleFocus = () => {
207730
+ refreshAccessToken();
207731
+ };
207732
+ window.addEventListener("focus", handleFocus);
207733
+ return () => {
207734
+ clearRefreshTimeout();
207735
+ window.removeEventListener("focus", handleFocus);
207736
+ };
207737
+ }
207738
+ clearRefreshTimeout();
207739
+ return void 0;
207740
+ }, [
207741
+ authStatus,
207742
+ hasLocalSession,
207743
+ refreshAccessToken,
207744
+ schedulePeriodicRefresh,
207745
+ clearRefreshTimeout
207746
+ ]);
207747
+ };
207748
+ const RadientTokenRefresherRunner = () => {
207749
+ useRadientTokenRefresher();
207750
+ return null;
207751
+ };
207570
207752
  const RadientAuthProvider = ({
207571
207753
  children
207572
207754
  }) => {
@@ -207636,7 +207818,10 @@ document.addEventListener("DOMContentLoaded", () => {
207636
207818
  options: posthogOptions,
207637
207819
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntimeExports.jsx(FeatureFlagProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(AuthProviders, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(ThemeProvider, { children: [
207638
207820
  /* @__PURE__ */ jsxRuntimeExports.jsx(CssBaseline, {}),
207639
- /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(HashRouter, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(App, {}) }) }),
207821
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorBoundary, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(HashRouter, { children: [
207822
+ /* @__PURE__ */ jsxRuntimeExports.jsx(App, {}),
207823
+ /* @__PURE__ */ jsxRuntimeExports.jsx(RadientTokenRefresherRunner, {})
207824
+ ] }) }),
207640
207825
  /* @__PURE__ */ jsxRuntimeExports.jsx(ThemedToastContainer, {}),
207641
207826
  isDevelopmentMode()
207642
207827
  ] }) }) }) })