Skip to content

Commit

Permalink
✨ Folders: Ability to set Hero Image
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacInsoll committed Dec 1, 2024
1 parent 89081f0 commit 63e6e26
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 1 deletion.
29 changes: 29 additions & 0 deletions backend/graphql/mutations/editFolder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { contextPermissionsForFolder as perms } from '../../auth/contextPermissionsForFolder';
import { doAuthError } from '../../auth/doAuthError';
import Folder from '../../models/Folder';
import File from '../../models/File';
import { GraphQLID, GraphQLNonNull } from 'graphql/index';
import { folderType } from '../types/folderType';

const resolver = async (_, params, context) => {
const [p, u] = await perms(context, params.folderId, true);
if (p != 'Admin') doAuthError("You don't have permissions for this folder");
const folder = await Folder.findByPk(params.folderId);
const heroImage = await File.findByPk(params.heroImageId);
if (!heroImage) doAuthError('Invalid hero image ID');
if (heroImage.type != 'Image') doAuthError('Not an image');
if (heroImage.folderId != folder.id) doAuthError('Not in this folder');

folder.heroImageId = heroImage.id;
await folder.save();
return { ...folder.toJSON(), heroImage };
};

export const editFolder = {
type: new GraphQLNonNull(folderType),
resolve: resolver,
args: {
folderId: { type: new GraphQLNonNull(GraphQLID) },
heroImageId: { type: GraphQLID },
},
};
2 changes: 2 additions & 0 deletions backend/graphql/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { serverInfoType } from './types/serverInfoType';
import { serverInfo } from './queries/serverInfoQuery';
import { searchFolders } from './queries/searchFolders';
import { searchFiles } from './queries/searchFiles';
import { editFolder } from './mutations/editFolder';

const queries = new GraphQLObjectType({
fields: () => ({
Expand Down Expand Up @@ -59,6 +60,7 @@ const mutations = new GraphQLObjectType({
editUser,
generateThumbnails,
generateZip,
editFolder,
}),
});

Expand Down
45 changes: 45 additions & 0 deletions frontend/public/graphql.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,51 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "editFolder",
"description": null,
"args": [
{
"name": "folderId",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "heroImageId",
"description": null,
"type": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Folder",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "editUser",
"description": null,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/FileListView/Review/FileReview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { addCommentMutation } from './addCommentMutation';
import { useCommentPermissions } from '../../../hooks/useCommentPermissions';
import { FileFlagBadge } from './FileFlagBadge';
import { FileRating } from './FileRating';
import { SetHeroImageButton } from './SetHeroImageButton';

// Horizontal component containing Flag, Rating and Comment buttons
export const FileReview = ({ file }: { file: MinimalFile }) => {
Expand Down Expand Up @@ -42,6 +43,7 @@ export const FileReview = ({ file }: { file: MinimalFile }) => {
totalComments={totalComments}
onClick={() => openComment(file.id)}
/>
<SetHeroImageButton file={file} />
</Group>
);
};
39 changes: 39 additions & 0 deletions frontend/src/components/FileListView/Review/SetHeroImageButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { MinimalFile } from '../../../../types';
import { useMe } from '../../../hooks/useMe';
import { ActionIcon, Tooltip } from '@mantine/core';
import { TbPhotoHeart } from 'react-icons/tb';
import { gql } from '../../../helpers/gql';
import { useMutation } from 'urql';
import { useState } from 'react';

export const SetHeroImageButton = ({ file }: { file: MinimalFile }) => {
const { isUser } = useMe();
const [, mutate] = useMutation(editFolderMutation);
const [loading, setLoading] = useState(false);
if (!isUser || !file || !file.type == 'Image') return null;
//TODO: actually do mutation
//TODO: look different if we are looking at the current hero image :)
const onClick = () => {
setLoading(true);
mutate({
folderId: file.folderId,
heroImageId: file?.id,
}).then(() => setLoading(false));
};
return (
<Tooltip label="Use this Image as the 'Hero Image' for this folder">
<ActionIcon variant="default" onClick={onClick} loading={loading}>
<TbPhotoHeart />
</ActionIcon>
</Tooltip>
);
};

const editFolderMutation = gql(/* GraphQL */ `
mutation editFolder($folderId: ID!, $heroImageId: ID!) {
editFolder(folderId: $folderId, heroImageId: $heroImageId) {
...FolderFragment
...HeroImageFragment
}
}
`);
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const SelectedFileView = ({
view: ({ index }) => {
const f = files[index];
// don't change URL if we are already on that URL (IE: first opening gallery)
if (f.id != fileId) {
if (f?.id && f.id != fileId) {
setFolder({ id: folderId }, f);
}
},
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/gql/gql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/
const documents = {
"\n mutation addComment(\n $id: ID!\n $rating: Int\n $flag: FileFlag\n $comment: String\n $nickName: String\n ) {\n addComment(\n id: $id\n rating: $rating\n flag: $flag\n comment: $comment\n nickName: $nickName\n ) {\n ...FileFragment\n }\n }\n": types.AddCommentDocument,
"\n query commentHistoryQuery($fileId: ID!) {\n comments(fileId: $fileId) {\n id\n comment\n systemGenerated\n timestamp\n user {\n id\n }\n }\n }\n": types.CommentHistoryQueryDocument,
"\n mutation editFolder($folderId: ID!, $heroImageId: ID!) {\n editFolder(folderId: $folderId, heroImageId: $heroImageId) {\n ...FolderFragment\n ...HeroImageFragment\n }\n }\n": types.EditFolderDocument,
"\n query searchQuery($folderId: ID!, $query: String!) {\n searchFolders(folderId: $folderId, query: $query) {\n ...FolderFragment\n }\n searchFiles(folderId: $folderId, query: $query) {\n ...FileFragment\n folder {\n ...MinimumFolderFragment\n }\n }\n }\n": types.SearchQueryDocument,
"\n query MeQuery {\n me {\n id\n name\n folderId\n uuid\n commentPermissions\n folder {\n id\n name\n }\n }\n }\n": types.MeQueryDocument,
"\n query generateThumbnailsStats($folderId: ID!) {\n folder(id: $folderId) {\n ...FolderFragment\n totalImages\n }\n }\n ": types.GenerateThumbnailsStatsDocument,
Expand Down Expand Up @@ -63,6 +64,10 @@ export function graphql(source: "\n mutation addComment(\n $id: ID!\n $ra
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n query commentHistoryQuery($fileId: ID!) {\n comments(fileId: $fileId) {\n id\n comment\n systemGenerated\n timestamp\n user {\n id\n }\n }\n }\n"): (typeof documents)["\n query commentHistoryQuery($fileId: ID!) {\n comments(fileId: $fileId) {\n id\n comment\n systemGenerated\n timestamp\n user {\n id\n }\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function graphql(source: "\n mutation editFolder($folderId: ID!, $heroImageId: ID!) {\n editFolder(folderId: $folderId, heroImageId: $heroImageId) {\n ...FolderFragment\n ...HeroImageFragment\n }\n }\n"): (typeof documents)["\n mutation editFolder($folderId: ID!, $heroImageId: ID!) {\n editFolder(folderId: $folderId, heroImageId: $heroImageId) {\n ...FolderFragment\n ...HeroImageFragment\n }\n }\n"];
/**
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
Expand Down
Loading

0 comments on commit 63e6e26

Please sign in to comment.