diff --git a/ui/src/features/assemble-freight/artifact-menu-item.tsx b/ui/src/features/assemble-freight/artifact-menu-item.tsx
index b13004d957..74624ee619 100644
--- a/ui/src/features/assemble-freight/artifact-menu-item.tsx
+++ b/ui/src/features/assemble-freight/artifact-menu-item.tsx
@@ -1,7 +1,13 @@
import classNames from 'classnames';
+import { SubscriptionName } from '@ui/features/common/subscription-name';
+
import { DiscoveryResult } from './types';
-import { getSubscriptionKey, isEqualSubscriptions } from './unique-subscription-key';
+import {
+ getSubscriptionKey,
+ getSubscriptionName,
+ isEqualSubscriptions
+} from './unique-subscription-key';
export interface ArtifactMenuItemProps {
onClick: () => void;
@@ -34,10 +40,16 @@ export const ArtifactMenuItems = ({
{items.map((item) => {
const isSelected = !!selected && isEqualSubscriptions(selected, item);
const key = getSubscriptionKey(item);
+ const subscriptionName = getSubscriptionName(item);
return (
onClick(item)} selected={isSelected}>
{key}
+ {!!subscriptionName && (
+
+
+
+ )}
);
})}
diff --git a/ui/src/features/assemble-freight/unique-subscription-key.ts b/ui/src/features/assemble-freight/unique-subscription-key.ts
index bf77dd82f8..b221605701 100644
--- a/ui/src/features/assemble-freight/unique-subscription-key.ts
+++ b/ui/src/features/assemble-freight/unique-subscription-key.ts
@@ -22,5 +22,8 @@ export const getSubscriptionKeyFreight = (res: Image | Chart | GitCommit) => {
return getSubscriptionKey(res);
};
+export const getSubscriptionName = (res: DiscoveryResult) =>
+ 'subscriptionName' in res ? res.subscriptionName : undefined;
+
export const isEqualSubscriptions = (a: DiscoveryResult, b: DiscoveryResult) =>
getSubscriptionKey(a) === getSubscriptionKey(b);
diff --git a/ui/src/features/common/commit-info.tsx b/ui/src/features/common/commit-info.tsx
index e7b35f8b57..1e12619e85 100644
--- a/ui/src/features/common/commit-info.tsx
+++ b/ui/src/features/common/commit-info.tsx
@@ -6,6 +6,12 @@ export const CommitInfo = ({ commit }: { commit: GitCommit }) => (
+ {commit.subscriptionName && (
+ <>
+ Subscription:
+ {commit.subscriptionName}
+ >
+ )}
{commit.branch ? (
<>
Branch:
diff --git a/ui/src/features/common/subscription-name.tsx b/ui/src/features/common/subscription-name.tsx
new file mode 100644
index 0000000000..fb8e6f97b2
--- /dev/null
+++ b/ui/src/features/common/subscription-name.tsx
@@ -0,0 +1,18 @@
+import { Typography } from 'antd';
+import classNames from 'classnames';
+
+export const SubscriptionName = ({ name, className }: { name?: string; className?: string }) => {
+ if (!name) {
+ return null;
+ }
+
+ return (
+
+ {name}
+
+ );
+};
diff --git a/ui/src/features/freight-timeline/freight-content-item.tsx b/ui/src/features/freight-timeline/freight-content-item.tsx
index 6de5f5e671..c8b3d88374 100644
--- a/ui/src/features/freight-timeline/freight-content-item.tsx
+++ b/ui/src/features/freight-timeline/freight-content-item.tsx
@@ -5,6 +5,7 @@ import Link from 'antd/es/typography/Link';
import classNames from 'classnames';
import { useMemo } from 'react';
+import { SubscriptionName } from '../common/subscription-name';
import { TruncateMiddle } from '../common/truncate-middle';
export const FreightContentItem = (props: {
@@ -23,6 +24,8 @@ export const FreightContentItem = (props: {
artifactSource?: string;
// build date of image
artifactBuildDate?: string;
+ // name of the subscription that discovered the artifact, if it has one
+ subscriptionName?: string;
}) => {
const {
horizontal,
@@ -34,9 +37,22 @@ export const FreightContentItem = (props: {
href,
children,
linkClass,
- fullContentVisibility
+ fullContentVisibility,
+ subscriptionName
} = props;
+ // The chips are too cramped to always carry the name, so it rides along in
+ // the tooltip and only becomes a visible tag where there is room for it.
+ const _title = useMemo(() => {
+ if (!subscriptionName) {
+ return title;
+ }
+
+ return title
+ ? `${title} (subscription: ${subscriptionName})`
+ : `subscription: ${subscriptionName}`;
+ }, [title, subscriptionName]);
+
const _children = useMemo(() => {
if (fullContentVisibility) {
return children;
@@ -57,7 +73,7 @@ export const FreightContentItem = (props: {
'bg-gray-200': !dark && horizontal
})}
overlay={overlay}
- title={title}
+ title={_title}
>
{!!icon && (
@@ -107,6 +123,9 @@ export const FreightContentItem = (props: {
{props.artifactBuildDate}
)}
+ {fullContentVisibility && (
+
+ )}
);
diff --git a/ui/src/features/freight-timeline/freight-contents.tsx b/ui/src/features/freight-timeline/freight-contents.tsx
index 4a690dc552..698887e7f2 100644
--- a/ui/src/features/freight-timeline/freight-contents.tsx
+++ b/ui/src/features/freight-timeline/freight-contents.tsx
@@ -38,8 +38,9 @@ export const FreightContents = (props: {
horizontal={horizontal}
linkClass={linkClass}
highlighted={highlighted}
- key={c.id}
+ key={`${c.subscriptionName || ''}:${c.id}`}
overlay={}
+ subscriptionName={c.subscriptionName}
icon={faGitAlt}
href={`${c.repoURL?.replace('.git', '')}/commit/${c.id}`}
fullContentVisibility={props.fullContentVisibility}
@@ -55,8 +56,9 @@ export const FreightContents = (props: {
horizontal={horizontal}
linkClass={linkClass}
highlighted={highlighted}
- key={`${i.repoURL}:${i.tag}`}
+ key={`${i.subscriptionName || ''}:${i.repoURL}:${i.tag}`}
title={`${i.repoURL}:${i.tag}`}
+ subscriptionName={i.subscriptionName}
icon={faDocker}
href={urlForImage(i.repoURL || '')}
fullContentVisibility={props.fullContentVisibility}
@@ -72,8 +74,9 @@ export const FreightContents = (props: {
horizontal={horizontal}
linkClass={linkClass}
highlighted={highlighted}
- key={`${c.repoURL}:${c.version}`}
+ key={`${c.subscriptionName || ''}:${c.repoURL}:${c.version}`}
title={`${c.repoURL}${c.name ? `/${c.name}` : ''}:${c.version}`}
+ subscriptionName={c.subscriptionName}
fullContentVisibility={props.fullContentVisibility}
icon={faAnchor}
>
@@ -84,6 +87,7 @@ export const FreightContents = (props: {
;
+ subscriptionName?: string;
}
| {
type: 'git';
@@ -16,12 +17,14 @@ export type TableSource =
author: string;
committer: string;
tag?: string;
+ subscriptionName?: string;
}
| {
type: 'helm';
repoURL: string;
name: string;
version: string;
+ subscriptionName?: string;
}
| ({
type: 'other';
@@ -35,7 +38,8 @@ export const flattenFreightOrigin = (
type: 'image',
repoURL: image?.repoURL || '',
tag: image?.tag || '',
- annotations: image?.annotations || {}
+ annotations: image?.annotations || {},
+ subscriptionName: image?.subscriptionName
})) || [];
const git: TableSource[] =
@@ -47,7 +51,8 @@ export const flattenFreightOrigin = (
committer: commit?.committer || '',
id: commit?.id || '',
message: commit?.message || '',
- tag: commit?.tag || ''
+ tag: commit?.tag || '',
+ subscriptionName: commit?.subscriptionName
})) || [];
const helm: TableSource[] =
@@ -55,7 +60,8 @@ export const flattenFreightOrigin = (
type: 'helm',
repoURL: chart?.repoURL || '',
name: chart?.name || '',
- version: chart?.version || ''
+ version: chart?.version || '',
+ subscriptionName: chart?.subscriptionName
})) || [];
const other: TableSource[] =
diff --git a/ui/src/features/project/pipelines/freight/freight-table.tsx b/ui/src/features/project/pipelines/freight/freight-table.tsx
index 2fff4ec770..99982f8eda 100644
--- a/ui/src/features/project/pipelines/freight/freight-table.tsx
+++ b/ui/src/features/project/pipelines/freight/freight-table.tsx
@@ -6,6 +6,7 @@ import { Table } from 'antd';
import classNames from 'classnames';
import { useMemo } from 'react';
+import { SubscriptionName } from '@ui/features/common/subscription-name';
import { ArtifactMetadata } from '@ui/features/freight/artifact-metadata';
import { flattenFreightOrigin } from '@ui/features/freight/flatten-freight-origin-utils';
import { Freight } from '@ui/gen/api/v2/models';
@@ -55,12 +56,18 @@ export const FreightTable = (props: FreightTableProps) => {
width: '30%',
render: (_, record) => {
if (record.type === 'other') {
- return record.subscriptionName || '-';
+ return '-';
}
- return record.repoURL;
+ return {record.repoURL};
}
},
+ {
+ title: 'Subscription Name',
+ width: '15%',
+ render: (_, record) =>
+ record.subscriptionName ? : '-'
+ },
{
title: 'Version',
render: (_, record) => {
diff --git a/ui/src/features/project/pipelines/nodes/stage-freight.tsx b/ui/src/features/project/pipelines/nodes/stage-freight.tsx
index 1ae286f9b6..a578aadd55 100644
--- a/ui/src/features/project/pipelines/nodes/stage-freight.tsx
+++ b/ui/src/features/project/pipelines/nodes/stage-freight.tsx
@@ -212,6 +212,9 @@ export const StageFreight = (props: { stage: Stage }) => {
);
};
+const subscriptionTitle = (base: string | undefined, subscriptionName: string | undefined) =>
+ subscriptionName ? `${base} (subscription: ${subscriptionName})` : base;
+
const Artifact = (props: { artifact: string | GitCommit | Chart | Image | ArtifactReference }) => {
if (typeof props.artifact === 'string') {
return (
@@ -221,10 +224,22 @@ const Artifact = (props: { artifact: string | GitCommit | Chart | Image | Artifa
);
}
+ // A generic artifact has no repository to name it, so its subscription name
+ // is all the carousel can show alongside the version.
if (isArtifactGeneric(props.artifact)) {
return (
-
- {props.artifact.version}
+
+
+ {props.artifact.version}
+
+ {!!props.artifact.subscriptionName && (
+ {props.artifact.subscriptionName}
+ )}
+
);
}
@@ -237,7 +252,11 @@ const Artifact = (props: { artifact: string | GitCommit | Chart | Image | Artifa
const url = getGitCommitURL(props.artifact.repoURL || '', props.artifact.id || '');
let TagComponent = (
-
+
{props.artifact.id?.slice(0, 7)}
@@ -273,7 +292,10 @@ const Artifact = (props: { artifact: string | GitCommit | Chart | Image | Artifa
if (isArtifactChart(props.artifact)) {
return (
@@ -297,7 +319,10 @@ const Artifact = (props: { artifact: string | GitCommit | Chart | Image | Artifa
let TagComponent = (
diff --git a/ui/src/features/project/pipelines/nodes/subscription-node.tsx b/ui/src/features/project/pipelines/nodes/subscription-node.tsx
index 9b40ccab67..4874159f20 100644
--- a/ui/src/features/project/pipelines/nodes/subscription-node.tsx
+++ b/ui/src/features/project/pipelines/nodes/subscription-node.tsx
@@ -23,8 +23,9 @@ export const SubscriptionNode = (props: { subscription: RepoSubscription }) => {
props.subscription?.chart?.repoURL ||
props.subscription?.image?.repoURL ||
'';
- const title = humanComprehendableArtifact({ repoURL }) || props.subscription.name;
- const base = artifactBase(repoURL) || repoURL;
+ const name = props.subscription.name;
+ const title = name || humanComprehendableArtifact({ repoURL }) || repoURL;
+ const base = name ? repoURL : artifactBase(repoURL) || repoURL;
const link = artifactURL(repoURL);
return { title, repoURL, base, link };
@@ -47,9 +48,11 @@ export const SubscriptionNode = (props: { subscription: RepoSubscription }) => {
size='small'
className={styles['subscription-node-size']}
title={
-
+
{icon && }
- {title}
+
+ {title}
+
}
variant='borderless'
diff --git a/ui/src/features/project/pipelines/promotion/freight-comparison-table.tsx b/ui/src/features/project/pipelines/promotion/freight-comparison-table.tsx
index 67c6125b44..d4c5d13bd8 100644
--- a/ui/src/features/project/pipelines/promotion/freight-comparison-table.tsx
+++ b/ui/src/features/project/pipelines/promotion/freight-comparison-table.tsx
@@ -2,10 +2,17 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Col, Flex, Row, Space, Table, Tag, theme, Typography } from 'antd';
import { useMemo } from 'react';
+import { SubscriptionName } from '@ui/features/common/subscription-name';
import { ArtifactMetadata } from '@ui/features/freight/artifact-metadata';
import { Freight, FreightReference } from '@ui/gen/api/v2/models';
-import { repoLabel, typeIcon, typeLabel, versionLabel } from './freight-comparison-utils';
+import {
+ repoLabel,
+ subscriptionName,
+ typeIcon,
+ typeLabel,
+ versionLabel
+} from './freight-comparison-utils';
import { PairedRow, pairArtifacts, PairStatus } from './pair-artifacts';
const statusTag = (status: PairStatus) => {
@@ -43,6 +50,11 @@ export const FreightComparisonTable = ({
const hasCurrent = !!currentFreight;
+ const hasSubscriptionNames = useMemo(
+ () => rows.some((row) => !!subscriptionName(row.incoming || row.current)),
+ [rows]
+ );
+
return (
className={className}
@@ -97,7 +109,7 @@ export const FreightComparisonTable = ({
>
title='Repo / Name'
- width='57%'
+ width={hasSubscriptionNames ? '42%' : '57%'}
render={(_, row) => {
const source = row.incoming || row.current;
if (!source) {
@@ -122,6 +134,21 @@ export const FreightComparisonTable = ({
);
}}
/>
+ {hasSubscriptionNames && (
+
+ title='Name'
+ width='15%'
+ render={(_, row) => {
+ const name = subscriptionName(row.incoming || row.current);
+
+ if (!name) {
+ return —;
+ }
+
+ return ;
+ }}
+ />
+ )}
title='Current'
width='15%'
diff --git a/ui/src/features/project/pipelines/promotion/freight-comparison-utils.ts b/ui/src/features/project/pipelines/promotion/freight-comparison-utils.ts
index 7c7d169df7..ffd92641f0 100644
--- a/ui/src/features/project/pipelines/promotion/freight-comparison-utils.ts
+++ b/ui/src/features/project/pipelines/promotion/freight-comparison-utils.ts
@@ -37,6 +37,9 @@ export const repoLabel = (source: TableSource): string => {
return source.repoURL || '-';
};
+export const subscriptionName = (source?: TableSource): string | undefined =>
+ !source || source.type === 'other' ? undefined : source.subscriptionName;
+
export const versionLabel = (source: TableSource): string => {
switch (source.type) {
case 'git':
diff --git a/ui/src/features/project/pipelines/warehouse/repo-subscriptions.tsx b/ui/src/features/project/pipelines/warehouse/repo-subscriptions.tsx
index cef27e5e70..cdff3ef74f 100644
--- a/ui/src/features/project/pipelines/warehouse/repo-subscriptions.tsx
+++ b/ui/src/features/project/pipelines/warehouse/repo-subscriptions.tsx
@@ -29,6 +29,12 @@ export const RepoSubscriptions = ({ subscriptions }: Props) => {
column={1}
style={{ width: '40%', minWidth: 500 }}
>
+ {!!subscription.name && (
+
+ {subscription.name}
+
+ )}
+
{
column={1}
style={{ width: '40%', minWidth: 500 }}
>
+ {!!subscription.name && (
+
+ {subscription.name}
+
+ )}
+
{subscription.git?.repoURL}
@@ -110,6 +122,12 @@ export const RepoSubscriptions = ({ subscriptions }: Props) => {
column={1}
style={{ width: '40%', minWidth: 500 }}
>
+ {!!subscription.name && (
+
+ {subscription.name}
+
+ )}
+
{
column={1}
style={{ width: '40%', minWidth: 500 }}
>
- {subscription.name}
+ {!!subscription.name && (
+ {subscription.name}
+ )}
+
{subscription.subscription.subscriptionType}
diff --git a/ui/src/features/stage/create-warehouse/create-warehouse-wizard.tsx b/ui/src/features/stage/create-warehouse/create-warehouse-wizard.tsx
index 419d427516..a046198177 100644
--- a/ui/src/features/stage/create-warehouse/create-warehouse-wizard.tsx
+++ b/ui/src/features/stage/create-warehouse/create-warehouse-wizard.tsx
@@ -93,15 +93,15 @@ export const CreateWarehouseWizard = (props: CreateWarehouseWizardProps) => {
+ onChange={(subscriptions) => {
setFormState({
...formState,
spec: {
...(formState?.spec || {}),
subscriptions
}
- })
- }
+ });
+ }}
/>
diff --git a/ui/src/features/stage/create-warehouse/subscription-wizard.tsx b/ui/src/features/stage/create-warehouse/subscription-wizard.tsx
index e546a481b3..7404b5723c 100644
--- a/ui/src/features/stage/create-warehouse/subscription-wizard.tsx
+++ b/ui/src/features/stage/create-warehouse/subscription-wizard.tsx
@@ -3,7 +3,7 @@ import { faEye, faTrash, IconDefinition } from '@fortawesome/free-solid-svg-icon
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Form from '@rjsf/antd';
import validator from '@rjsf/validator-ajv8';
-import { Button, Card, Collapse, Modal, Select, Tag, Typography } from 'antd';
+import { Button, Card, Collapse, Input, Modal, Select, Tag, Typography } from 'antd';
import AntdFormLabel from 'antd/es/form/FormItemLabel';
import classNames from 'classnames';
import { JSONSchema7 } from 'json-schema';
@@ -15,6 +15,7 @@ import { FieldTemplate } from '@ui/features/common/form/rjsf/field-template';
import { ObjectFieldTemplate } from '@ui/features/common/form/rjsf/object-field-template';
import { IconSetByKargoTerminology } from '@ui/features/common/icons';
import { ObjectDescription } from '@ui/features/common/object-description';
+import { SubscriptionName } from '@ui/features/common/subscription-name';
import { warehouseCreateFormJSONSchema } from './schema';
@@ -31,6 +32,8 @@ export const SubscriptionWizard = (props: {
subscriptionTypes[2] /* image as default and common subscription */
);
+ const [name, setName] = useState('');
+
return (
<>
@@ -61,6 +64,16 @@ export const SubscriptionWizard = (props: {
value={selectedNewSubscription}
onChange={(newSubscription) => setSelectedNewSubscription(newSubscription)}
/>
+
+
+
setName(e.target.value)}
+ placeholder='Optional'
+ />
+
+ onSubmit={(data) => {
props.onChange([
...props.subscriptions,
{
+ ...(name ? { name } : {}),
[selectedNewSubscription]: data.formData
}
- ])
- }
+ ]);
+ setName('');
+ }}
>
}>
Add Subscription
@@ -116,8 +131,8 @@ SubscriptionWizard.Subscription = (props: {
let icon: IconDefinition | null = null;
// one of git, image or chart
- const subscriptionType = (Object.keys(props.subscription)[0] || '') as
- keyof RepoSubscription | '';
+ const subscriptionType = (Object.keys(props.subscription).filter((k) => k !== 'name')[0] ||
+ '') as keyof RepoSubscription | '';
if (subscriptionType === '') {
return Corrupt Subscription! Please Check YAML;
@@ -166,7 +181,12 @@ SubscriptionWizard.Subscription = (props: {
}
title={subscriptionType}
- description={subscriptionSource}
+ description={
+
+
+ {subscriptionSource}
+
+ }
/>
);