From 215f70f87dcb64f9183a33f8d06f007270ba9811 Mon Sep 17 00:00:00 2001
From: psiddharthdesign <107192927+psiddharthdesign@users.noreply.github.com>
Date: Tue, 30 Jul 2024 19:29:53 +0530
Subject: [PATCH] fix / optimizing tfvars logic
---
.../(specific-project-pages)/TFVarTable.tsx | 23 ++---
.../TFVarsDetails.tsx | 20 ++---
.../(specific-project-pages)/tfvars/page.tsx | 57 ++-----------
src/data/admin/encryption.ts | 14 +---
src/data/user/tfvars.ts | 84 +++++++++++++++++++
5 files changed, 106 insertions(+), 92 deletions(-)
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarTable.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarTable.tsx
index 6676b567..2ec899f0 100644
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarTable.tsx
+++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarTable.tsx
@@ -9,6 +9,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
import { Separator } from "@/components/ui/separator";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Textarea } from "@/components/ui/textarea";
+import { tfvarsOnBulkUpdate, tfvarsOnDelete, tfvarsOnUpdate } from "@/data/user/tfvars";
import { EnvVar } from "@/types/userTypes";
import { motion } from 'framer-motion';
import { Copy, Edit, LockKeyhole, Plus, Save, Trash, Unlock } from 'lucide-react';
@@ -19,9 +20,7 @@ import { toast } from 'sonner';
type TFVarTableProps = {
envVars: EnvVar[];
- onUpdate: (oldName: string, newName: string, value: string, isSecret: boolean) => Promise;
- onDelete: (name: string) => Promise;
- onBulkUpdate: (vars: EnvVar[]) => Promise;
+ projectId: string;
};
const EmptyState: React.FC<{ onAddVariable: () => void }> = ({ onAddVariable }) => {
@@ -51,7 +50,7 @@ const EmptyState: React.FC<{ onAddVariable: () => void }> = ({ onAddVariable })
);
};
-export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }: TFVarTableProps) {
+export default function TFVarTable({ projectId, envVars }: TFVarTableProps) {
const [editingVar, setEditingVar] = useState<{ originalName: string, currentVar: EnvVar } | null>(null);
const [newVar, setNewVar] = useState>({ name: '', value: '', is_secret: false });
const [bulkEditMode, setBulkEditMode] = useState(false);
@@ -70,7 +69,6 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
});
};
-
const handleSave = async () => {
if (editingVar) {
if (editingVar.currentVar.name.toLowerCase() !== editingVar.originalName.toLowerCase() &&
@@ -80,11 +78,12 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
}
setIsLoading(true);
try {
- await onUpdate(
+ await tfvarsOnUpdate(
editingVar.originalName,
editingVar.currentVar.name,
editingVar.currentVar.value,
- editingVar.currentVar.is_secret
+ editingVar.currentVar.is_secret,
+ projectId
);
toast.success('Variable updated successfully');
setEditingVar(null);
@@ -97,7 +96,6 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
}
};
-
const handleAddNew = async () => {
if (newVar.name && newVar.value) {
if (envVars.some(v => v.name.toLowerCase() === newVar.name.toLowerCase())) {
@@ -106,7 +104,7 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
}
setIsLoading(true);
try {
- await onUpdate(newVar.name, newVar.name, newVar.value, newVar.is_secret);
+ await tfvarsOnUpdate(newVar.name, newVar.name, newVar.value, newVar.is_secret, projectId);
toast.success('New variable added successfully');
setNewVar({ name: '', value: '', is_secret: false });
setShowAddForm(false);
@@ -122,7 +120,7 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
const handleDeleteVar = async (name: string) => {
setIsLoading(true);
try {
- await onDelete(name);
+ await tfvarsOnDelete(name, projectId);
toast.success('Variable deleted successfully');
router.refresh();
} catch (error) {
@@ -136,7 +134,6 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
try {
const parsedVars = JSON.parse(bulkEditValue);
if (Array.isArray(parsedVars)) {
- // Check for duplicate names in the parsed vars
const names = parsedVars.map(v => v.name.toLowerCase());
if (new Set(names).size !== names.length) {
toast.error('Duplicate variable names are not allowed');
@@ -144,7 +141,7 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
}
setIsLoading(true);
- await onBulkUpdate(parsedVars);
+ await tfvarsOnBulkUpdate(parsedVars, projectId);
toast.success('Bulk update successful');
setBulkEditMode(false);
router.refresh();
@@ -156,7 +153,6 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
}
};
-
const toggleBulkEdit = () => {
if (!bulkEditMode) {
const nonSecretVars = envVars.filter(v => !v.is_secret).map(({ name, value }) => ({ name, value }));
@@ -345,7 +341,6 @@ export default function TFVarTable({ envVars, onUpdate, onDelete, onBulkUpdate }
Edit all environment variables at once in JSON format. Be careful with this operation.
- {/*
*/}
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarsDetails.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarsDetails.tsx
index 0860738d..d9c35032 100644
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarsDetails.tsx
+++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/TFVarsDetails.tsx
@@ -1,3 +1,4 @@
+// TFVarsDetails.tsx
'use client'
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
@@ -8,18 +9,11 @@ import { motion } from "framer-motion";
import TFVarTable from "./TFVarTable";
type TFVarsDetailsProps = {
- tfvarsdata: {
- id: string;
- project_id: string;
- tfvars: EnvVar[];
- updated_at: string;
- };
- onUpdate: (oldName: string, newName: string, value: string, isSecret: boolean) => Promise
;
- onDelete: (name: string) => Promise;
- onBulkUpdate: (vars: EnvVar[]) => Promise;
+ projectId: string;
+ initialEnvVars: EnvVar[];
}
-export default function TFVarsDetails({ tfvarsdata, onUpdate, onDelete, onBulkUpdate }: TFVarsDetailsProps) {
+export default function TFVarsDetails({ projectId, initialEnvVars }: TFVarsDetailsProps) {
return (
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/tfvars/page.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/tfvars/page.tsx
index 383c375d..5b2ba9c7 100644
--- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/tfvars/page.tsx
+++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/tfvars/page.tsx
@@ -1,6 +1,6 @@
-import { deleteEnvVar, getAllEnvVars, storeEncryptedEnvVar } from "@/data/admin/encryption";
+// page.tsx
+import { getAllEnvVars } from "@/data/admin/encryption";
import { getSlimProjectBySlug } from "@/data/user/projects";
-import { EnvVar } from "@/types/userTypes";
import { projectSlugParamSchema } from "@/utils/zod-schemas/params";
import type { Metadata } from "next";
import TFVarsDetails from '../TFVarsDetails';
@@ -28,60 +28,13 @@ export default async function TFVarsPage({ params }: { params: unknown }) {
throw new Error('MASTER_PASSWORD or ENCRYPTION_SALT is not set');
}
- const envVars = await getAllEnvVars(project.id, MASTER_PASSWORD, ENCRYPTION_SALT);
-
- async function handleUpdate(oldName: string, newName: string, value: string, isSecret: boolean) {
- 'use server'
- if (oldName !== newName) {
- await deleteEnvVar(project.id, oldName);
- }
- await storeEncryptedEnvVar(project.id, newName, value, isSecret, MASTER_PASSWORD, ENCRYPTION_SALT);
- return getAllEnvVars(project.id, MASTER_PASSWORD, ENCRYPTION_SALT);
- }
-
- async function handleDelete(name: string) {
- 'use server'
- await deleteEnvVar(project.id, name);
- return getAllEnvVars(project.id, MASTER_PASSWORD, ENCRYPTION_SALT);
- }
-
- async function handleBulkUpdate(vars: EnvVar[]) {
- 'use server'
- const currentVars = await getAllEnvVars(project.id, MASTER_PASSWORD, ENCRYPTION_SALT);
- const currentVarsMap = Object.fromEntries(currentVars.map(v => [v.name, v]));
-
- for (const newVar of vars) {
- const currentVar = currentVarsMap[newVar.name];
- if (currentVar) {
- if (!currentVar.is_secret && (currentVar.value !== newVar.value || currentVar.name !== newVar.name)) {
- await handleUpdate(currentVar.name, newVar.name, newVar.value, currentVar.is_secret);
- }
- } else {
- await handleUpdate(newVar.name, newVar.name, newVar.value, false);
- }
- }
-
- for (const currentVar of currentVars) {
- if (!vars.some(v => v.name === currentVar.name) && !currentVar.is_secret) {
- await deleteEnvVar(project.id, currentVar.name);
- }
- }
-
- return getAllEnvVars(project.id, MASTER_PASSWORD, ENCRYPTION_SALT);
- }
+ const envVars = await getAllEnvVars(project.id);
return (
);
diff --git a/src/data/admin/encryption.ts b/src/data/admin/encryption.ts
index c6de87d1..0bce3cfc 100644
--- a/src/data/admin/encryption.ts
+++ b/src/data/admin/encryption.ts
@@ -61,8 +61,6 @@ export async function storeEncryptedEnvVar(
name: string,
value: string,
isSecret: boolean,
- masterPassword: string,
- salt: string,
) {
console.log('Encryption: Storing encrypted var:', {
projectId,
@@ -93,11 +91,7 @@ export async function storeEncryptedEnvVar(
console.log('Encryption: Variable stored successfully');
return data;
}
-export async function getDecryptedEnvVar(
- projectId: string,
- name: string,
- masterPassword: string,
-) {
+export async function getDecryptedEnvVar(projectId: string, name: string) {
const { data, error } = await supabaseAdminClient
.from('encrypted_env_vars')
.select('encrypted_value, is_secret')
@@ -133,11 +127,7 @@ export async function deleteEnvVar(projectId: string, name: string) {
if (error) throw error;
}
-export async function getAllEnvVars(
- projectId: string,
- masterPassword: string,
- salt: string,
-): Promise {
+export async function getAllEnvVars(projectId: string): Promise {
const { data, error } = await supabaseAdminClient
.from('encrypted_env_vars')
.select('name, encrypted_value, is_secret, updated_at')
diff --git a/src/data/user/tfvars.ts b/src/data/user/tfvars.ts
index e69de29b..fee2d479 100644
--- a/src/data/user/tfvars.ts
+++ b/src/data/user/tfvars.ts
@@ -0,0 +1,84 @@
+// tfvars.ts
+'use server';
+
+import { EnvVar } from '@/types/userTypes';
+import {
+ deleteEnvVar,
+ getAllEnvVars,
+ storeEncryptedEnvVar,
+} from '../admin/encryption';
+
+export async function tfvarsOnUpdate(
+ oldName: string,
+ newName: string,
+ value: string,
+ isSecret: boolean,
+ projectId: string,
+): Promise {
+ if (oldName !== newName) {
+ await deleteEnvVar(projectId, oldName);
+ }
+ await storeEncryptedEnvVar(projectId, newName, value, isSecret);
+ const vars = await getAllEnvVars(projectId);
+ return vars.map((v) => ({ ...v, updated_at: new Date().toISOString() }));
+}
+
+export async function tfvarsOnDelete(
+ name: string,
+ projectId: string,
+): Promise {
+ await deleteEnvVar(projectId, name);
+ const vars = await getAllEnvVars(projectId);
+ return vars.map((v) => ({ ...v, updated_at: new Date().toISOString() }));
+}
+
+export async function tfvarsOnBulkUpdate(
+ vars: EnvVar[],
+ projectId: string,
+): Promise {
+ const currentVars = await getAllEnvVars(projectId);
+ const currentVarsMap = Object.fromEntries(
+ currentVars.map((v) => [v.name, v]),
+ );
+
+ for (const newVar of vars) {
+ const currentVar = currentVarsMap[newVar.name];
+ if (currentVar) {
+ if (
+ !currentVar.is_secret &&
+ (currentVar.value !== newVar.value || currentVar.name !== newVar.name)
+ ) {
+ await tfvarsOnUpdate(
+ currentVar.name,
+ newVar.name,
+ newVar.value,
+ currentVar.is_secret,
+ projectId,
+ );
+ }
+ } else {
+ await tfvarsOnUpdate(
+ newVar.name,
+ newVar.name,
+ newVar.value,
+ false,
+ projectId,
+ );
+ }
+ }
+
+ for (const currentVar of currentVars) {
+ if (
+ !vars.some((v) => v.name === currentVar.name) &&
+ !currentVar.is_secret
+ ) {
+ await tfvarsOnDelete(currentVar.name, projectId);
+ }
+ }
+
+ const updatedVars = await getAllEnvVars(projectId);
+ return updatedVars.map((v) => ({
+ ...v,
+ updated_at: new Date().toISOString(),
+ }));
+}