Skip to content

Commit

Permalink
full urdf uploading (#299)
Browse files Browse the repository at this point in the history
* full urdf uploading

* more changes

* more fixes

* working, mostly

* fix lint

* fix tests
  • Loading branch information
codekansas authored Aug 19, 2024
1 parent b7dd924 commit 206d006
Show file tree
Hide file tree
Showing 30 changed files with 1,239 additions and 454 deletions.
7 changes: 6 additions & 1 deletion frontend/src/components/footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const Footer = () => {
return (
<footer className="bg-gray-50 dark:bg-gray-800 text-sm py-20">
<div className="flex flex-col gap-4 mx-12 sm:mx-36">
{/* Logo and Social Links */}
<div className="flex flex-row justify-between items-center">
<span className="text-xl sm:text-2xl">K-Scale Store</span>
<div className="flex flex-row gap-4 rounded-full">
Expand Down Expand Up @@ -56,7 +57,9 @@ const Footer = () => {
</SocialLink>
</div>
</div>
<div className="flex flex-row gap-32 sm:gap-56 md:gap-64">

{/* Footer Links */}
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
<div className="flex flex-col items-start gap-2 sm:gap-3">
<h2 className="text-base sm:text-lg font-semibold mb-1">Company</h2>
<a
Expand Down Expand Up @@ -93,6 +96,8 @@ const Footer = () => {
</a>
</div>
</div>

{/* Copy Right */}
<div className="mt-10 text-xs">
<p>
<span>©</span> {new Date().getFullYear()} K-Scale Labs
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/components/listing/FileUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,7 @@ export const FileUploader = forwardRef<
const [isFileTooBig, setIsFileTooBig] = useState(false);
const [activeIndex, setActiveIndex] = useState(-1);
const {
accept = {
"image/*": [".jpg", ".jpeg", ".png", ".gif", ".webp"],
"application/xml": [".urdf"],
},
accept,
maxSize = 4 * 1024 * 1024,
multiple = true,
} = dropzoneOptions;
Expand Down
17 changes: 8 additions & 9 deletions frontend/src/components/listing/ListingBody.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { paths } from "gen/api";

import ListingArtifacts from "./ListingArtifacts";
import ListingChildren from "./ListingChildren";
import ListingDescription from "./ListingDescription";
import ListingArtifacts from "components/listing/ListingArtifacts";
import ListingChildren from "components/listing/ListingChildren";
import ListingDescription from "components/listing/ListingDescription";
import ListingUrdf from "components/listing/ListingUrdf";

type ListingResponse =
paths["/listings/{id}"]["get"]["responses"][200]["content"]["application/json"];
Expand All @@ -18,13 +19,11 @@ const ListingBody = (props: ListingBodyProps) => {
<ListingDescription
listingId={listing.id}
description={listing.description}
edit={listing.owner_is_user}
edit={listing.can_edit}
/>
<ListingChildren
child_ids={listing.child_ids}
edit={listing.owner_is_user}
/>
<ListingArtifacts listingId={listing.id} edit={listing.owner_is_user} />
<ListingChildren child_ids={listing.child_ids} edit={listing.can_edit} />
<ListingUrdf listingId={listing.id} edit={listing.can_edit} />
<ListingArtifacts listingId={listing.id} edit={listing.can_edit} />
</div>
);
};
Expand Down
32 changes: 15 additions & 17 deletions frontend/src/components/listing/ListingFileUpload.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useCallback, useState } from "react";
import { DropzoneOptions } from "react-dropzone";

import { components } from "gen/api";
import { useAlertQueue } from "hooks/useAlertQueue";
Expand All @@ -15,16 +16,14 @@ import {
import Spinner from "components/ui/Spinner";

interface Props {
accept: {
[key: string]: string[];
};
maxSize: number;
description: string;
listingId: string;
dropzoneOptions: DropzoneOptions;
onUpload: (artifact: components["schemas"]["UploadArtifactResponse"]) => void;
}

const ListingFileUpload = (props: Props) => {
const { accept, maxSize, listingId, onUpload } = props;
const { description, listingId, dropzoneOptions, onUpload } = props;

const { addErrorAlert } = useAlertQueue();
const auth = useAuthentication();
Expand All @@ -39,9 +38,7 @@ const ListingFileUpload = (props: Props) => {

setUploading(true);
(async () => {
const { data, error } = await auth.api.upload(files, {
listing_id: listingId,
});
const { data, error } = await auth.api.upload(files, listingId);

if (error) {
addErrorAlert(error);
Expand All @@ -53,7 +50,9 @@ const ListingFileUpload = (props: Props) => {
})();
}, [files, auth, listingId, addErrorAlert]);

const fileExtensions = Object.values(accept).flat();
const fileExtensions = dropzoneOptions.accept
? Object.values(dropzoneOptions.accept).flat()
: undefined;

return uploading ? (
<div className="w-full flex justify-center mt-4">
Expand All @@ -63,19 +62,18 @@ const ListingFileUpload = (props: Props) => {
<FileUploader
value={files}
onValueChange={setFiles}
dropzoneOptions={{
accept,
maxSize,
}}
dropzoneOptions={dropzoneOptions}
className="relative bg-background mt-4 rounded-lg"
>
<FileInput>
<div className="flex justify-center w-full h-32">
<div className="align-middle h-full justify-center flex flex-col">
<div className="text-center">Drag and drop or click to browse</div>
<div className="text-center">
File extensions: {fileExtensions.join(", ")}
</div>
<div className="text-center">{description}</div>
{fileExtensions && (
<div className="text-center">
File extensions: {fileExtensions.join(", ")}
</div>
)}
</div>
</div>
</FileInput>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/listing/ListingFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface Props {

const ListingFooter = ({ listingId, edit }: Props) => {
return (
<div className="relative border-t p-4">
<div className="relative p-4">
<div className="grid grid-cols-1 md:grid-cols-[1fr_auto] gap-4 items-center">
<div className="text-gray-600 dark:text-gray-300 italic text-sm">
{`Listing ID: ${listingId}`}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/listing/ListingHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ const CloseButton = () => {

const ListingHeader = (props: Props) => {
return (
<div className="relative border-b p-4 mb-4">
<div className="relative p-4 mb-4">
<div className="grid grid-cols-1 md:grid-cols-[1fr_auto] gap-4">
<ListingTitle {...props} />
<CloseButton />
Expand Down
107 changes: 45 additions & 62 deletions frontend/src/components/listing/ListingImages.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from "react";
import { FaCaretSquareDown, FaCaretSquareUp, FaTimes } from "react-icons/fa";
import { FaTimes } from "react-icons/fa";

import { components } from "gen/api";
import { useAlertQueue } from "hooks/useAlertQueue";
Expand Down Expand Up @@ -27,7 +27,6 @@ const ListingImages = (props: Props) => {
allArtifacts.filter((a) => a.artifact_type === "image"),
);
const [deletingIds, setDeletingIds] = useState<string[]>([]);
const [collapsed, setCollapsed] = useState<boolean>(true);

const [showImageModal, setShowImageModal] = useState<number | null>(null);

Expand Down Expand Up @@ -55,65 +54,46 @@ const ListingImages = (props: Props) => {
<div className="flex flex-col items-center justify-center relative">
{images.length > 0 ? (
<>
<Button
onClick={() => setCollapsed(!collapsed)}
variant="primary"
className="text-md p-4 w-full"
>
{collapsed ? (
<FaCaretSquareUp className="mr-2" />
) : (
<FaCaretSquareDown className="mr-2" />
)}
Images
</Button>
{!collapsed && (
<>
<div className="grid gap-2 md:gap-4 mx-auto w-full grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 mt-4">
{images.map((image, idx) => (
<div
key={image.artifact_id}
className="bg-background relative p"
<div className="grid gap-2 md:gap-4 mx-auto w-full grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 mt-4">
{images.map((image, idx) => (
<div key={image.artifact_id} className="bg-background relative p">
<div className="bg-white rounded-lg w-full">
<img
src={image.urls.small ?? image.urls.large}
alt={image.name}
className="aspect-square cursor-pointer rounded-lg w-full"
onClick={() => setShowImageModal(idx)}
/>
</div>
{edit && (
<Button
onClick={() => onDelete(image.artifact_id)}
variant="destructive"
className="absolute top-2 right-2 rounded-full"
disabled={deletingIds.includes(image.artifact_id)}
>
<div className="bg-white rounded-lg w-full">
<img
src={image.url}
alt={image.name}
className="aspect-square cursor-pointer rounded-lg"
onClick={() => setShowImageModal(idx)}
/>
</div>
{edit && (
<Button
onClick={() => onDelete(image.artifact_id)}
variant="destructive"
className="absolute top-2 right-2 rounded-full"
disabled={deletingIds.includes(image.artifact_id)}
>
<FaTimes />
</Button>
)}
</div>
))}
<FaTimes />
</Button>
)}
</div>
{showImageModal !== null && (
<div
className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
onClick={() => setShowImageModal(null)}
>
<div
className="absolute bg-white rounded-lg p-4 max-w-4xl max-h-4xl m-4"
onClick={(e) => e.stopPropagation()}
>
<img
src={images[showImageModal].url}
alt={images[showImageModal].name}
className="max-h-full max-w-full"
/>
</div>
</div>
)}
</>
))}
</div>
{showImageModal !== null && (
<div
className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"
onClick={() => setShowImageModal(null)}
>
<div
className="absolute bg-white rounded-lg p-4 max-w-4xl max-h-4xl m-4"
onClick={(e) => e.stopPropagation()}
>
<img
src={images[showImageModal].urls.large}
alt={images[showImageModal].name}
className="max-h-full max-w-full"
/>
</div>
</div>
)}
</>
) : (
Expand All @@ -123,10 +103,13 @@ const ListingImages = (props: Props) => {
)}
{edit && (
<ListingFileUpload
accept={{
"image/*": [".jpg", ".jpeg", ".png", ".webp"],
description="Upload images"
dropzoneOptions={{
accept: {
"image/*": [".jpg", ".jpeg", ".png", ".webp"],
},
maxSize: 4 * 1024 * 1024,
}}
maxSize={4 * 1024 * 1024}
listingId={listingId}
onUpload={(artifact) => {
setImages([
Expand Down
23 changes: 12 additions & 11 deletions frontend/src/components/listing/ListingMeshes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import MeshRenderer from "components/listing/MeshRenderer";
import { Button } from "components/ui/Button/Button";
import { Tooltip } from "components/ui/ToolTip";

type MeshType = "stl" | "urdf";
type MeshType = "obj";
type AllArtifactsType =
components["schemas"]["ListArtifactsResponse"]["artifacts"];
type ArtifactType = AllArtifactsType[0];
Expand All @@ -25,8 +25,7 @@ interface Props {

const getMeshType = (artifactType: ArtifactType["artifact_type"]): MeshType => {
switch (artifactType) {
case "stl":
case "urdf":
case "obj":
return artifactType;
default:
throw new Error(`Unknown artifact type: ${artifactType}`);
Expand All @@ -40,9 +39,7 @@ const ListingMeshes = (props: Props) => {
const { addErrorAlert } = useAlertQueue();

const [meshes, setMeshes] = useState<AllArtifactsType>(
allArtifacts
.filter((a) => ["stl", "urdf"].includes(a.artifact_type))
.sort((a) => (a.artifact_type === "urdf" ? -1 : 1)),
allArtifacts.filter((a) => ["obj"].includes(a.artifact_type)),
);
const [mesh, setMesh] = useState<MeshAndArtifactType | null>(null);
const [deletingIds, setDeletingIds] = useState<string[]>([]);
Expand Down Expand Up @@ -131,7 +128,7 @@ const ListingMeshes = (props: Props) => {
))}
</div>
<MeshRenderer
url={mesh[1].url}
url={mesh[1].urls.large}
name={mesh[1].name}
kind={mesh[0]}
edit={edit}
Expand All @@ -148,11 +145,15 @@ const ListingMeshes = (props: Props) => {
)}
{edit && (
<ListingFileUpload
accept={{
"application/sla": [".stl"],
"application/xml": [".urdf"],
description="Upload meshes"
dropzoneOptions={{
accept: {
"application/sla": [".stl"],
"application/octet-stream": [".obj"],
"model/vnd.collada+xml": [".dae"],
},
maxSize: 4 * 1024 * 1024,
}}
maxSize={4 * 1024 * 1024}
listingId={listingId}
onUpload={(artifact) => {
setMeshes([
Expand Down
Loading

0 comments on commit 206d006

Please sign in to comment.