diff --git a/.eslintrc.json b/.eslintrc.json
index b5e13c1..02a9f43 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -16,6 +16,8 @@
"unicorn/prefer-spread": 0,
"unicorn/no-array-reduce": 0,
"unicorn/prevent-abbreviations": 0,
+ "unicorn/prefer-global-this": 0,
+ "unicorn/prefer-logical-operator-over-ternary": 0,
// TODO: Check these rules later
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-unused-vars": [
diff --git a/.github/assets/home.gif b/.github/assets/home.gif
new file mode 100644
index 0000000..73f6a66
Binary files /dev/null and b/.github/assets/home.gif differ
diff --git a/.github/assets/keyspace-details.gif b/.github/assets/keyspace-details.gif
new file mode 100644
index 0000000..0802a0c
Binary files /dev/null and b/.github/assets/keyspace-details.gif differ
diff --git a/.github/assets/query-runner-details.gif b/.github/assets/query-runner-details.gif
new file mode 100644
index 0000000..a4f7ca5
Binary files /dev/null and b/.github/assets/query-runner-details.gif differ
diff --git a/.github/assets/query-ruuner-dashboard.gif b/.github/assets/query-ruuner-dashboard.gif
new file mode 100644
index 0000000..3533714
Binary files /dev/null and b/.github/assets/query-ruuner-dashboard.gif differ
diff --git a/.github/assets/table-details.gif b/.github/assets/table-details.gif
new file mode 100644
index 0000000..4ee736b
Binary files /dev/null and b/.github/assets/table-details.gif differ
diff --git a/README.md b/README.md
index e36f297..9ca5c4d 100644
--- a/README.md
+++ b/README.md
@@ -16,8 +16,13 @@
- **Visual Management of Keyspaces and Tables:**
Create, edit, and visualize keyspaces and tables directly from the interface.
+
+
+
- **Integrated Metrics Monitoring:**
Leverages ScyllaDB's Prometheus and Grafana integrations to display important metrics within the app.
+
+
- **Cluster Connectivity:**
Easily connect to your local cluster using `https://local.scylladb.studio` or manage cloud-based clusters.
diff --git a/src/app/(main)/keyspace/[keyspace]/_components/keyspace-info.tsx b/src/app/(main)/keyspace/[keyspace]/_components/keyspace-info.tsx
index 294de03..0292dd8 100644
--- a/src/app/(main)/keyspace/[keyspace]/_components/keyspace-info.tsx
+++ b/src/app/(main)/keyspace/[keyspace]/_components/keyspace-info.tsx
@@ -58,29 +58,25 @@ export default function KeyspaceInfo({ keyspace }: KeyspaceInfoProperties) {
"",
)}
/>
-
-
-
-
-
-
- Replication Sizes
-
-
- {replicationSizes.map(([key, value]) => (
-
-
- {key}: {value}
-
-
- ))}
-
-
-
+ }
+ label="Replication Sizes"
+ >
+
+ {replicationSizes.map(([key, value]) => (
+
+
+ {key}: {value}
+
+
+ ))}
+
+
+
}
label="Durable Writes"
@@ -99,9 +95,9 @@ export default function KeyspaceInfo({ keyspace }: KeyspaceInfoProperties) {
);
}
-function KeyspaceInfoItem({ icon, label, value }: any) {
+function KeyspaceInfoItem({ icon, label, value, children }: any) {
return (
-
+
{icon}
@@ -109,9 +105,14 @@ function KeyspaceInfoItem({ icon, label, value }: any) {
{label}
-
- {value}
-
+
+ {children ? (
+ children
+ ) : (
+
+ {value}
+
+ )}
);
@@ -119,7 +120,9 @@ function KeyspaceInfoItem({ icon, label, value }: any) {
function KeyspaceCQLTooltip({
keyspaceInfo,
-}: { keyspaceInfo: KeyspaceDefinition }) {
+}: {
+ keyspaceInfo: KeyspaceDefinition;
+}) {
const cql = `CREATE KEYSPACE ${keyspaceInfo.name}
WITH replication = {
'class': '${keyspaceInfo?.replication?.class}',
@@ -154,12 +157,17 @@ function DeleteKeyspaceButton() {
-
+
Delete Keyspace
-
+
+ Work In Progress
+
);
diff --git a/src/app/(main)/keyspace/[keyspace]/_components/keyspace-tables.tsx b/src/app/(main)/keyspace/[keyspace]/_components/keyspace-tables.tsx
index 4cab4b8..22c41d8 100644
--- a/src/app/(main)/keyspace/[keyspace]/_components/keyspace-tables.tsx
+++ b/src/app/(main)/keyspace/[keyspace]/_components/keyspace-tables.tsx
@@ -1,3 +1,4 @@
+import { CustomTooltip } from "@scylla-studio/components/composed/custom-tooltip";
import { Badge } from "@scylla-studio/components/ui/badge";
import { Button } from "@scylla-studio/components/ui/button";
import {
@@ -14,12 +15,7 @@ import {
TableHeader,
TableRow,
} from "@scylla-studio/components/ui/table";
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@scylla-studio/components/ui/tooltip";
+
import { KeyspaceDefinition } from "@scylla-studio/lib/cql-parser/keyspace-parser";
import {
ArrowDownIcon,
@@ -54,42 +50,41 @@ export default function KeyspaceDefinitions({
-
+
-
+
Table Name
-
- Keys
-
-
- Actions
-
+ Keys
+ Actions
{tables.map(({ name, table }) => (
-
-
-
+
+
+
+
+ {table.tableName}
+
+
+ }
>
-
-
- {table.tableName}
-
-
+ View details
+
-
+
-
+
-
-
-
-
-
-
-
-
- View Data
-
-
-
-
-
-
-
-
-
-
-
- Generate MV
-
-
-
-
-
-
-
-
-
-
-
- Drop Table
-
-
-
+
+
+
+ }
+ >
+ View Data
+
+
+
+
+
+ }
+ >
+ Generate MV
+ (Work In Progress)
+
+
+
+
+
+ }
+ >
+ Drop Table
+ (Work In Progress)
+
diff --git a/src/app/(main)/keyspace/[keyspace]/table/[table]/_components/table-structure.tsx b/src/app/(main)/keyspace/[keyspace]/table/[table]/_components/table-structure.tsx
index d3d8ae7..fdbe76e 100644
--- a/src/app/(main)/keyspace/[keyspace]/table/[table]/_components/table-structure.tsx
+++ b/src/app/(main)/keyspace/[keyspace]/table/[table]/_components/table-structure.tsx
@@ -94,7 +94,7 @@ export default function TableStructure({ table }: TableStructureProperties) {
-
+
@@ -118,7 +118,9 @@ export default function TableStructure({ table }: TableStructureProperties) {
}
label="Default TTL"
- value={`${table.options.defaultTimeToLive} seconds ${table.options.defaultTimeToLive === 0 ? "(disabled)" : ""}`}
+ value={`${table.options.defaultTimeToLive} seconds ${
+ table.options.defaultTimeToLive === 0 ? "(disabled)" : ""
+ }`}
/>
}
@@ -148,7 +150,7 @@ function SettingItem({ icon, label, value }: any) {
-
+
{icon}
diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx
index 4427430..bad373d 100644
--- a/src/app/(main)/page.tsx
+++ b/src/app/(main)/page.tsx
@@ -1,11 +1,13 @@
"use client";
+import { CustomTooltip } from "@scylla-studio/components/composed/custom-tooltip";
import { ContentLayout } from "@scylla-studio/components/composed/sidebar/content-layout";
import { Badge } from "@scylla-studio/components/ui/badge";
import {
Card,
CardContent,
CardHeader,
+ CardTitle,
} from "@scylla-studio/components/ui/card";
import {
Tooltip,
@@ -48,9 +50,9 @@ type MergedContributor = PackageContributor & GithubContributor;
export default function DashboardPage() {
return (
-
+
+
-
@@ -61,26 +63,25 @@ export default function DashboardPage() {
function DashboardHeader() {
return (
-
+
+
+
+ ScyllaDB Studio
+
+
+ A front-end application designed for the ScyllaDB ecosystem, inspired
+ by tools like Drizzle and Prisma Studio. It provides an intuitive
+ interface for managing your ScyllaDB keyspaces and tables, integrating
+ essential performance metrics, and offering a unified solution to
+ interact with both local and cloud-based ScyllaDB clusters.
+
+
-
-
- ScyllaDB Studio
-
- a front-end application designed for the ScyllaDB ecosystem,
- inspired by tools like Drizzle and Prisma Studio. It provides an
- intuitive interface for managing your ScyllaDB keyspaces and tables,
- integrating essential performance metrics, and offering a unified
- solution to interact with both local and cloud-based ScyllaDB
- clusters.
-
-
-
);
}
@@ -91,23 +92,39 @@ function DashboardKeyFeatures() {
{ name: "Explore your data with a powerful query editor", status: "wip" },
{ name: "Visualize your data model", status: "done" },
{ name: "Support for both local and cloud-based clusters", status: "done" },
- { name: "Keyspace Autocomplete based on Active Connection", status: "wip" },
+ {
+ name: "Keyspace Autocomplete based on Active Connection",
+ status: "done",
+ },
{ name: "Query History", status: "wip" },
];
return (
-
+
Key Features:
-
+
{features.map((feature, index) => (
-
- {feature.status === "done" ? (
-
- ) : (
-
- )}
- {feature.name}
-
+
+ {feature.name}
+
+
+ {feature.status === "done" ? (
+
+ ) : (
+
+ )}
+ >
+ }
+ >
+ {feature.status}
+
+
+
))}
@@ -195,33 +212,34 @@ const DashboardContributors = () => {
}, []);
return (
-
+
Contributors:
-
+
{contributors.map((contributor, index) => (
-
-
-
- {contributor.openToWork && (
-
- Open to Work
-
- )}
-
-
-
-
{contributor.name}
+
+
+
+
+
+ {contributor.openToWork && (
+
+ Open to Work
+
+ )}
{contributor.core && (
Core Member
)}
+
+
{contributor.name}
+
@@ -272,14 +290,14 @@ const DashboardContributors = () => {
-
+
-
+
{contributor.linkedin && (
Run current query
- Ctrl + Enter
+
+ {isMacEnviroment ? "⌘" : "Ctrl"} + Enter
+
-
+
+
+ }
>
-
-
+ Results
+
-
+
+
+ }
>
-
-
+ Tracing
+
-
+
+
+ }
>
-
-
+ Dashboard
+
)}
diff --git a/src/app/(main)/query-runner/_components/results-render.tsx b/src/app/(main)/query-runner/_components/results-render.tsx
index 472e4e0..0f4e1eb 100644
--- a/src/app/(main)/query-runner/_components/results-render.tsx
+++ b/src/app/(main)/query-runner/_components/results-render.tsx
@@ -96,10 +96,12 @@ const ResultsRenderComponent = ({
-
+
{headers.map((header) => (
- {header}
+
+ {header}
+
))}
@@ -108,7 +110,7 @@ const ResultsRenderComponent = ({
// biome-ignore lint/suspicious/noArrayIndexKey: it needs to be
{headers.map((header) => (
-
+
{row[header] === undefined ? "N/A" : String(row[header])}
))}
diff --git a/src/app/(main)/query-runner/_components/tracing-dashboard-render.tsx b/src/app/(main)/query-runner/_components/tracing-dashboard-render.tsx
index 3f85925..5232bfe 100644
--- a/src/app/(main)/query-runner/_components/tracing-dashboard-render.tsx
+++ b/src/app/(main)/query-runner/_components/tracing-dashboard-render.tsx
@@ -23,6 +23,18 @@ import {
YAxis,
} from "recharts";
+// Define colors for charts
+const colors = [
+ "#8884d8",
+ "#82ca9d",
+ "#ffc658",
+ "#d0ed57",
+ "#a4de6c",
+ "#8dd1e1",
+ "#83a6ed",
+ "#8e4585",
+];
+
export default function QueryDashboard({
tracingInfo,
}: {
@@ -183,18 +195,6 @@ export default function QueryDashboard({
setTotalSourceElapsed(maxSourceElapsed);
}, [data]);
- // Define colors for charts
- const colors = [
- "#8884d8",
- "#82ca9d",
- "#ffc658",
- "#d0ed57",
- "#a4de6c",
- "#8dd1e1",
- "#83a6ed",
- "#8e4585",
- ];
-
return (
Query Dashboard
diff --git a/src/app/(main)/query-runner/_components/tracing-render.tsx b/src/app/(main)/query-runner/_components/tracing-render.tsx
index 073101d..5ada383 100644
--- a/src/app/(main)/query-runner/_components/tracing-render.tsx
+++ b/src/app/(main)/query-runner/_components/tracing-render.tsx
@@ -23,7 +23,9 @@ export const TracingRender = ({ data }: { data: TracingResult }) => {
{headers.map((header) => (
- {header}
+
+ {header}
+
))}
@@ -33,7 +35,7 @@ export const TracingRender = ({ data }: { data: TracingResult }) => {
{headers.map((header) => (
-
+
{row[header as keyof typeof row] === undefined
? "N/A"
: String(row[header as keyof typeof row])}
diff --git a/src/components/composed/custom-tooltip.tsx b/src/components/composed/custom-tooltip.tsx
new file mode 100644
index 0000000..cec0873
--- /dev/null
+++ b/src/components/composed/custom-tooltip.tsx
@@ -0,0 +1,29 @@
+import type { PropsWithChildren, ReactNode } from "react";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "../ui/tooltip";
+
+interface CustomTooltipProps {
+ Trigger: ReactNode;
+ side?: "right" | "top" | "bottom" | "left";
+ triggerAsChild?: boolean;
+}
+
+export function CustomTooltip({
+ Trigger,
+ children,
+ side,
+ triggerAsChild,
+}: PropsWithChildren) {
+ return (
+
+
+ {Trigger}
+ {children}
+
+
+ );
+}
diff --git a/src/components/composed/sidebar/menu.tsx b/src/components/composed/sidebar/menu.tsx
index 8289686..06fce5f 100644
--- a/src/components/composed/sidebar/menu.tsx
+++ b/src/components/composed/sidebar/menu.tsx
@@ -15,6 +15,7 @@ import {
} from "@scylla-studio/components/ui/tooltip";
import { useGetMenuList } from "@scylla-studio/lib/menu-list";
import { cn } from "@scylla-studio/lib/utils";
+import { getIsMacEnviroment } from "@scylla-studio/utils";
interface MenuProperties {
isOpen: boolean | undefined;
@@ -34,6 +35,8 @@ const triggerCtrlK = () => {
document.dispatchEvent(keyEvent);
};
+const isMacEnvironment = getIsMacEnviroment(navigator.platform.toUpperCase());
+
export function Menu({ isOpen }: MenuProperties) {
const pathname = usePathname();
const menuList = useGetMenuList(pathname);
@@ -138,7 +141,9 @@ export function Menu({ isOpen }: MenuProperties) {
Press{" "}
- ⌘ K
+
+ {isMacEnvironment ? "⌘" : "Ctrl"} + K
+
to open the Command Pallete
diff --git a/src/utils/index.tsx b/src/utils/index.tsx
new file mode 100644
index 0000000..2a92035
--- /dev/null
+++ b/src/utils/index.tsx
@@ -0,0 +1,3 @@
+export const getIsMacEnviroment = (OS: string) => {
+ return OS.includes("MAC") ? true : false;
+};