Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ For production
npm run preview
```

#### Configuration
The application will defaults to the connection setup on first access.


To preset connection details use the following ENV variables:
```
VITE_CLICKHOUSE_URL
VITE_CLICKHOUSE_USER
VITE_CLICKHOUSE_PASS
```

For self-serving setups such as quackpipe
```
VITE_SELFSERVICE
```

## 📄 License

[ch-ui](https://github.com/caioricciuti/ch-ui) fork licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
16 changes: 13 additions & 3 deletions src/components/common/AppInit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ declare global {
VITE_CLICKHOUSE_PASS?: string;
VITE_CLICKHOUSE_USE_ADVANCED?: boolean;
VITE_CLICKHOUSE_CUSTOM_PATH?: string;
VITE_SELFSERVICE?: string;
};
}
}
Expand Down Expand Up @@ -46,10 +47,19 @@ const AppInitializer = ({ children }: { children: ReactNode }) => {
const envUrl = ( import.meta.env?.VITE_CLICKHOUSE_URL || window.env?.VITE_CLICKHOUSE_URL );
const envUser = ( import.meta.env?.VITE_CLICKHOUSE_USER || window.env?.VITE_CLICKHOUSE_USER );
const envPass = ( import.meta.env?.VITE_CLICKHOUSE_PASS || window.env?.VITE_CLICKHOUSE_PASS );
const envUseAdvanced = window.env?.VITE_CLICKHOUSE_USE_ADVANCED;
const envCustomPath = window.env?.VITE_CLICKHOUSE_CUSTOM_PATH;
const envUseAdvanced = ( import.meta.env?.VITE_CLICKHOUSE_USE_ADVANCED || window.env?.VITE_CLICKHOUSE_USE_ADVANCED );
const envCustomPath = ( import.meta.env?.VITE_CLICKHOUSE_CUSTOM_PATH || window.env?.VITE_CLICKHOUSE_CUSTOM_PATH );

if (envUrl && envUser) {
if (import.meta.env?.VITE_SELFSERVICE || window.env?.VITE_SELFSERVICE) {
setCredential({
url: window.location.origin,
username: 'default',
password: '',
useAdvanced: false,
customPath: "",
});
setCredentialSource("env");
} else if (envUrl) {
setCredential({
url: envUrl,
username: envUser,
Expand Down
14 changes: 0 additions & 14 deletions src/features/explorer/components/CreateDatabase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,20 +163,6 @@ const CreateDatabase = () => {
}
sqlStatement += `${databaseName} `;

if (onCluster && clusterName) {
sqlStatement += `ON CLUSTER ${clusterName} `;
}

if (engine === "Lazy") {
sqlStatement += `ENGINE = Lazy(${expirationTimeInSeconds}) `;
} else if (engine) {
sqlStatement += `ENGINE = ${engine} `;
}

if (comment) {
sqlStatement += `COMMENT '${comment}'`;
}

setSql(sqlStatement.trim());
setErrors({});
return sqlStatement.trim();
Expand Down
4 changes: 2 additions & 2 deletions src/features/explorer/components/CreateTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ const CreateTable = () => {
return `${field.name} ${typeStr} ${nullableStr}${commentStr}`;
}).join(",\n ");

let sql = `CREATE TABLE ${database}.${tableName}\n(\n ${fieldDefinitions}\n) ENGINE = ${engine}`;
let sql = `CREATE TABLE ${database}.${tableName}\n(\n ${fieldDefinitions}\n)`;

if (primaryKeyFields.length > 0) {
sql += `\nPRIMARY KEY (${primaryKeyFields.join(", ")})`;
Expand Down Expand Up @@ -350,4 +350,4 @@ const CreateTable = () => {
);
};

export default CreateTable;
export default CreateTable;
151 changes: 100 additions & 51 deletions src/features/metrics/config/metricsConfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//ignore TS check
// @ts-nocheck

import { ChartConfig } from "@/components/ui/chart";
import {
HomeIcon,
Expand All @@ -13,6 +10,7 @@ import {
CpuIcon,
AlertTriangleIcon,
} from "lucide-react";
import { ReactNode, ComponentType } from "react";

export interface Metrics {
title: string;
Expand All @@ -28,29 +26,51 @@ export interface MetricItem {
type: "card" | "table" | "chart";
chartType?: "bar" | "line" | "area" | "pie" | "radar" | "radial";
description: string;
chartConfig?: ChartConfig;
chartConfig?: CustomChartConfig;
tiles?: number;
}

export type ChartTheme = {
light: string;
dark: string;
}

export type ChartDataConfig = {
label?: ReactNode;
icon?: ComponentType<{}>;
} & ({ color?: string; theme?: never } | { color?: never; theme: ChartTheme });

export type CustomChartConfig = {
indexBy: string;
[key: string]: ChartDataConfig | string | undefined;
}

export const metrics: Metrics[] = [
{
title: "Overview",
scope: "overview",
description: "Overview of ClickHouse metrics.",
description: "Overview of DuckDB metrics.",
icon: HomeIcon,
items: [
{
title: "Server Uptime (days)",
query: `SELECT 1`,
query: `
SELECT
ROUND(SUM(julianday('now') - julianday(start_time)), 2) AS uptime_days
FROM pragma_database_list
WHERE name = 'main'
`,
type: "card",
description:
"Total time the server has been running in seconds, minutes, hours, and days.",
"Total time the server has been running in days.",
tiles: 1,
},
{
title: "Total Databases",
query: `
SELECT count(database) as total_databases FROM (SHOW ALL TABLES)
SELECT COUNT(*) AS total_databases
FROM pragma_database_list
WHERE name NOT IN ('main', 'temp')
`,
type: "card",
description: "Total number of databases excluding system databases.",
Expand All @@ -59,7 +79,9 @@ export const metrics: Metrics[] = [
{
title: "Total Tables",
query: `
SELECT count(name) as total_tables FROM (SHOW ALL TABLES);
SELECT COUNT(*) AS total_tables
FROM information_schema.tables
WHERE table_schema NOT IN ('main', 'temp')
`,
type: "card",
description: "Total number of user tables excluding temporary tables.",
Expand All @@ -70,7 +92,7 @@ export const metrics: Metrics[] = [
query: `SELECT version() AS version`,
type: "card",
description:
"Version of the ClickHouse server running on the current instance.",
"Version of the DuckDB server running on the current instance.",
tiles: 1,
},
],
Expand All @@ -83,65 +105,92 @@ export const metrics: Metrics[] = [
items: [
{
title: "Total Tables",
query: `SELECT count(name) as total_tables FROM (SHOW ALL TABLES);`,
query: `
SELECT COUNT(*) AS total_tables
FROM information_schema.tables
WHERE table_schema NOT IN ('main', 'temp')
`,
type: "card",
description: "Total number of user-defined tables.",
tiles: 1,
},
{
title: "Total System Tables",
query: `SELECT count(name) as total_tables FROM (SHOW ALL TABLES);`,
query: `
SELECT COUNT(*) AS total_tables
FROM information_schema.tables
WHERE table_schema IN ('main', 'temp')
`,
type: "card",
description: "Total number of system tables.",
tiles: 1,
},
],
},
{
title: "Queries",
scope: "queries",
description: "Comprehensive metrics related to queries in the system.",
icon: TerminalSquareIcon,
items: [
{
title: "Queries Per Second (QPS)",
query: `SELECT 0`,
type: "chart",
chartType: "area",
description: "Rate of queries per second over the last hour.",
chartConfig: {
indexBy: "minute",
qps: {
label: "QPS",
color: "hsl(var(--chart-3))",
},
},
title: "Total Temporary Tables",
query: `
SELECT COUNT(*) AS total_tables
FROM information_schema.tables
WHERE table_schema LIKE 'temp%'
`,
type: "card",
description: "Total number of temporary tables.",
tiles: 1,
},
{
title: "Biggest Table",
query: `
SELECT table_name AS table
FROM information_schema.tables
WHERE table_schema NOT IN ('main', 'temp')
ORDER BY table_name DESC
LIMIT 1
`,
type: "card",
description: "Largest table in the system.",
tiles: 1,
},
{
title: "Table Cardinality",
query: `
SELECT table_schema, table_name AS table, COUNT(*) AS total_rows
FROM information_schema.tables
WHERE table_schema NOT IN ('main', 'temp')
GROUP BY table_schema, table_name
ORDER BY total_rows DESC
LIMIT 10
`,
type: "table",
description: "Number of rows in the top 10 tables.",
tiles: 2,
},
{
title: "Table Row Counts",
query: `
SELECT table_schema, table_name AS table, COUNT(*) AS total_rows
FROM information_schema.tables
WHERE table_schema NOT IN ('main', 'temp')
GROUP BY table_schema, table_name
ORDER BY total_rows DESC
LIMIT 10
`,
type: "table",
description: "Number of rows in the top 10 tables.",
tiles: 2,
},
],
},
{
title: "Performance",
scope: "performance",
description: "Performance-related metrics.",
icon: CpuIcon,
title: "Settings & Config",
scope: "settings",
description: "Settings and configuration.",
icon: Settings2,
items: [
{
title: "CPU Usage",
query: `
SELECT 0
`,
type: "chart",
chartType: "line",
description: "CPU usage over the last hour.",
chartConfig: {
indexBy: "minute",
cpu_usage: {
label: "CPU Usage",
color: "hsl(var(--chart-5))",
},
},
tiles: 2,
title: "Current Settings",
query: `SELECT * FROM pragma_settings`,
type: "table",
description: "Current DuckDB settings.",
tiles: 4,
},
],
},
Expand Down
24 changes: 12 additions & 12 deletions src/features/workspace/components/HomeTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,27 +93,26 @@ const HomeTab = () => {
setLoading(true);
setError(null);
try {
const recentQueries = await runQuery(`
SELECT DISTINCT
replaceAll(query, 'FORMAT JSON', '') AS cleaned_query,
max(event_time) AS latest_event_time,
const recentQueries = await runQuery(`
SELECT DISTINCT
REPLACE(query, 'FORMAT JSON', '') AS cleaned_query,
MAX(event_time) AS latest_event_time,
query_kind,
length(replaceAll(query, 'FORMAT JSON', '')) AS query_length
LENGTH(REPLACE(query, 'FORMAT JSON', '')) AS query_length
FROM
system.query_log
pragma_sql_log
WHERE
user = '${credential.username}'
AND event_time >= (current_timestamp() - INTERVAL 2 DAY)
AND arrayExists(db -> db NOT LIKE '%system%', databases)
AND event_time >= (CURRENT_TIMESTAMP - INTERVAL '2' DAY)
AND query NOT LIKE 'SELECT DISTINCT%'
GROUP BY
cleaned_query, query_kind
ORDER BY
latest_event_time DESC
LIMIT
6;
`);
setRecentItems(recentQueries.data);
LIMIT
6;
`);
setRecentItems(recentQueries.data);
} catch (err) {
setError("Failed to load recent queries");
console.error(err);
Expand All @@ -122,6 +121,7 @@ const HomeTab = () => {
}
};


const truncateQuery = (query: string, length: number = 50) => {
return query.length > length ? `${query.slice(0, length)}...` : query;
};
Expand Down
Loading