|
@@ -1,102 +1,72 @@
|
|
|
-import React, { useEffect, useState } from "react";
|
|
|
|
|
|
|
+import React, { useState } from "react";
|
|
|
import styled from "styled-components";
|
|
import styled from "styled-components";
|
|
|
import tag_icon from "assets/tag.png";
|
|
import tag_icon from "assets/tag.png";
|
|
|
import addCircle from "assets/add-circle.png";
|
|
import addCircle from "assets/add-circle.png";
|
|
|
-
|
|
|
|
|
-import api from "shared/api";
|
|
|
|
|
-import Loading from "components/Loading";
|
|
|
|
|
-import { ImageType, TagType, tagValidator } from "./types";
|
|
|
|
|
-import { useQuery } from "@tanstack/react-query";
|
|
|
|
|
|
|
+import { ArtifactType, ImageType } from "./types";
|
|
|
import SearchBar from "components/SearchBar";
|
|
import SearchBar from "components/SearchBar";
|
|
|
-import { z } from "zod";
|
|
|
|
|
|
|
|
|
|
type Props = {
|
|
type Props = {
|
|
|
selectedImage?: ImageType;
|
|
selectedImage?: ImageType;
|
|
|
- projectId: number;
|
|
|
|
|
setSelectedTag: (x: string) => void;
|
|
setSelectedTag: (x: string) => void;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const TagList: React.FC<Props> = ({
|
|
const TagList: React.FC<Props> = ({
|
|
|
selectedImage,
|
|
selectedImage,
|
|
|
- projectId,
|
|
|
|
|
setSelectedTag,
|
|
setSelectedTag,
|
|
|
}) => {
|
|
}) => {
|
|
|
- const [tags, setTags] = useState<TagType[]>([]);
|
|
|
|
|
const [searchFilter, setSearchFilter] = useState<string>("");
|
|
const [searchFilter, setSearchFilter] = useState<string>("");
|
|
|
|
|
|
|
|
- const { data: tagResp, isLoading, error } = useQuery(
|
|
|
|
|
- ["getImageTags", selectedImage],
|
|
|
|
|
- async () => {
|
|
|
|
|
- if (!selectedImage) {
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ const renderTagList = () => {
|
|
|
|
|
+ if (selectedImage == null) {
|
|
|
|
|
+ if (searchFilter) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <TagItem
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ setSelectedTag(searchFilter);
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <img src={addCircle} />
|
|
|
|
|
+ {`Use tag \"${searchFilter}\"`}
|
|
|
|
|
+ </TagItem>
|
|
|
|
|
+ );
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- const res = await api.getImageTags(
|
|
|
|
|
- "<token>",
|
|
|
|
|
- {},
|
|
|
|
|
- {
|
|
|
|
|
- project_id: projectId,
|
|
|
|
|
- registry_id: selectedImage.registry_id,
|
|
|
|
|
- repo_name: selectedImage.name,
|
|
|
|
|
- }
|
|
|
|
|
- );
|
|
|
|
|
- return z.array(tagValidator).parseAsync(res.data);
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- enabled: !!selectedImage && selectedImage.registry_id !== 0,
|
|
|
|
|
- refetchOnWindowFocus: false,
|
|
|
|
|
|
|
+ return <LoadingWrapper>Please specify an tag.</LoadingWrapper>;
|
|
|
}
|
|
}
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- if (tagResp) {
|
|
|
|
|
- setTags(tagResp);
|
|
|
|
|
- }
|
|
|
|
|
- }, [tagResp])
|
|
|
|
|
-
|
|
|
|
|
- const renderTagList = () => {
|
|
|
|
|
- if (isLoading && selectedImage && selectedImage.registry_id !== 0) {
|
|
|
|
|
- return (
|
|
|
|
|
- <LoadingWrapper>
|
|
|
|
|
- <Loading />
|
|
|
|
|
- </LoadingWrapper>
|
|
|
|
|
- );
|
|
|
|
|
- } else if (error) {
|
|
|
|
|
- return <LoadingWrapper>Error loading tags.</LoadingWrapper>;
|
|
|
|
|
- } else if (tags.length === 0 && !searchFilter) {
|
|
|
|
|
- return <LoadingWrapper>Please specify a tag.</LoadingWrapper>;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (selectedImage.artifacts.length === 0 && !searchFilter) {
|
|
|
|
|
+ return <LoadingWrapper>Image has no tags; please specify a different image.</LoadingWrapper>;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const sortedTags = searchFilter
|
|
|
|
|
- ? tags
|
|
|
|
|
- .filter((tag) => tag.tag.toLowerCase().includes(searchFilter.toLowerCase()))
|
|
|
|
|
|
|
+ const sortedArtifacts = searchFilter
|
|
|
|
|
+ ? selectedImage.artifacts
|
|
|
|
|
+ .filter(({ tag }) => tag.toLowerCase().includes(searchFilter.toLowerCase()))
|
|
|
.sort((a, b) => {
|
|
.sort((a, b) => {
|
|
|
const aIndex = a.tag.toLowerCase().indexOf(searchFilter.toLowerCase());
|
|
const aIndex = a.tag.toLowerCase().indexOf(searchFilter.toLowerCase());
|
|
|
const bIndex = b.tag.toLowerCase().indexOf(searchFilter.toLowerCase());
|
|
const bIndex = b.tag.toLowerCase().indexOf(searchFilter.toLowerCase());
|
|
|
return aIndex - bIndex;
|
|
return aIndex - bIndex;
|
|
|
})
|
|
})
|
|
|
- : tags.sort((a, b) => {
|
|
|
|
|
|
|
+ : selectedImage.artifacts.sort((a, b) => {
|
|
|
return (
|
|
return (
|
|
|
- new Date(b.pushed_at ?? "").getTime() -
|
|
|
|
|
- new Date(a.pushed_at ?? "").getTime()
|
|
|
|
|
|
|
+ new Date(b.updated_at ?? "").getTime() -
|
|
|
|
|
+ new Date(a.updated_at ?? "").getTime()
|
|
|
);
|
|
);
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
- const tagCards = sortedTags.map((tag: TagType, i: number) => {
|
|
|
|
|
|
|
+ const tagCards = sortedArtifacts.map((artifact: ArtifactType, i: number) => {
|
|
|
return (
|
|
return (
|
|
|
<TagItem
|
|
<TagItem
|
|
|
key={i}
|
|
key={i}
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
- setSelectedTag(tag.tag);
|
|
|
|
|
|
|
+ setSelectedTag(artifact.tag);
|
|
|
}}
|
|
}}
|
|
|
>
|
|
>
|
|
|
<img src={tag_icon} />
|
|
<img src={tag_icon} />
|
|
|
- {tag.tag}
|
|
|
|
|
|
|
+ {artifact.tag}
|
|
|
</TagItem>
|
|
</TagItem>
|
|
|
);
|
|
);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- if (searchFilter !== "" && !tags.some((tag) => tag.tag === searchFilter)) {
|
|
|
|
|
|
|
+ if (searchFilter !== "" && !sortedArtifacts.some(({ tag }) => tag === searchFilter)) {
|
|
|
tagCards.push(
|
|
tagCards.push(
|
|
|
<TagItem
|
|
<TagItem
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
@@ -116,7 +86,7 @@ const TagList: React.FC<Props> = ({
|
|
|
<>
|
|
<>
|
|
|
<SearchBar
|
|
<SearchBar
|
|
|
setSearchFilter={setSearchFilter}
|
|
setSearchFilter={setSearchFilter}
|
|
|
- disabled={error != null || isLoading}
|
|
|
|
|
|
|
+ disabled={false}
|
|
|
prompt={"Search tags..."}
|
|
prompt={"Search tags..."}
|
|
|
/>
|
|
/>
|
|
|
<ExpandedWrapper>
|
|
<ExpandedWrapper>
|
|
@@ -170,5 +140,4 @@ const LoadingWrapper = styled.div`
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
justify-content: center;
|
|
|
font-size: 13px;
|
|
font-size: 13px;
|
|
|
- color: #ffffff44;
|
|
|
|
|
`;
|
|
`;
|