@@ -45,27 +80,43 @@ const ImageTagSelectList = (props: ImageTagSelectListProps) => {
}
/>
-
- {t('availableTags')}
-
-
- {selected ? null :
}
-
-
- {filters.filtered.map((it, index) => (
-
{
- setSelected(it)
- onTagSelected(it)
- }}
- qaLabel={`imageTag-${index}`}
- />
- ))}
+
+
+ {t('availableTags')}
+
+
+
+ {loadingTags ? (
+
+ ) : (
+ <>
+ {selected ? null : }
+
+ {sortedItems.map((it, index) => (
+ {
+ setSelected(it[0])
+ onTagSelected(it[0])
+ }}
+ qaLabel={`imageTag-${index}`}
+ labelTemplate={label => (
+ <>
+ {isTagNewer(index, selectedTagIndex) && (
+
+ )}
+ {label}
+ >
+ )}
+ />
+ ))}
+
+ >
+ )}
)
}
diff --git a/web/crux-ui/src/components/projects/versions/images/tag-sort-toggle.tsx b/web/crux-ui/src/components/projects/versions/images/tag-sort-toggle.tsx
new file mode 100644
index 000000000..1b4ec7ba2
--- /dev/null
+++ b/web/crux-ui/src/components/projects/versions/images/tag-sort-toggle.tsx
@@ -0,0 +1,70 @@
+import clsx from 'clsx'
+import useTranslation from 'next-translate/useTranslation'
+import Image from 'next/image'
+
+export const SORT_MODES = ['alphabetic', 'date'] as const
+export type SortModesEnum = (typeof SORT_MODES)[number]
+
+export type SortState = {
+ mode: SortModesEnum
+ dir: -1 | 1
+}
+
+type TagSortToggleProps = {
+ className?: string
+ state: SortState
+ onStateChange: (state: SortState) => void
+}
+
+const SORT_ICONS: Record
= {
+ alphabetic: {
+ '1': '/sort-alphabetical-asc.svg',
+ '-1': '/sort-alphabetical-desc.svg',
+ },
+ date: {
+ '1': '/sort-date-asc.svg',
+ '-1': '/sort-date-desc.svg',
+ },
+}
+
+const TagSortToggle = (props: TagSortToggleProps) => {
+ const { className, state, onStateChange } = props
+ const { mode, dir } = state
+
+ const { t } = useTranslation('common')
+
+ const onToggleMode = (newMode: SortModesEnum) => {
+ if (mode === newMode) {
+ onStateChange({
+ mode,
+ dir: dir == 1 ? -1 : 1,
+ })
+ } else {
+ onStateChange({
+ mode: newMode,
+ dir,
+ })
+ }
+ }
+
+ return (
+
+ {SORT_MODES.map(it => (
+
onToggleMode(it)}
+ >
+
+
+ ))}
+
+ )
+}
+
+export default TagSortToggle
diff --git a/web/crux-ui/src/components/projects/versions/use-version-state.ts b/web/crux-ui/src/components/projects/versions/use-version-state.ts
index b93c0bc99..679f01c80 100644
--- a/web/crux-ui/src/components/projects/versions/use-version-state.ts
+++ b/web/crux-ui/src/components/projects/versions/use-version-state.ts
@@ -37,6 +37,7 @@ import {
WS_TYPE_PATCH_RECEIVED,
WS_TYPE_REGISTRY_FETCH_IMAGE_TAGS,
WS_TYPE_REGISTRY_IMAGE_TAGS,
+ RegistryImageTag,
} from '@app/models'
import WebSocketClientEndpoint from '@app/websockets/websocket-client-endpoint'
import useTranslation from 'next-translate/useTranslation'
@@ -126,9 +127,15 @@ const refreshImageTags = (registriesSock: WebSocketClientEndpoint, images: Versi
})
}
-export const selectTagsOfImage = (state: VerionState, image: VersionImage): string[] => {
+export const selectTagsOfImage = (state: VerionState, image: VersionImage): Record => {
const regImgTags = state.tags[imageTagKey(image.registry.id, image.name)]
- return regImgTags ? regImgTags.tags : image.tag ? [image.tag] : []
+ return regImgTags
+ ? regImgTags.tags
+ : image.tag
+ ? {
+ [image.tag]: null,
+ }
+ : {}
}
export const useVersionState = (options: VersionStateOptions): [VerionState, VersionActions] => {
diff --git a/web/crux-ui/src/components/projects/versions/version-view-list.tsx b/web/crux-ui/src/components/projects/versions/version-view-list.tsx
index 6a8b19359..446240bb8 100644
--- a/web/crux-ui/src/components/projects/versions/version-view-list.tsx
+++ b/web/crux-ui/src/components/projects/versions/version-view-list.tsx
@@ -50,6 +50,8 @@ const VersionViewList = (props: VersionViewListProps) => {
actions.fetchImageTags(it)
}
+ const imageTags = tagsModalTarget ? selectTagsOfImage(state, tagsModalTarget) : null
+
return (
<>
@@ -144,6 +146,7 @@ const VersionViewList = (props: VersionViewListProps) => {
qaLabel={QA_MODAL_LABEL_IMAGE_TAGS}
>
actions.selectTagForImage(tagsModalTarget, it)}
diff --git a/web/crux-ui/src/elements/dyo-radio-button.tsx b/web/crux-ui/src/elements/dyo-radio-button.tsx
index 954cb4eb8..869d17ea0 100644
--- a/web/crux-ui/src/elements/dyo-radio-button.tsx
+++ b/web/crux-ui/src/elements/dyo-radio-button.tsx
@@ -9,10 +9,11 @@ type DyoRadioButtonProps = {
checked?: boolean
onSelect?: VoidFunction
qaLabel: string
+ labelTemplate?: (label?: string) => React.ReactNode
}
const DyoRadioButton = (props: DyoRadioButtonProps) => {
- const { className, disabled, label, checked, onSelect, qaLabel } = props
+ const { className, disabled, label, checked, onSelect, qaLabel, labelTemplate } = props
const handleCheckedChange = () => {
if (disabled) {
@@ -30,7 +31,7 @@ const DyoRadioButton = (props: DyoRadioButtonProps) => {
handleCheckedChange()} className="hidden" />
-