Skip to content

Conversation

@maparent
Copy link
Collaborator

@maparent maparent commented Sep 4, 2025

https://linear.app/discourse-graphs/issue/ENG-593/change-from-dev-to-admin-panel

Summary by CodeRabbit

  • New Features

    • Added a Secret Admin Panel with a schema picker and a table of nodes.
    • Interactive content actions: Shift+click opens blocks in the sidebar; open pages when available.
  • Changes

    • Renamed hidden tab to “Secret Admin Panel.”
    • Temporarily disabled automatic discourse embedding initialization during startup.
    • Schema picker now includes global/shared schemas in addition to workspace-specific ones.
  • Refactor

    • Moved admin tools from inline UI into the dedicated panel.

@linear
Copy link

linear bot commented Sep 4, 2025

@supabase
Copy link

supabase bot commented Sep 4, 2025

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@maparent
Copy link
Collaborator Author

maparent commented Sep 4, 2025

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 4, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 4, 2025

📝 Walkthrough

Walkthrough

Adds a new AdminPanel React component for browsing node schemas and nodes via Supabase; wires it into Settings as a hidden “Secret Admin Panel” opened by Ctrl+Shift+A; comments out the createOrUpdateDiscourseEmbedding call in onload. Also relaxes node schema query to include cache entries with spaceId === 0.

Changes

Cohort / File(s) Summary of changes
Admin Panel Component
apps/roam/src/components/settings/AdminPanel.tsx
Adds AdminPanel (default export) with internal NodeRow/NodeTable. Initializes Supabase context and client, loads node schemas, fetches nodes for selected schema, renders schema Select + nodes table, shows Spinner while loading, and surfaces errors. Implements async calls to getNodeSchemas and getNodes.
Settings Integration
apps/roam/src/components/settings/Settings.tsx
Replaces prior inline secret-dev UI with <AdminPanel />, renames hidden tab to secret-admin-panel, updates title to "Secret Admin Panel", changes global shortcut to Ctrl+Shift+A, and passes onloadArgs into AdminPanel. Removes the previous sendErrorEmail button/import.
Onload Initialization
apps/roam/src/index.ts
Comments out the call to createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI) (marked TODO for removal), so the embedding creation/update is skipped during onload.
Database Query Relaxation
packages/database/src/lib/queries.ts
Changes getNodeSchemas filter to include entries where spaceId === 0 in addition to matching spaceId (i.e., `.filter(x => x.spaceId === spaceId

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Settings as Settings Panel
  participant AdminPanel as AdminPanel Component
  participant SB as Supabase Client
  participant Roam as roamAlphaAPI

  User->>Settings: Ctrl+Shift+A
  Settings->>Settings: setSelectedTabId("secret-admin-panel")
  Settings->>AdminPanel: mount (props.onloadArgs)

  rect rgb(238,246,255)
  note right of AdminPanel: Initialization & data load
  AdminPanel->>SB: getLoggedInClient()
  SB-->>AdminPanel: client/context
  AdminPanel->>SB: getNodeSchemas(spaceId)
  SB-->>AdminPanel: [schemas]
  AdminPanel->>SB: getNodes(schemaLocalIds)
  SB-->>AdminPanel: [nodes]
  AdminPanel->>AdminPanel: setState({schemas, nodes})
  end

  User->>AdminPanel: change schema selection
  AdminPanel->>SB: getNodes(newSchema)
  SB-->>AdminPanel: [nodes]
  AdminPanel->>AdminPanel: setState(nodes)

  alt Shift+click content link
    AdminPanel->>Roam: open block in right sidebar
  else Click with Document present
    AdminPanel->>Roam: open page in main window
  end
Loading
sequenceDiagram
  autonumber
  participant Ext as Roam Extension
  participant Embed as createOrUpdateDiscourseEmbedding
  participant Menu as installDiscourseFloatingMenu

  Ext->>Embed: (call commented out / SKIPPED)
  note right of Ext: TODO: REMOVE AFTER TESTING — embedding step not executed
  Ext->>Menu: installDiscourseFloatingMenu()
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "ENG-593 Change from Dev to Admin Panel" concisely and accurately captures the primary intent of the changeset: replacing the previous dev panel with a new AdminPanel and renaming/repurposing the hidden settings tab, which matches the added AdminPanel component and Settings.tsx updates. It is short, specific to the main change, and includes the ticket reference for traceability. This makes it clear to reviewers scanning history what the primary change is.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (5)
apps/roam/src/components/settings/AdminPanel.tsx (3)

74-75: Use array length directly.

Minor: more idiomatic and avoids needless Object.keys on arrays.

Apply:

-        {Object.keys(this.state.schemas).length > 0 ? (
+        {this.state.schemas.length > 0 ? (

80-83: Avoid spreading current state in setState.

setState merges; spreading risks stale state.

Apply:

-                  this.setState({ ...this.state, showingSchema: choice });
-                  this.getNodes(choice.id).then((nodes) =>
-                    this.setState({ ...this.state, nodes }),
-                  );
+                  this.setState({ showingSchema: choice });
+                  this.getNodes(choice.id).then((nodes) =>
+                    this.setState({ nodes }),
+                  );

77-97: Type the Select for better TS safety.

Optional: use a typed Select to catch renderer/selection mismatches.

Add above the component:

const NodeSignatureSelect = Select.ofType<NodeSignature>();

Then:

-              <Select
+              <NodeSignatureSelect
                 items={this.state.schemas}
                 ...
-              >
+              >
apps/roam/src/components/settings/Settings.tsx (2)

78-82: Support macOS (Meta) and avoid repeat keydown triggers.

Broaden shortcut compatibility and prevent rapid re-triggering.

Apply:

-      if (e.ctrlKey && e.shiftKey && e.key === "A") {
+      if ((e.ctrlKey || e.metaKey) && e.shiftKey && (e.key === "A" || e.key === "a") && !e.repeat) {
         e.stopPropagation();
         e.preventDefault();
         setSelectedTabId("secret-admin-panel");
       }

19-19: Lazy-load AdminPanel to keep initial bundle lean.

The panel is hidden; defer loading until needed.

Example:

// replace static import
// import AdminPanel from "./AdminPanel";
const AdminPanel = React.lazy(() => import("./AdminPanel"));

Then wrap the Tab panel:

<React.Suspense fallback={<div className="p-4">Loading…</div>}>
  <AdminPanel onloadArgs={onloadArgs} />
</React.Suspense>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 62db485 and 6f48723.

📒 Files selected for processing (3)
  • apps/roam/src/components/settings/AdminPanel.tsx (1 hunks)
  • apps/roam/src/components/settings/Settings.tsx (3 hunks)
  • apps/roam/src/index.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-19T22:34:23.619Z
Learnt from: CR
PR: DiscourseGraphs/discourse-graph#0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-07-19T22:34:23.619Z
Learning: Applies to apps/roam/**/*.{js,jsx,ts,tsx} : Use Roam Depot/Extension API documentation from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when working with the Roam Extension API

Applied to files:

  • apps/roam/src/index.ts
📚 Learning: 2025-06-23T11:49:45.457Z
Learnt from: maparent
PR: DiscourseGraphs/discourse-graph#220
File: apps/roam/src/utils/conceptConversion.ts:11-40
Timestamp: 2025-06-23T11:49:45.457Z
Learning: In the DiscourseGraphs/discourse-graph codebase, direct access to `window.roamAlphaAPI` is the established pattern throughout the codebase. The team prefers to maintain this pattern consistently rather than making piecemeal changes, and plans to address dependency injection as a global refactor when scheduled.

Applied to files:

  • apps/roam/src/index.ts
🔇 Additional comments (1)
apps/roam/src/components/settings/Settings.tsx (1)

206-210: Approve changes; secret admin panel wiring verified and no stale references found.

Comment on lines 71 to 79
<p>
Context: <code>{JSON.stringify(this.state.context)}</code>
</p>
{Object.keys(this.state.schemas).length > 0 ? (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid leaking secrets: don’t render full Supabase context.

Context may include tokens/URLs. Show only non-sensitive fields.

Apply:

-        <p>
-          Context: <code>{JSON.stringify(this.state.context)}</code>
-        </p>
+        <p>
+          Context:{" "}
+          <code>
+            {JSON.stringify(
+              this.state.context ? { spaceId: this.state.context.spaceId } : null,
+            )}
+          </code>
+        </p>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<p>
Context: <code>{JSON.stringify(this.state.context)}</code>
</p>
{Object.keys(this.state.schemas).length > 0 ? (
<p>
Context:{" "}
<code>
{JSON.stringify(
this.state.context
? { spaceId: this.state.context.spaceId }
: null,
)}
</code>
</p>
{Object.keys(this.state.schemas).length > 0 ? (
🤖 Prompt for AI Agents
In apps/roam/src/components/settings/AdminPanel.tsx around lines 71-74, the code
renders the entire this.state.context via JSON.stringify which can leak Supabase
tokens/URLs; instead, only display a whitelist of non-sensitive fields (or
explicitly filter out sensitive keys like "apiKey", "token", "access_token",
"refresh_token", "service_role", "url", "endpoint") and/or mask values (e.g.,
show first/last few chars with ****) before rendering; implement a small helper
to pick or sanitize allowed keys from this.state.context and render that
sanitized object (or a simple list of key: maskedValue) rather than
JSON.stringify(this.state.context).

Comment on lines 142 to 146
// TODO: REMOVE AFTER TESTING
// await createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI);
await createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Don’t block extension load with embeddings sync; guard and handle errors.

Running this on every load (and awaiting it) can slow startup and fail in offline/encrypted graphs. Make it dev-only, non-blocking, and resilient.

Apply:

-  // TODO: REMOVE AFTER TESTING
-  await createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI);
+  // Dev-only; run non-blocking and don't break load on failure
+  if (process.env.NODE_ENV === "development") {
+    void createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI).catch((e) =>
+      console.error("createOrUpdateDiscourseEmbedding failed", e),
+    );
+  }

Run to confirm there are no other startup-time callers and that the function has timeouts/retries:


🏁 Script executed:

#!/bin/bash
rg -n --type=ts 'createOrUpdateDiscourseEmbedding' -C3

Length of output: 2506


Guard extension load from embedding sync in development only
Only startup caller found; wrap in a non-blocking, dev-only call and catch errors:

-  // TODO: REMOVE AFTER TESTING
-  await createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI);
+  // Dev-only; run non-blocking and don’t break load on failure
+  if (process.env.NODE_ENV === "development") {
+    void createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI)
+      .catch((e) => console.error("createOrUpdateDiscourseEmbedding failed", e));
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// TODO: REMOVE AFTER TESTING
// await createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI);
await createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI);
// Dev-only; run non-blocking and don’t break load on failure
if (process.env.NODE_ENV === "development") {
void createOrUpdateDiscourseEmbedding(onloadArgs.extensionAPI)
.catch((e) => console.error("createOrUpdateDiscourseEmbedding failed", e));
}
🤖 Prompt for AI Agents
In apps/roam/src/index.ts around lines 142 to 144, the call to
createOrUpdateDiscourseEmbedding is run unguarded and blocking; change it to run
only in development, non-blocking (do not await), and wrap it in a try/catch to
swallow/log errors so extension load is not blocked. Specifically: check
process.env.NODE_ENV === 'development' (or a suitable dev flag) before invoking,
call the function without awaiting (fire-and-forget) and handle promise
rejection by attaching a .catch that logs the error to the extension logger or
console.

@maparent
Copy link
Collaborator Author

maparent commented Sep 4, 2025

Note: To test, you have to uncomment createOrUpdateDiscourseEmbedding in roam/src/index.ts:143 , and run with access to either local or production database.

@maparent maparent requested a review from mdroidian September 4, 2025 23:07
Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a loom video walking through the UI/UX changes then re-tag me? Thank you.

@maparent maparent force-pushed the eng-593-change-from-dev-to-admin-panel branch 2 times, most recently from 805e271 to bfb894d Compare September 9, 2025 15:01
@maparent maparent changed the base branch from main to eng-833-isolate-node-query-functions September 9, 2025 15:01
@maparent maparent force-pushed the eng-593-change-from-dev-to-admin-panel branch 2 times, most recently from 5d3dad3 to cb836b0 Compare September 11, 2025 00:43
@maparent maparent force-pushed the eng-833-isolate-node-query-functions branch 2 times, most recently from d865ad4 to 05df276 Compare September 12, 2025 13:46
@maparent maparent force-pushed the eng-593-change-from-dev-to-admin-panel branch from cb836b0 to 1394ffd Compare September 12, 2025 13:48
Base automatically changed from eng-833-isolate-node-query-functions to main September 13, 2025 00:31
@maparent maparent force-pushed the eng-593-change-from-dev-to-admin-panel branch from 1394ffd to a8343e6 Compare September 13, 2025 00:33
@maparent maparent requested a review from mdroidian September 13, 2025 00:42
Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High-level feedback

  • In modern React (since 16.8), functional components with Hooks are the norm for UI. Class components are legacy and generally avoided for new code. (ref) Hooks make data-flow and effects explicit, reduce boilerplate (this, setState merges, lifecycle juggling), and play nicely with newer React features and tooling.

  • Using Hooks here will make the component shorter, easier to test, and less bug-prone (no accidental partial state merges, no stale this.state copies, no componentDidMount branching).

Here's an example of what this code might look like as a functional component with hooks:
https://gist.github.com/mdroidian/88dc865156bef4359a860e9f962203b1

Let's go ahead and update this to functional component with hooks.

Additional notes

  • Consider loading/error states; right now failures only console.error
  • Consider extracting <NodesTable /> into its own component to keep AdminPanel focused on orchestration.
  • There are multiple unused imports, make sure to remove them before submitting the PR
  • There are multiple lint warnings, let's try to remove them all. If you have any issues, let me know, or if any specific warnings cannot be removed for some reason, add a comment inline or in GitHub UI.

@maparent maparent force-pushed the eng-593-change-from-dev-to-admin-panel branch from a8343e6 to 983f856 Compare September 22, 2025 10:03
@maparent maparent requested a review from mdroidian September 22, 2025 14:26
@mdroidian
Copy link
Contributor

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 22, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/database/src/lib/queries.ts (1)

99-102: Inconsistent cache filter drops global (spaceId=0) schemas on cache hits.

You only include spaceId === 0 after a cache reload, not when serving from cache. This yields inconsistent results depending on cache state.

Fix: include spaceId === 0 in the initial cache-hit filter as well.

   let result = Object.values(NODE_SCHEMA_CACHE)
     .filter((x) => typeof x === "object")
-    .filter((x) => x.spaceId === spaceId);
+    .filter((x) => x.spaceId === spaceId || x.spaceId === 0);
🧹 Nitpick comments (6)
apps/roam/src/components/settings/AdminPanel.tsx (6)

106-124: Initialize supabase/context in parallel and always clear loading in finally.

Prevents premature spinner hide and ensures it clears on error.

 useEffect(() => {
   let ignore = false;
   void (async () => {
     try {
-      if (!ignore) {
-        setContext(await getSupabaseContext());
-      }
-      if (!ignore) {
-        setSupabase(await getLoggedInClient());
-      }
+      const [ctx, cli] = await Promise.all([getSupabaseContext(), getLoggedInClient()]);
+      if (!ignore) {
+        setContext(ctx);
+        setSupabase(cli);
+      }
     } catch (e) {
       setError((e as Error).message);
       console.error("AdminPanel init failed", e);
+    } finally {
+      if (!ignore) setLoading(false);
     }
   })();
   return () => {
     ignore = true;
   };
 }, []);

155-164: Ensure node spinner clears on both success and error.

setLoadingNodes(false) should be in a finally, otherwise it can spin forever on errors.

         try {
           setLoadingNodes(true);
           setNodes(
             await getNodes({
               supabase,
               spaceId,
               schemaLocalIds: showingSchema.sourceLocalId,
             }),
           );
-          setLoadingNodes(false);
         } catch (e) {
           setError((e as Error).message);
           console.error("getNodes failed", e);
+        } finally {
+          setLoadingNodes(false);
         }

194-219: Use array length to check emptiness.

Object.keys(schemas).length on arrays is brittle; use schemas.length.

-      {Object.keys(schemas).length > 0 ? (
+      {schemas.length > 0 ? (

17-17: Remove unused import.

OnLoadArgs isn’t used.

-import { OnLoadArgs } from "esbuild";

21-22: Redundant key on inside NodeRow.

The list key lives on <NodeRow ... key={node.id} />; the inner <tr key> is unnecessary.

-    <tr key={node.id}>
+    <tr>

37-65: Simplify click handler and add basic keyboard accessibility.

Avoid nested async IIFE; add role/tabIndex and Enter/Space activation.

-          <span
-            className="rm-page-ref rm-page-ref--link"
-            onClick={(event) => {
-              void (async (event) => {
-                if (event.shiftKey) {
-                  if (node.Content?.source_local_id) {
-                    await window.roamAlphaAPI.ui.rightSidebar.addWindow({
-                      window: {
-                        // @ts-expect-error TODO: fix this
-                        "block-uid": node.Content.source_local_id,
-                        type: "outline",
-                      },
-                    });
-                  }
-                } else if (node.Content?.Document?.source_local_id) {
-                  await window.roamAlphaAPI.ui.mainWindow.openPage({
-                    page: {
-                      uid: node.Content.Document.source_local_id,
-                    },
-                  });
-                }
-              })(event);
-            }}
-          >
+          <span
+            className="rm-page-ref rm-page-ref--link"
+            role="link"
+            tabIndex={0}
+            onKeyDown={async (e) => {
+              if (e.key === "Enter" || e.key === " ") {
+                e.preventDefault();
+                e.currentTarget.click();
+              }
+            }}
+            onClick={async (event) => {
+              if (event.shiftKey && node.Content?.source_local_id) {
+                await window.roamAlphaAPI.ui.rightSidebar.addWindow({
+                  window: {
+                    // @ts-expect-error TODO: fix this
+                    "block-uid": node.Content.source_local_id,
+                    type: "outline",
+                  },
+                });
+              } else if (node.Content?.Document?.source_local_id) {
+                await window.roamAlphaAPI.ui.mainWindow.openPage({
+                  page: { uid: node.Content.Document.source_local_id },
+                });
+              }
+            }}
+          >
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f48723 and ed52999.

📒 Files selected for processing (4)
  • apps/roam/src/components/settings/AdminPanel.tsx (1 hunks)
  • apps/roam/src/components/settings/Settings.tsx (3 hunks)
  • apps/roam/src/index.ts (1 hunks)
  • packages/database/src/lib/queries.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/roam/src/index.ts
  • apps/roam/src/components/settings/Settings.tsx
🔇 Additional comments (5)
packages/database/src/lib/queries.ts (1)

123-126: LGTM: reload path correctly includes global schemas.

Including x.spaceId === 0 here aligns with the intended behavior. Ensure the cache‑hit path (Lines 99–102) matches this.

apps/roam/src/components/settings/AdminPanel.tsx (4)

33-35: LGTM: correct JSX binding for data- attributes.*

Attributes now bind expressions rather than literal strings.


126-136: Good: errors are caught and surfaced to UI.

Both schema and node fetch effects log errors and set error state. With the loading fixes above, UX will be consistent.

Also applies to: 144-173


73-93: Potential performance concerns with large datasets (non-blocking).

Rendering full JSON blobs in tables and unpaginated lists can be heavy. Consider pagination/limit in queries, or table virtualization/infinite scroll.

Also applies to: 175-181, 215-216


191-193: Don’t render the full Supabase context (secrets risk).

Only masking spacePassword still exposes tokens/URLs. Render a whitelist (e.g., just spaceId) or remove entirely.

-      <p>
-        Context:{" "}
-        <code>{JSON.stringify({ ...context, spacePassword: "****" })}</code>
-      </p>
+      <p>
+        Context: <code>{JSON.stringify(context ? { spaceId: context.spaceId } : null)}</code>
+      </p>

Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good start on the panel! Could use some UI cleaning for readability, but that can be addressed later.

A few comments, mostly nits. But also take a look at the coderabbit comment and nits.

type PConcept,
} from "@repo/database/lib/queries";
import { DGSupabaseClient } from "@repo/database/lib/client";
import { OnLoadArgs } from "esbuild";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused, remove

/>
)}
>
<Button text={`display: ${showingSchema.name}`} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider wrapping this in a Label so that display isn't part of the button

<Label>
  <Select ...
</Label>

It can replace one of the two <div>'s that wrap the <Select>. (the other div can be replaced with <>)

@maparent maparent merged commit 71ddfeb into main Sep 23, 2025
4 checks passed
@github-project-automation github-project-automation bot moved this to Done in General Sep 23, 2025
@maparent maparent deleted the eng-593-change-from-dev-to-admin-panel branch September 23, 2025 14:19
sid597 pushed a commit that referenced this pull request Sep 25, 2025
Dev panel has become admin panel (ctrl-shift-A).
It shows the supabase Context object, and a table of all nodes of a certain types, starting with schema nodes.
trangdoan982 pushed a commit that referenced this pull request Oct 3, 2025
Dev panel has become admin panel (ctrl-shift-A).
It shows the supabase Context object, and a table of all nodes of a certain types, starting with schema nodes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants