Skip to content

Commit 17502d6

Browse files
committed
backup
1 parent 0c75248 commit 17502d6

31 files changed

+27982
-91
lines changed

package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/app/src/actions/data/folders/createFolder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { revalidateTag } from "next/cache";
88
export async function createFolderAction(
99
projectId: string,
1010
parentFolderId: string | null = null,
11-
type: "query" | "plot" = "query",
11+
type: "query" | "plot" | "stat" = "query",
1212
name?: string,
1313
) {
1414
const user = await getServerUser();
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"use server";
2+
3+
import { updateStat, readStatForProject } from "@/db/crud/stat";
4+
import { StatDefinition, validateStatQueries, defaultQueryReference } from "@common/db/schema/stat";
5+
import { getServerUser } from "@/lib/auth";
6+
import { getProjectForUser } from "@/lib/dal/projects";
7+
import { revalidateStatCache } from "@/lib/dal/stats";
8+
import { notFound } from "next/navigation";
9+
10+
export async function addQueryToStatAction(
11+
statId: string,
12+
projectId: string,
13+
queryId: string,
14+
columnName: string,
15+
isComputedColumn: boolean = false,
16+
label?: string,
17+
unit?: string,
18+
) {
19+
const user = await getServerUser();
20+
21+
if (!user) {
22+
throw new Error("Unauthorized");
23+
}
24+
25+
const project = await getProjectForUser(user, projectId);
26+
27+
if (!project) {
28+
notFound();
29+
}
30+
31+
const stat = await readStatForProject(projectId, statId);
32+
33+
if (!stat) {
34+
throw new Error("Stat not found");
35+
}
36+
37+
const currentDefinition = stat.definition || { queries: [] };
38+
39+
// Check if we already have 4 queries
40+
if (currentDefinition.queries.length >= 4) {
41+
throw new Error("Maximum of 4 queries allowed");
42+
}
43+
44+
// Check if this query+column combination already exists
45+
const existingQuery = currentDefinition.queries.find(
46+
q => q.queryId === queryId && q.columnName === columnName
47+
);
48+
49+
if (existingQuery) {
50+
throw new Error("This query and column combination already exists");
51+
}
52+
53+
const newQuery = {
54+
...defaultQueryReference,
55+
queryId,
56+
columnName,
57+
isComputedColumn,
58+
label: label || null,
59+
unit: unit || null,
60+
};
61+
62+
const updatedDefinition: StatDefinition = {
63+
queries: [...currentDefinition.queries, newQuery],
64+
};
65+
66+
// Validate the updated definition
67+
if (!validateStatQueries(updatedDefinition)) {
68+
throw new Error("Invalid query configuration");
69+
}
70+
71+
await updateStat(statId, {
72+
definition: updatedDefinition,
73+
});
74+
75+
revalidateStatCache(statId, projectId);
76+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"use server";
2+
3+
import { getServerUser } from "@/lib/auth";
4+
import { revalidateTag } from "next/cache";
5+
import { redirect } from "next/navigation";
6+
import { getProjectForUser } from "@/lib/dal/projects";
7+
8+
import { createStat, generateUniqueStatName } from "@/db/crud/stat";
9+
import { defaultStatDefinition } from "@common/db/schema/stat";
10+
11+
export async function createStatAction(
12+
projectId: string,
13+
folderId?: string | null,
14+
) {
15+
const user = await getServerUser();
16+
const userProject = await getProjectForUser(user, projectId);
17+
18+
if (!userProject) {
19+
throw new Error("Project not found");
20+
}
21+
22+
const name = await generateUniqueStatName(projectId);
23+
const newStat = await createStat({
24+
name,
25+
projectId,
26+
folderId: folderId || null,
27+
definition: defaultStatDefinition,
28+
});
29+
30+
revalidateTag(`project-${projectId}-stats`);
31+
revalidateTag(`project-${projectId}-data`);
32+
33+
redirect(`/projects/${projectId}/data/stats/${newStat.id}`);
34+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"use server";
2+
3+
import { getServerUser } from "@/lib/auth";
4+
import { getProjectForUser } from "@/lib/dal/projects";
5+
import { readStatForProject, deleteStat } from "@/db/crud/stat";
6+
import { revalidateTag } from "next/cache";
7+
8+
export async function deleteStatAction(projectId: string, statId: string) {
9+
const user = await getServerUser();
10+
const userProject = await getProjectForUser(user, projectId);
11+
12+
if (!userProject) {
13+
throw new Error("Project not found");
14+
}
15+
16+
const stat = await readStatForProject(projectId, statId);
17+
18+
if (!stat) {
19+
throw new Error("Stat not found");
20+
}
21+
22+
await deleteStat(statId);
23+
24+
revalidateTag(`project-${projectId}-stats`);
25+
revalidateTag(`project-${projectId}-data`);
26+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"use server";
2+
3+
import { getServerUser } from "@/lib/auth";
4+
import { getProjectForUser } from "@/lib/dal/projects";
5+
import { getQueryForProject } from "@/lib/dal/queries";
6+
import { readDataForQuery } from "@/db/crud/data/query";
7+
import { readQueryZones } from "@/db/crud/zone";
8+
9+
export async function getQueryDataForStatsAction(
10+
projectId: string,
11+
queryId: string,
12+
columnName: string,
13+
) {
14+
const user = await getServerUser();
15+
16+
if (!user) {
17+
throw new Error("Unauthorized");
18+
}
19+
20+
const project = await getProjectForUser(user, projectId);
21+
22+
if (!project) {
23+
throw new Error("Project not found");
24+
}
25+
26+
const query = await getQueryForProject(projectId, queryId);
27+
28+
if (!query || !query.definition) {
29+
throw new Error("Query not found or not configured");
30+
}
31+
32+
// Get zones for the query
33+
const zones = await readQueryZones(queryId);
34+
35+
// Fetch data for the query
36+
const data = await readDataForQuery(
37+
projectId,
38+
query.definition,
39+
undefined, // No pagination - get all data
40+
undefined, // No filters
41+
zones.map((zone) => zone.zoneId),
42+
);
43+
44+
// Extract values for the specified column
45+
const columnValues = data
46+
.map((row) => row[columnName])
47+
.filter((value) => value !== null && value !== undefined);
48+
49+
// Convert to numbers and filter out non-numeric values
50+
const numericValues = columnValues
51+
.map((value) => {
52+
const num = typeof value === 'number' ? value : parseFloat(String(value));
53+
return isNaN(num) ? null : num;
54+
})
55+
.filter((value) => value !== null) as number[];
56+
57+
// Calculate statistics
58+
const stats = calculateStatistics(numericValues);
59+
60+
return {
61+
values: numericValues,
62+
rawData: data, // Add raw data for histogram visualization
63+
stats,
64+
totalRows: data.length,
65+
validNumericRows: numericValues.length,
66+
};
67+
}
68+
69+
function calculateStatistics(values: number[]) {
70+
if (values.length === 0) {
71+
return {
72+
mean: null,
73+
median: null,
74+
stdDev: null,
75+
min: null,
76+
max: null,
77+
range: null,
78+
count: 0,
79+
};
80+
}
81+
82+
const sorted = [...values].sort((a, b) => a - b);
83+
const sum = values.reduce((acc, val) => acc + val, 0);
84+
const mean = sum / values.length;
85+
86+
// Calculate median
87+
const mid = Math.floor(sorted.length / 2);
88+
const median = sorted.length % 2 === 0
89+
? (sorted[mid - 1] + sorted[mid]) / 2
90+
: sorted[mid];
91+
92+
// Calculate standard deviation
93+
const variance = values.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / values.length;
94+
const stdDev = Math.sqrt(variance);
95+
96+
const min = sorted[0];
97+
const max = sorted[sorted.length - 1];
98+
const range = max - min;
99+
100+
return {
101+
mean: Math.round(mean * 100) / 100,
102+
median: Math.round(median * 100) / 100,
103+
stdDev: Math.round(stdDev * 100) / 100,
104+
min,
105+
max,
106+
range: Math.round(range * 100) / 100,
107+
count: values.length,
108+
};
109+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
"use server";
2+
3+
import { getServerUser } from "@/lib/auth";
4+
import { readStatForProject, updateStat } from "@/db/crud/stat";
5+
import { getProjectForUser } from "@/lib/dal/projects";
6+
import { revalidateTag } from "next/cache";
7+
8+
export async function moveStatAction(
9+
projectId: string,
10+
statId: string,
11+
newFolderId: string | null,
12+
) {
13+
const user = await getServerUser();
14+
const userProject = await getProjectForUser(user, projectId);
15+
16+
if (!userProject) {
17+
throw new Error("Project not found");
18+
}
19+
20+
const stat = await readStatForProject(projectId, statId);
21+
22+
if (!stat) {
23+
throw new Error("Stat not found");
24+
}
25+
26+
const updatedStat = await updateStat(statId, {
27+
folderId: newFolderId,
28+
});
29+
30+
revalidateTag(`project-${projectId}-stats`);
31+
revalidateTag(`project-${projectId}-data`);
32+
33+
return updatedStat;
34+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"use server";
2+
3+
import { updateStat, readStatForProject } from "@/db/crud/stat";
4+
import { StatDefinition, validateStatQueries } from "@common/db/schema/stat";
5+
import { getServerUser } from "@/lib/auth";
6+
import { getProjectForUser } from "@/lib/dal/projects";
7+
import { revalidateStatCache } from "@/lib/dal/stats";
8+
import { notFound } from "next/navigation";
9+
10+
export async function removeQueryFromStatAction(
11+
statId: string,
12+
projectId: string,
13+
queryId: string,
14+
columnName: string,
15+
) {
16+
const user = await getServerUser();
17+
18+
if (!user) {
19+
throw new Error("Unauthorized");
20+
}
21+
22+
const project = await getProjectForUser(user, projectId);
23+
24+
if (!project) {
25+
notFound();
26+
}
27+
28+
const stat = await readStatForProject(projectId, statId);
29+
30+
if (!stat) {
31+
throw new Error("Stat not found");
32+
}
33+
34+
const currentDefinition = stat.definition || { queries: [] };
35+
36+
// Remove the specified query
37+
const updatedQueries = currentDefinition.queries.filter(
38+
q => !(q.queryId === queryId && q.columnName === columnName)
39+
);
40+
41+
const updatedDefinition: StatDefinition = {
42+
queries: updatedQueries,
43+
};
44+
45+
// Validate the updated definition
46+
if (!validateStatQueries(updatedDefinition)) {
47+
throw new Error("Invalid query configuration");
48+
}
49+
50+
await updateStat(statId, {
51+
definition: updatedDefinition,
52+
});
53+
54+
revalidateStatCache(statId, projectId);
55+
}

0 commit comments

Comments
 (0)