From f8619d3ef76f310a5b86c5890889e3d0d2e13c37 Mon Sep 17 00:00:00 2001 From: John Costa Date: Sun, 21 Sep 2025 16:48:17 +0100 Subject: [PATCH] fix: stuff --- backend/models/image.go | 9 +- backend/schema.sql | 4 +- .../notifications/ProcessingImage.tsx | 150 +++++++++--------- frontend/src/network/index.ts | 11 +- frontend/src/pages/list/index.tsx | 110 +++++++++++-- 5 files changed, 196 insertions(+), 88 deletions(-) diff --git a/backend/models/image.go b/backend/models/image.go index cdbcbb1..0681c37 100644 --- a/backend/models/image.go +++ b/backend/models/image.go @@ -9,6 +9,7 @@ import ( . "screenmark/screenmark/.gen/haystack/haystack/table" . "github.com/go-jet/jet/v2/postgres" + "github.com/go-jet/jet/v2/qrm" "github.com/google/uuid" ) @@ -250,11 +251,15 @@ func (m ImageModel) Delete(ctx context.Context, imageID uuid.UUID) error { func (m ImageModel) IsUserAuthorized(ctx context.Context, imageId uuid.UUID, userId uuid.UUID) bool { getImageUserId := UserImages.SELECT(UserImages.UserID).WHERE(UserImages.ImageID.EQ(UUID(imageId))) + getProcessingImageUserId := UserImagesToProcess.SELECT(UserImagesToProcess.UserID).WHERE(UserImagesToProcess.ImageID.EQ(UUID(imageId))) userImage := model.UserImages{} - err := getImageUserId.QueryContext(ctx, m.dbPool, &userImage) + userProcessingImage := model.UserImagesToProcess{} - return err == nil && userImage.UserID.String() == userId.String() + err1 := getImageUserId.QueryContext(ctx, m.dbPool, &userImage) + err2 := getProcessingImageUserId.QueryContext(ctx, m.dbPool, &userProcessingImage) + + return (err1 == nil || err1 == qrm.ErrNoRows) && (err2 == nil || err2 == qrm.ErrNoRows) && (userImage.UserID.String() == userId.String() || userProcessingImage.UserID.String() == userId.String()) } func NewImageModel(db *sql.DB) ImageModel { diff --git a/backend/schema.sql b/backend/schema.sql index f032a2b..82ad9d1 100644 --- a/backend/schema.sql +++ b/backend/schema.sql @@ -68,13 +68,13 @@ CREATE TABLE haystack.image_lists ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), image_id UUID NOT NULL REFERENCES haystack.image (id) ON DELETE CASCADE, - list_id UUID NOT NULL REFERENCES haystack.lists (id) + list_id UUID NOT NULL REFERENCES haystack.lists (id) ON DELETE CASCADE ); CREATE TABLE haystack.schemas ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - list_id UUID NOT NULL REFERENCES haystack.lists (id) + list_id UUID NOT NULL REFERENCES haystack.lists (id) ON DELETE CASCADE ); CREATE TABLE haystack.schema_items ( diff --git a/frontend/src/components/notifications/ProcessingImage.tsx b/frontend/src/components/notifications/ProcessingImage.tsx index b3eb0ed..10181ce 100644 --- a/frontend/src/components/notifications/ProcessingImage.tsx +++ b/frontend/src/components/notifications/ProcessingImage.tsx @@ -1,82 +1,86 @@ import { Popover } from "@kobalte/core/popover"; -import { Component, For, Show } from "solid-js"; +import { Component, createResource, For, Show, Suspense } from "solid-js"; import { LoadingCircle } from "./LoadingCircle"; -import { base } from "@network/index"; +import { base, getAccessToken } from "@network/index"; import { useNotifications } from "@contexts/Notifications"; export const ProcessingImages: Component = () => { - const notifications = useNotifications(); + const notifications = useNotifications(); - const processingNumber = () => - Object.keys(notifications.state.ProcessingImages).length + - Object.keys(notifications.state.ProcessingLists).length; + const processingNumber = () => + Object.keys(notifications.state.ProcessingImages).length + + Object.keys(notifications.state.ProcessingLists).length; - return ( - - - 0}> -

- Processing {processingNumber()}{" "} - {processingNumber() === 1 ? "item" : "items"} - ... -

-
- } - > - - -
- - - 0} - fallback={

No items to process

} - > - - {([id, _image]) => ( - - {(image) => ( -
- processing -
-

{image().ImageName}

-
- -
- )} -
- )} -
+ const [accessToken] = createResource(getAccessToken) - - {([, _list]) => ( - - {(list) => ( -
-
-

New Stack: {list().Name}

-
- -
- )} -
- )} -
-
-
-
-
- ); + return ( + + + + 0}> +

+ Processing {processingNumber()}{" "} + {processingNumber() === 1 ? "item" : "items"} + ... +

+
+ } + > + + +
+ + + 0} + fallback={

No items to process

} + > + + {([id, _image]) => ( + + {(image) => ( +
+ processing +
+

{image().ImageName}

+
+ +
+ )} +
+ )} +
+ + + {([, _list]) => ( + + {(list) => ( +
+
+

New Stack: {list().Name}

+
+ +
+ )} +
+ )} +
+
+
+
+
+
+ ); }; diff --git a/frontend/src/network/index.ts b/frontend/src/network/index.ts index 3b56068..29ea561 100644 --- a/frontend/src/network/index.ts +++ b/frontend/src/network/index.ts @@ -46,7 +46,7 @@ export const getAccessToken = async (): Promise => { throw new Error("your are not logged in") } - const isValidAccessToken = accessToken != null && getTokenProperties(accessToken).exp.getTime() > Date.now() + const isValidAccessToken = accessToken != null && getTokenProperties(accessToken).exp.getTime() * 1000 > Date.now() if (!isValidAccessToken) { const newAccessToken = await fetch(getBaseRequest({ @@ -129,6 +129,15 @@ export const deleteImageFromStack = async (listID: string, imageID: string): Pro await fetch(request); } +export const deleteList = async (listID: string): Promise => { + const request = await getBaseAuthorizedRequest({ + path: `stacks/${listID}`, + method: "DELETE", + }); + + await fetch(request); +} + export class ImageLimitReached extends Error { constructor() { super(); diff --git a/frontend/src/pages/list/index.tsx b/frontend/src/pages/list/index.tsx index d90402b..0785f47 100644 --- a/frontend/src/pages/list/index.tsx +++ b/frontend/src/pages/list/index.tsx @@ -1,7 +1,14 @@ import { useSearchImageContext } from "@contexts/SearchImageContext"; -import { useParams } from "@solidjs/router"; -import { Component, For, Show, Suspense, createResource, createSignal } from "solid-js"; -import { base, getAccessToken } from "../../network"; +import { useParams, useNavigate } from "@solidjs/router"; +import { + Component, + For, + Show, + Suspense, + createResource, + createSignal, +} from "solid-js"; +import { base, deleteList, getAccessToken } from "../../network"; import { Dialog } from "@kobalte/core"; const DeleteButton: Component<{ onDelete: () => void }> = (props) => { @@ -35,7 +42,10 @@ const DeleteButton: Component<{ onDelete: () => void }> = (props) => { Cancel - @@ -47,8 +57,55 @@ const DeleteButton: Component<{ onDelete: () => void }> = (props) => { ); }; +const DeleteListButton: Component<{ onDelete: () => void }> = (props) => { + const [isOpen, setIsOpen] = createSignal(false); + + return ( + <> + + + + + +
+ + + Confirm Delete List + + + Are you sure you want to delete this entire + list? This action cannot be undone. + +
+ + + + +
+
+
+
+
+ + ); +}; + export const List: Component = () => { const { listId } = useParams(); + const nav = useNavigate(); const { lists, onDeleteImageFromStack } = useSearchImageContext(); @@ -56,12 +113,35 @@ export const List: Component = () => { const list = () => lists().find((l) => l.ID === listId); + const handleDeleteList = async () => { + await deleteList(listId) + nav("/"); + }; + return ( {(l) => (
-
+
+
+
+

+ {l().Name} +

+ +

+ {l().Description} +

+
+
+ +
+
+
@@ -106,14 +186,22 @@ export const List: Component = () => { alt="List item" /> - onDeleteImageFromStack(l().ID, image.ImageID)} /> + + onDeleteImageFromStack( + l().ID, + image.ImageID, + ) + } + /> {(item, colIndex) => (
{ >
{item.Value}
@@ -139,8 +229,8 @@ export const List: Component = () => { No images in this list yet

- Images will appear here once added to the - list + Images will appear here once added to + the list