zebflow 0.7.9

Reactive web automation platform — pipelines, templates, and real-time collaboration in a single binary.
Documentation
import ProjectStudioShell from "@/pages/project-studio/components/shell";
import { initProjectDbConnectionsBehavior } from "@/pages/project-studio/connections/connections-behavior";
import { StudioTable, StudioTd, StudioThead, StudioTh } from "@/components/ui/studio-data-table";
import { StudioTabNav, StudioTabLink } from "@/components/ui/studio-tab-nav";

export const page = {
  head: {
    links: [
      { rel: "stylesheet", href: "/assets/platform/db-connections.css" },
      { rel: "stylesheet", href: "/assets/libraries/zeb/icons/0.1/runtime/devicons.css" },
    ],
  },
  html: {
    lang: "en",
  },
  body: {
    className: "font-sans",
  },
  navigation: "history",
};

export function getPage(input) {
  return {
    head: {
      title: input?.seo?.title ?? "Database Connections",
      description:
        input?.seo?.description ??
        "Manage project database connections and open DB suite.",
    },
  };
}

export default function Page(input) {
  initProjectDbConnectionsBehavior();
  const connections = Array.isArray(input?.connections) ? input.connections : [];
  const dbConnectionsRuntime = {
    owner: input?.owner ?? "",
    project: input?.project ?? "",
    api: {
      list: input?.db_connections?.api?.list ?? "",
      item_base: input?.db_connections?.api?.item_base ?? "",
      test: input?.db_connections?.api?.test ?? "",
      credentials_list: input?.db_connections?.api?.credentials_list ?? "",
    },
  };
  return (
    <ProjectStudioShell
      projectHref={input.project_href}
      projectLabel={input.title}
      currentMenu="Databases / Connections"
      owner={input.owner}
      project={input.project}
      nav={input.nav}
    >
      <div className="flex-1 min-h-0 flex flex-col overflow-hidden">
        <StudioTabNav>
          <StudioTabLink href={input.nav?.links?.db_connections ?? "#"} active>Connections</StudioTabLink>
        </StudioTabNav>
        <section className="flex-1 min-h-0 overflow-auto flex flex-col bg-bg">
          <div className="project-content-wrap">
            <section className="project-content-section">
              <div className="project-content-head">
                <div>
                  <p className="project-content-title">Database Connections</p>
                  <p className="project-content-copy">Manage project database connections and open DB suite.</p>
                </div>
                <button type="button" className="project-inline-chip project-inline-chip-accent" data-db-connection-create="true">+ New Database Connection</button>
              </div>
            </section>
            <section className="project-content-section" data-project-db-connections="true">
              <script id="project-db-connections-runtime" type="application/json">
                {JSON.stringify(dbConnectionsRuntime)}
              </script>
              <div className="project-content-body">
                <StudioTable>
                  <StudioThead>
                    <tr>
                      <StudioTh>Connection</StudioTh>
                      <StudioTh>Label</StudioTh>
                      <StudioTh>Kind</StudioTh>
                      <StudioTh>Credential</StudioTh>
                      <StudioTh>Updated</StudioTh>
                      <StudioTh>Action</StudioTh>
                    </tr>
                  </StudioThead>
                  <tbody data-db-connection-rows="true">
                    {connections.map((item, index) => (
                      <tr key={`${item?.slug ?? "conn"}-${index}`}>
                        <StudioTd>
                          <span className="db-connection-name">
                            <i className={`zf-devicon ${item.icon_class || ""}`} aria-hidden="true"></i>
                            <span>{item.slug}</span>
                          </span>
                        </StudioTd>
                        <StudioTd>{item.name}</StudioTd>
                        <StudioTd>
                          <span className="db-connection-kind">
                            <i className={`zf-devicon ${item.icon_class || ""}`} aria-hidden="true"></i>
                            <span>{item.kind}</span>
                          </span>
                        </StudioTd>
                        <StudioTd>{item.credential_id || "-"}</StudioTd>
                        <StudioTd>{item.updated_at || "-"}</StudioTd>
                        <StudioTd>
                          <a href={item.path} className="project-inline-chip">Open</a>
                        </StudioTd>
                      </tr>
                    ))}
                  </tbody>
                </StudioTable>
              </div>

              <dialog className="pipeline-editor-dialog" data-db-connection-dialog="true">
                <form method="dialog" className="pipeline-editor-dialog-form" data-db-connection-form="true">
                  <h3 className="pipeline-editor-dialog-title" data-db-connection-title="true">Database Connection</h3>
                  <p className="pipeline-editor-subtitle" data-db-connection-status="true">Ready.</p>

                  <label className="pipeline-editor-field">
                    <span>Connection Slug</span>
                    <input name="connection_slug" type="text" placeholder="analytics-pg" required data-db-connection-slug="true" />
                  </label>

                  <label className="pipeline-editor-field">
                    <span>Connection Label</span>
                    <input name="connection_label" type="text" placeholder="Analytics Postgres" required />
                  </label>

                  <label className="pipeline-editor-field">
                    <span>Database Kind</span>
                    <select name="database_kind" data-db-connection-kind="true" required>
                      <option value="sekejap">sekejap</option>
                      <option value="postgresql">postgresql</option>
                      <option value="mysql">mysql</option>
                      <option value="sqlite">sqlite</option>
                      <option value="mongodb">mongodb</option>
                      <option value="redis">redis</option>
                      <option value="qdrant">qdrant</option>
                      <option value="pinecone">pinecone</option>
                      <option value="chromadb">chromadb</option>
                      <option value="elasticsearch">elasticsearch</option>
                    </select>
                  </label>

                  <div className="pipeline-editor-field">
                    <span>Credential</span>
                    <select name="credential_id" data-db-connection-credential-id="true">
                      <option value="">None</option>
                    </select>
                    <small className="pipeline-editor-field-help" data-db-connection-credential-help="true">
                      Select an existing credential for this database kind.
                    </small>
                  </div>

                  <div className="pipeline-editor-dialog-actions">
                    <button type="button" data-db-credential-create-inline="true">Create Credential</button>
                    <button type="button" data-db-credential-refresh-inline="true">Refresh Credentials</button>
                  </div>

                  <label className="pipeline-editor-field">
                    <span>Config JSON</span>
                    <textarea name="config_json" rows="6" placeholder="JSON config" data-db-connection-config-json="true"></textarea>
                  </label>

                  <div className="pipeline-editor-dialog-actions">
                    <button type="button" data-db-connection-test="true">Test</button>
                    <button type="button" data-db-connection-delete="true">Delete</button>
                    <button type="button" data-db-connection-cancel="true">Cancel</button>
                    <button type="submit" data-db-connection-save="true">Save</button>
                  </div>
                </form>
              </dialog>

              <dialog className="pipeline-editor-dialog" data-db-credential-dialog="true">
                <form method="dialog" className="pipeline-editor-dialog-form" data-db-credential-form="true">
                  <h3 className="pipeline-editor-dialog-title">Create Credential</h3>
                  <p className="pipeline-editor-subtitle" data-db-credential-status="true">Create a credential and bind it to this connection.</p>

                  <label className="pipeline-editor-field">
                    <span>Credential ID</span>
                    <input name="credential_id" type="text" readOnly data-db-credential-id="true" />
                  </label>

                  <label className="pipeline-editor-field">
                    <span>Title</span>
                    <input name="title" type="text" placeholder="Primary Postgres" required data-db-credential-title="true" />
                  </label>

                  <label className="pipeline-editor-field">
                    <span>Kind</span>
                    <select name="kind" required data-db-credential-kind="true">
                      <option value="postgres">postgres</option>
                      <option value="mysql">mysql</option>
                      <option value="custom">custom</option>
                    </select>
                  </label>

                  <label className="pipeline-editor-field">
                    <span>Secret JSON</span>
                    <textarea name="secret_json" rows="8" data-db-credential-secret-json="true">{"{}"}</textarea>
                  </label>

                  <div className="pipeline-editor-dialog-actions">
                    <button type="button" data-db-credential-cancel="true">Cancel</button>
                    <button type="submit" data-db-credential-save="true">Create</button>
                  </div>
                </form>
              </dialog>
            </section>
          </div>
        </section>
      </div>
    </ProjectStudioShell>
  );
}