Skip to content

Commit

Permalink
Merge branch 'main' into kalilsn/sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
kalilsn authored Feb 25, 2025
2 parents 69f0f95 + 07ab053 commit 6437e39
Show file tree
Hide file tree
Showing 12 changed files with 619 additions and 138 deletions.
55 changes: 55 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# yaml-language-server: $schema=https://json.schemastore.org/dependabot-2.0.json
# Dependabot configuration file
# See documentation: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
# package.json + pnpm catalog updates
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 10
labels:
- "dependencies"
- "npm"
commit-message:
prefix: "npm"
include: "scope"
# group all minor and patch updates together
groups:
minor-patch-dependencies:
patterns:
- "*"
update-types:
- "minor"
- "patch"

# GitHub Actions updates
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "github-actions"
commit-message:
prefix: "github-actions"
include: "scope"

# docker updates
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels:
- "dependencies"
- "docker"
commit-message:
prefix: "docker"
include: "scope"
4 changes: 3 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"ms-playwright.playwright",
"YoavBls.pretty-ts-errors",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint"
"dbaeumer.vscode-eslint",
// for yaml autocompletion using the # yaml-language-server: $schema=... directive
"redhat.vscode-yaml"
]
}
21 changes: 15 additions & 6 deletions core/app/c/[communitySlug]/pubs/[pubId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MembersList } from "~/app/components//Memberships/MembersList";
import { PubsRunActionDropDownMenu } from "~/app/components/ActionUI/PubsRunActionDropDownMenu";
import { AddMemberDialog } from "~/app/components/Memberships/AddMemberDialog";
import { CreatePubButton } from "~/app/components/pubs/CreatePubButton";
import { RemovePubButton } from "~/app/components/pubs/RemovePubButton";
import SkeletonTable from "~/app/components/skeletons/SkeletonTable";
import { db } from "~/kysely/database";
import { getPageLoginData } from "~/lib/authentication/loginData";
Expand Down Expand Up @@ -156,12 +157,20 @@ export default async function Page(props: {
</div>
<h1 className="mb-2 text-xl font-bold">{getPubTitle(pub)} </h1>
</div>
<Button variant="outline" asChild className="flex items-center gap-1">
<Link href={`/c/${communitySlug}/pubs/${pub.id}/edit`}>
<Pencil size="14" />
Update
</Link>
</Button>
<div className="flex items-center gap-2">
<Button
variant="outline"
size="sm"
asChild
className="flex items-center gap-x-2 py-4"
>
<Link href={`/c/${communitySlug}/pubs/${pub.id}/edit`}>
<Pencil size="12" />
<span>Update</span>
</Link>
</Button>
<RemovePubButton pubId={pub.id} redirectTo={`/c/${communitySlug}/pubs`} />
</div>
</div>

<div className="flex flex-wrap space-x-4">
Expand Down
2 changes: 1 addition & 1 deletion core/app/components/pubs/RemovePubButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ButtonProps } from "ui/button";
import { Trash } from "ui/icon";

import type { PubRemoveProps } from "./RemovePubForm";
import type { PubRemoveProps } from "./RemovePubFormClient";
import { PathAwareDialog } from "../PathAwareDialog";
import { PubRemove } from "./RemovePubForm";

Expand Down
11 changes: 3 additions & 8 deletions core/app/components/pubs/RemovePubForm.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { Suspense } from "react";
import dynamic from "next/dynamic";

import type { PubsId } from "db/public";

import type { PubRemoveProps } from "./RemovePubFormClient";
import { SkeletonCard } from "../skeletons/SkeletonCard";

export type PubRemoveProps = {
pubId: PubsId;
};

const PubRemoveForm = dynamic(
async () => {
return import("./RemovePubFormClient").then((mod) => ({
Expand All @@ -18,10 +13,10 @@ const PubRemoveForm = dynamic(
{ loading: () => <SkeletonCard /> }
);

export async function PubRemove({ pubId }: PubRemoveProps) {
export async function PubRemove({ pubId, redirectTo }: PubRemoveProps) {
return (
<Suspense fallback={<div>Loading...</div>}>
<PubRemoveForm pubId={pubId} />
<PubRemoveForm pubId={pubId} redirectTo={redirectTo} />
</Suspense>
);
}
15 changes: 12 additions & 3 deletions core/app/components/pubs/RemovePubFormClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import { toast } from "ui/use-toast";
import { useServerAction } from "~/lib/serverActions";
import * as actions from "./PubEditor/actions";

export const PubRemoveForm = ({ pubId }: { pubId: PubsId }) => {
export type PubRemoveProps = {
pubId: PubsId;
redirectTo?: string;
};

export const PubRemoveForm = ({ pubId, redirectTo }: PubRemoveProps) => {
const form = useForm({
mode: "onChange",
reValidateMode: "onChange",
Expand All @@ -32,8 +37,12 @@ export const PubRemoveForm = ({ pubId }: { pubId: PubsId }) => {
}, [path, searchParams]);

const closeForm = useCallback(() => {
router.replace(pathWithoutFormParam);
}, [pathWithoutFormParam]);
if (redirectTo) {
router.push(redirectTo);
} else {
router.replace(pathWithoutFormParam);
}
}, [pathWithoutFormParam, redirectTo, router]);

const onSubmit = async () => {
const result = await runRemovePub({
Expand Down
48 changes: 48 additions & 0 deletions core/lib/server/assets.db.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import fs from "fs/promises";

import { beforeAll, describe, expect, it } from "vitest";

import { mockServerCode } from "~/lib/__tests__/utils";
import { env } from "../env/env.mjs";

const { createForEachMockedTransaction } = await mockServerCode();

const { getTrx } = createForEachMockedTransaction();

beforeAll(async () => {
// check if minio is up

if (!env.ASSETS_STORAGE_ENDPOINT) {
throw new Error(
"You should only run this test against a local minio instance, not to prod S3"
);
}

const check = await fetch(env.ASSETS_STORAGE_ENDPOINT, {
method: "OPTIONS",
});

if (!check.ok) {
throw new Error(
"Minio is not running. Please setup the test environment properly by running `pnpm -w test:setup`"
);
}
});

describe("assets upload", () => {
it("should be able to upload a file to the minio bucket from the server", async () => {
const { uploadFileToS3 } = await import("./assets");

const file = await fs.readFile(new URL("./assets.ts", import.meta.url));

const url = await uploadFileToS3("test", "test.ts", file, {
contentType: "text/plain",
});

expect(url).toBeDefined();

const text = await fetch(url).then((res) => res.text());

expect(text).toEqual(file.toString("utf8"));
});
});
76 changes: 73 additions & 3 deletions core/lib/server/assets.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

import type { PubsId } from "db/public";
import { logger } from "logger";

import { env } from "../env/env.mjs";

export const generateSignedAssetUploadUrl = async (pubId: PubsId, fileName: string) => {
let s3Client: S3Client;

export const getS3Client = () => {
if (s3Client) {
return s3Client;
}

const region = env.ASSETS_REGION;
const key = env.ASSETS_UPLOAD_KEY;
const secret = env.ASSETS_UPLOAD_SECRET_KEY;
const bucket = env.ASSETS_BUCKET_NAME;

const client = new S3Client({
s3Client = new S3Client({
endpoint: env.ASSETS_STORAGE_ENDPOINT,
region: region,
credentials: {
Expand All @@ -20,9 +27,72 @@ export const generateSignedAssetUploadUrl = async (pubId: PubsId, fileName: stri
},
forcePathStyle: !!env.ASSETS_STORAGE_ENDPOINT, // Required for MinIO
});

return s3Client;
};

export const generateSignedAssetUploadUrl = async (pubId: PubsId, fileName: string) => {
const client = getS3Client();

const bucket = env.ASSETS_BUCKET_NAME;
const command = new PutObjectCommand({
Bucket: bucket,
Key: `${pubId}/${fileName}`,
});

return await getSignedUrl(client, command, { expiresIn: 3600 });
};

/**
* Uploads a file to the S3 bucket using the S3 client directly
* @param id - id under which the file will be stored. eg for a pub, the pubId. for community assets like the logo, the communityId. for user avatars, the userId.
* @param fileName - name of the file to be stored
* @param fileData - the file data to upload (Buffer or Uint8Array)
* @param contentType - MIME type of the file (e.g., 'image/jpeg')
* @returns the URL of the uploaded file
*/
export const uploadFileToS3 = async (
id: string,
fileName: string,
fileData: Buffer | Uint8Array,
{
contentType,
queueSize,
partSize,
progressCallback,
}: {
contentType: string;
queueSize?: number;
partSize?: number;
progressCallback?: (progress: any) => void;
}
): Promise<string> => {
const client = getS3Client();
const bucket = env.ASSETS_BUCKET_NAME;
const key = `${id}/${fileName}`;

const parallelUploads3 = new Upload({
client,
params: {
Bucket: bucket,
Key: key,
Body: fileData,
ContentType: contentType,
},
queueSize: queueSize ?? 3, // optional concurrency configuration
partSize: partSize ?? 1024 * 1024 * 5, // optional size of each part, in bytes, at least 5MB
leavePartsOnError: false, // optional manually handle dropped parts
});

parallelUploads3.on(
"httpUploadProgress",
progressCallback ??
((progress) => {
logger.debug(progress);
})
);

const result = await parallelUploads3.done();

return result.Location!;
};
1 change: 1 addition & 0 deletions core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
},
"dependencies": {
"@aws-sdk/client-s3": "^3.445.0",
"@aws-sdk/lib-storage": "^3.750.0",
"@aws-sdk/s3-request-presigner": "^3.445.0",
"@dagrejs/dagre": "^1.0.4",
"@dnd-kit/core": "^6.1.0",
Expand Down
6 changes: 3 additions & 3 deletions core/playwright/pub.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,15 +62,15 @@ test.describe("Moving a pub", () => {
await pubDetailsPage.goTo();
await expect(page.getByTestId("current-stage")).toHaveText("Submitted");
// For this initial stage, there are only destinations ,no sources
await page.getByRole("button", { name: "Move" }).click();
await page.getByRole("button", { name: "Move", exact: true }).click();
const sources = page.getByTestId("sources");
const destinations = page.getByTestId("destinations");
await expect(sources).toHaveCount(0);
await destinations.getByRole("button", { name: "Ask Author For Consent" }).click();
await expect(page.getByTestId("current-stage")).toHaveText("Ask Author for Consent");

// Open the move modal again and expect to be able to move to sources and destinations
await page.getByRole("button", { name: "Move" }).click();
await page.getByRole("button", { name: "Move", exact: true }).click();
await expect(sources.getByRole("button", { name: "Submitted" })).toHaveCount(1);
await expect(destinations.getByRole("button", { name: "To Evaluate" })).toHaveCount(1);
});
Expand All @@ -91,7 +91,7 @@ test.describe("Moving a pub", () => {
const pubDetailsPage = new PubDetailsPage(page, COMMUNITY_SLUG, pubId);
await pubDetailsPage.goTo();
await expect(page.getByTestId("current-stage")).toHaveText("Shelved");
await expect(page.getByRole("button", { name: "Move" })).toHaveCount(0);
await expect(page.getByRole("button", { name: "Move", exact: true })).toHaveCount(0);
});
});

Expand Down
2 changes: 2 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ services:
networks:
- app-network
profiles:
- test
- integration

minio-init:
Expand All @@ -39,6 +40,7 @@ services:
networks:
- app-network
profiles:
- test
- integration

inbucket:
Expand Down
Loading

0 comments on commit 6437e39

Please sign in to comment.