feature: add download all file by file alongside the tar download
This commit is contained in:
parent
27e9b7eb35
commit
48e5e8a71c
20 changed files with 79 additions and 45 deletions
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "ConvertX Development Environment",
|
||||
"name": "ConvertX",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
|
|
@ -46,5 +46,8 @@
|
|||
},
|
||||
"postCreateCommand": "bun install",
|
||||
"remoteUser": "root",
|
||||
"mounts": ["source=${localWorkspaceFolder}/data,target=/app/data,type=bind"]
|
||||
"mounts": ["source=${localWorkspaceFolder}/data,target=/app/data,type=bind"],
|
||||
"containerEnv": {
|
||||
"JWT_SECRET": "jwt_secret_only_used_in_testing_for_easier_hot_reloading"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,3 +22,17 @@ const refreshData = () => {
|
|||
};
|
||||
|
||||
refreshData();
|
||||
|
||||
window.downloadAll = function () {
|
||||
// Get all download links
|
||||
const downloadLinks = document.querySelectorAll("a[download]");
|
||||
|
||||
// Trigger download for each link
|
||||
downloadLinks.forEach((link, index) => {
|
||||
// We add a delay for each download to prevent them from starting at the same time
|
||||
setTimeout(() => {
|
||||
const event = new MouseEvent("click");
|
||||
link.dispatchEvent(event);
|
||||
}, index * 300);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
1
reset.d.ts
vendored
1
reset.d.ts
vendored
|
|
@ -1 +0,0 @@
|
|||
import "@total-typescript/ts-reset";
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import { Html } from "@elysiajs/html";
|
||||
import { version } from "../../package.json";
|
||||
|
||||
export const BaseHtml = ({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import { Html } from "@kitajs/html";
|
||||
|
||||
export const Header = ({
|
||||
loggedIn,
|
||||
accountRegistration,
|
||||
|
|
|
|||
18
src/icons/download.tsx
Normal file
18
src/icons/download.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
export function DownloadIcon() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="1.5"
|
||||
stroke="currentColor"
|
||||
class={`size-6`}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
19
src/icons/eye.tsx
Normal file
19
src/icons/eye.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
export function EyeIcon() {
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
class={`size-6`}
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"
|
||||
/>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import { Html } from "@elysiajs/html";
|
||||
import Elysia, { t } from "elysia";
|
||||
import { getPossibleTargets } from "../converters/main";
|
||||
import { userService } from "./user";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { Html } from "@elysiajs/html";
|
||||
import { Elysia } from "elysia";
|
||||
import { BaseHtml } from "../components/base";
|
||||
import { Header } from "../components/header";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { Html } from "@elysiajs/html";
|
||||
import Elysia from "elysia";
|
||||
import { BaseHtml } from "../components/base";
|
||||
import { Header } from "../components/header";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { Html } from "@elysiajs/html";
|
||||
import { JWTPayloadSpec } from "@elysiajs/jwt";
|
||||
import { Elysia } from "elysia";
|
||||
import { BaseHtml } from "../components/base";
|
||||
|
|
@ -6,6 +5,8 @@ import { Header } from "../components/header";
|
|||
import db from "../db/db";
|
||||
import { Filename, Jobs } from "../db/types";
|
||||
import { ALLOW_UNAUTHENTICATED, WEBROOT } from "../helpers/env";
|
||||
import { DownloadIcon } from "../icons/download";
|
||||
import { EyeIcon } from "../icons/eye";
|
||||
import { userService } from "./user";
|
||||
|
||||
function ResultsArticle({
|
||||
|
|
@ -25,25 +26,24 @@ function ResultsArticle({
|
|||
<article class="article">
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<h1 class="text-xl">Results</h1>
|
||||
<div>
|
||||
<div class="flex flex-row gap-4">
|
||||
<a
|
||||
style={files.length !== job.num_files ? "pointer-events: none;" : ""}
|
||||
href={`${WEBROOT}/archive/${user.id}/${job.id}`}
|
||||
download={`converted_files_${job.id}.tar`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="float-right w-40 btn-primary"
|
||||
class="flex btn-primary flex-row gap-2 text-contrast"
|
||||
{...(files.length !== job.num_files ? { disabled: true, "aria-busy": "true" } : "")}
|
||||
>
|
||||
{files.length === job.num_files ? "Download All" : "Converting..."}
|
||||
</button>
|
||||
<DownloadIcon /> <p>Tar</p>
|
||||
</a>
|
||||
<button class="flex btn-primary flex-row gap-2 text-contrast" onclick="downloadAll()">
|
||||
<DownloadIcon /> <p>All</p>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<progress
|
||||
max={job.num_files}
|
||||
value={files.length}
|
||||
{...(files.length === job.num_files ? { value: files.length } : "")}
|
||||
class={`
|
||||
mb-4 inline-block h-2 w-full appearance-none overflow-hidden rounded-full border-0
|
||||
bg-neutral-700 bg-none text-accent-500 accent-accent-500
|
||||
|
|
@ -84,15 +84,7 @@ function ResultsArticle({
|
|||
sm:px-4
|
||||
`}
|
||||
>
|
||||
View
|
||||
</th>
|
||||
<th
|
||||
class={`
|
||||
px-2 py-2
|
||||
sm:px-4
|
||||
`}
|
||||
>
|
||||
Download
|
||||
Actions
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -103,7 +95,7 @@ function ResultsArticle({
|
|||
{file.output_file_name}
|
||||
</td>
|
||||
<td safe>{file.status}</td>
|
||||
<td>
|
||||
<td class="flex flex-row gap-4">
|
||||
<a
|
||||
class={`
|
||||
text-accent-500 underline
|
||||
|
|
@ -111,10 +103,8 @@ function ResultsArticle({
|
|||
`}
|
||||
href={`${WEBROOT}/download/${outputPath}${file.output_file_name}`}
|
||||
>
|
||||
View
|
||||
<EyeIcon />
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a
|
||||
class={`
|
||||
text-accent-500 underline
|
||||
|
|
@ -123,7 +113,7 @@ function ResultsArticle({
|
|||
href={`${WEBROOT}/download/${outputPath}${file.output_file_name}`}
|
||||
download={file.output_file_name}
|
||||
>
|
||||
Download
|
||||
<DownloadIcon />
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { randomInt } from "node:crypto";
|
||||
import { Html } from "@elysiajs/html";
|
||||
import { JWTPayloadSpec } from "@elysiajs/jwt";
|
||||
import { Elysia, t } from "elysia";
|
||||
import { BaseHtml } from "../components/base";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { randomUUID } from "node:crypto";
|
||||
import { Html } from "@elysiajs/html";
|
||||
import { jwt } from "@elysiajs/jwt";
|
||||
import { Elysia, t } from "elysia";
|
||||
import { BaseHtml } from "../components/base";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ExecFileException } from "node:child_process";
|
||||
import { beforeEach, expect, test } from "bun:test";
|
||||
import type { ExecFileException } from "node:child_process";
|
||||
import { convert } from "../../src/converters/dvisvgm";
|
||||
import { ExecFileFn } from "../../src/converters/types";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ExecFileException } from "node:child_process";
|
||||
import { expect } from "bun:test";
|
||||
import type { ExecFileException } from "node:child_process";
|
||||
import { ConvertFnWithExecFile, ExecFileFn } from "../../../src/converters/types";
|
||||
|
||||
export async function runConvertSuccessTest(convertFn: ConvertFnWithExecFile) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ExecFileException } from "node:child_process";
|
||||
import { beforeEach, expect, test } from "bun:test";
|
||||
import type { ExecFileException } from "node:child_process";
|
||||
import { convert } from "../../src/converters/imagemagick";
|
||||
import { ExecFileFn } from "../../src/converters/types";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ExecFileException } from "node:child_process";
|
||||
import { beforeEach, expect, test } from "bun:test";
|
||||
import type { ExecFileException } from "node:child_process";
|
||||
import { convert } from "../../src/converters/libjxl";
|
||||
import { ExecFileFn } from "../../src/converters/types";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ExecFileException } from "node:child_process";
|
||||
import { expect, test } from "bun:test";
|
||||
import type { ExecFileException } from "node:child_process";
|
||||
import { convert } from "../../src/converters/msgconvert";
|
||||
import { ExecFileFn } from "../../src/converters/types";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ExecFileException } from "node:child_process";
|
||||
import { beforeEach, expect, test } from "bun:test";
|
||||
import type { ExecFileException } from "node:child_process";
|
||||
import { ExecFileFn } from "../../src/converters/types";
|
||||
import { convert } from "../../src/converters/vips";
|
||||
import { runCommonTests } from "./helpers/commonTests";
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@
|
|||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "Html.createElement",
|
||||
"jsxFragmentFactory": "Html.Fragment",
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "@kitajs/html",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"allowJs": true,
|
||||
|
|
@ -30,5 +29,5 @@
|
|||
"esModuleInterop": true
|
||||
// "noImplicitReturns": true
|
||||
},
|
||||
"include": ["src", "tests", "package.json", "reset.d.ts"]
|
||||
"include": ["src", "tests", "package.json"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue