Skip to content

Commit

Permalink
feat: add functionality to download DB Gate files
Browse files Browse the repository at this point in the history
  • Loading branch information
biersoeckli committed Jan 28, 2025
1 parent 460ac6f commit 88ce5f5
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 10 deletions.
9 changes: 8 additions & 1 deletion src/app/project/app/[appId]/credentials/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,11 @@ export const deleteDbGatDeploymentForAppIfExists = async (appId: string) =>
await getAuthUserSession();
await dbGateService.deleteDbGatDeploymentForAppIfExists(appId);
return new SuccessActionResult();
}) as Promise<ServerActionResult<unknown, void>>;
}) as Promise<ServerActionResult<unknown, void>>;

export const downloadDbGateFilesForApp = async (appId: string) =>
simpleAction(async () => {
await getAuthUserSession();
const url = await dbGateService.downloadDbGateFilesForApp(appId);
return new SuccessActionResult(url);
}) as Promise<ServerActionResult<unknown, string>>;
6 changes: 0 additions & 6 deletions src/app/project/app/[appId]/credentials/db-crendentials.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { AppExtendedModel } from "@/shared/model/app-extended.model";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { useConfirmDialog } from "@/frontend/states/zustand.states";
import { Toast } from "@/frontend/utils/toast.utils";
import { ClipboardCopy } from "lucide-react";
import { toast } from "sonner";
import { DatabaseTemplateInfoModel } from "@/shared/model/database-template-info.model";
import { Actions } from "@/frontend/utils/nextjs-actions.utils";
import { getDatabaseCredentials } from "./actions";
import { Label } from "@/components/ui/label";
import CopyInputField from "@/components/custom/copy-input-field";
import FullLoadingSpinner from "@/components/ui/full-loading-spinnter";

Expand Down
35 changes: 32 additions & 3 deletions src/app/project/app/[appId]/credentials/db-gate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import { Button } from "@/components/ui/button";
import { useConfirmDialog } from "@/frontend/states/zustand.states";
import { Toast } from "@/frontend/utils/toast.utils";
import { Actions } from "@/frontend/utils/nextjs-actions.utils";
import { deleteDbGatDeploymentForAppIfExists, deployDbGate, getIsDbGateActive, getLoginCredentialsForRunningDbGate } from "./actions";
import { deleteDbGatDeploymentForAppIfExists, deployDbGate, downloadDbGateFilesForApp, getIsDbGateActive, getLoginCredentialsForRunningDbGate } from "./actions";
import { Label } from "@/components/ui/label";
import FullLoadingSpinner from "@/components/ui/full-loading-spinnter";
import { Switch } from "@/components/ui/switch";
import { Code } from "@/components/custom/code";
import LoadingSpinner from "@/components/ui/loading-spinner";
import { Download } from "lucide-react";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";

export default function DbGateCard({
app
Expand All @@ -27,6 +29,19 @@ export default function DbGateCard({
setIsDbGateActive(response);
}

const downloadDbGateFilesForAppAsync = async () => {
try {
setLoading(true);
await Toast.fromAction(() => downloadDbGateFilesForApp(app.id)).then(x => {
if (x.status === 'success' && x.data) {
window.open('/api/volume-data-download?fileName=' + x.data);
}
});
} finally {
setLoading(false);
}
}

const openDbGateAsync = async () => {
try {
setLoading(true);
Expand Down Expand Up @@ -88,9 +103,23 @@ export default function DbGateCard({
}} />
<Label htmlFor="airplane-mode">DB Gate</Label>
</div>
{isDbGateActive && <>
<Button variant='outline' onClick={() => openDbGateAsync()}
disabled={!isDbGateActive || loading}>Open DB Gate</Button>

<TooltipProvider>
<Tooltip delayDuration={300}>
<TooltipTrigger>
<Button onClick={() => downloadDbGateFilesForAppAsync()} disabled={!isDbGateActive || loading}
variant="ghost"><Download /></Button>
</TooltipTrigger>
<TooltipContent>
<p>Download the "Files" folder from DB Gate.</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</>}
{loading && <LoadingSpinner></LoadingSpinner>}
{isDbGateActive && <Button variant='outline' onClick={() => openDbGateAsync()}
disabled={!isDbGateActive || loading}>Open DB Gate</Button>}
</div>}
</CardContent>
</Card >
Expand Down
29 changes: 29 additions & 0 deletions src/server/services/dbgate.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import podService from "./pod.service";
import { AppTemplateUtils } from "../utils/app-template.utils";
import appService from "./app.service";
import { AppExtendedModel } from "@/shared/model/app-extended.model";
import { PathUtils } from "../utils/path.utils";
import { FsUtils } from "../utils/fs.utils";
import path from "path";

class DbGateService {

Expand All @@ -39,6 +42,32 @@ class DbGateService {
return true;
}

async downloadDbGateFilesForApp(appId: string) {

const app = await appService.getExtendedById(appId);
const dbGateAppName = KubeObjectNameUtils.toDbGateId(app.id);
const pod = await podService.getPodsForApp(app.projectId, dbGateAppName);
if (pod.length === 0) {
throw new ServiceException(`There are no running pods for DBGate. Make sure the DB Gate is running.`);
}
const firstPod = pod[0];

const continerSourcePath = '/root/.dbgate/files';
const continerRootPath = '/root';

await podService.runCommandInPod(app.projectId, firstPod.podName, firstPod.containerName, ['cp', '-r', continerSourcePath, continerRootPath]);

const downloadPath = path.join(PathUtils.tempVolumeDownloadPath, dbGateAppName + '.tar.gz');
await FsUtils.createDirIfNotExistsAsync(PathUtils.tempVolumeDownloadPath, true);
await FsUtils.deleteDirIfExistsAsync(downloadPath, true);

console.log(`Downloading data from pod ${firstPod.podName} ${continerRootPath} to ${downloadPath}`);
await podService.cpFromPod(app.projectId, firstPod.podName, firstPod.containerName, continerRootPath, downloadPath, continerRootPath);

const fileName = path.basename(downloadPath);
return fileName;
}

async getLoginCredentialsForRunningDbGate(appId: string) {
const app = await appService.getExtendedById(appId);
const dbGateAppName = KubeObjectNameUtils.toDbGateId(app.id);
Expand Down

0 comments on commit 88ce5f5

Please sign in to comment.