Skip to content

Commit fd91f7d

Browse files
committed
OCI repos should be supported; Source Icons should be SVG (#8003)
Signed-off-by: Keith Chong <[email protected]>
1 parent 00cbc56 commit fd91f7d

File tree

11 files changed

+210
-58
lines changed

11 files changed

+210
-58
lines changed

src/gitops/Revision/Revision.tsx

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import gitUrlParse, { GitUrl } from 'git-url-parse';
23
import { createRevisionURL } from 'src/gitops/utils/gitops';
34

45
import ExternalLink from '../utils/components/ExternalLink/ExternalLink';
@@ -8,26 +9,86 @@ interface RevisionProps {
89
revision: string;
910
helm: boolean;
1011
revisionExtra?: string;
12+
path?: string;
1113
}
1214

13-
const Revision: React.FC<RevisionProps> = ({ repoURL, revision, helm, revisionExtra }) => {
15+
const Revision: React.FC<RevisionProps> = ({ repoURL, revision, helm, revisionExtra, path }) => {
1416
if (revision) {
17+
const hasPath = path && path !== '.';
18+
let url = revisionUrl(repoURL, revision, hasPath);
19+
if (url !== null && hasPath) {
20+
url += '/' + path;
21+
}
22+
// eslint-disable-next-line no-nested-ternary
23+
const content = isSHA(revision)
24+
? revision.startsWith('sha256:')
25+
? revision.substr(0, 14)
26+
: revision.substr(0, 7)
27+
: revision;
1528
return (
1629
<>
17-
{!helm && (
30+
{!helm && url !== null ? (
1831
<span>
19-
<ExternalLink href={createRevisionURL(repoURL, revision)}>
20-
({revision.substring(0, 7) || ''})
21-
</ExternalLink>
32+
<ExternalLink href={createRevisionURL(repoURL, revision)}>{content}</ExternalLink>
2233
{revisionExtra && revisionExtra}
2334
</span>
35+
) : (
36+
<span>{content}</span>
2437
)}
25-
{helm && <span>({revision.substring(0, 7) || ''})</span>}
2638
</>
2739
);
2840
} else {
2941
return <span>(None)</span>;
3042
}
3143
};
3244

45+
export const isSHA = (revision: string) => {
46+
if (revision.startsWith('sha256:')) {
47+
const hashOnly = revision.replace('sha256:', '');
48+
return hashOnly.match(/^[a-f0-9]{8,69}$/) !== null;
49+
}
50+
// https://stackoverflow.com/questions/468370/a-regex-to-match-a-sha1
51+
return revision.match(/^[a-f0-9]{5,40}$/) !== null;
52+
};
53+
54+
function supportedSource(parsed: GitUrl): boolean {
55+
return (
56+
parsed.resource.startsWith('github') ||
57+
['gitlab.com', 'bitbucket.org'].indexOf(parsed.source) >= 0
58+
);
59+
}
60+
61+
function protocol(proto: string): string {
62+
return proto === 'ssh' ? 'https' : proto;
63+
}
64+
65+
function revisionUrl(url: string, revision: string, forPath: boolean): string {
66+
let parsed;
67+
try {
68+
parsed = gitUrlParse(url);
69+
} catch {
70+
return null;
71+
}
72+
let urlSubPath = isSHA(revision) ? 'commit' : 'tree';
73+
74+
if (url.indexOf('bitbucket') >= 0) {
75+
// The reason for the condition of 'forPath' is that when we build nested path, we need to use 'src'
76+
urlSubPath = isSHA(revision) && !forPath ? 'commits' : 'src';
77+
}
78+
79+
// Gitlab changed the way urls to commit look like
80+
// Ref: https://docs.gitlab.com/ee/update/deprecations.html#legacy-urls-replaced-or-removed
81+
if (parsed.source === 'gitlab.com') {
82+
urlSubPath = '-/' + urlSubPath;
83+
}
84+
85+
if (!supportedSource(parsed)) {
86+
return null;
87+
}
88+
89+
return `${protocol(parsed.protocol)}://${parsed.resource}/${parsed.owner}/${
90+
parsed.name
91+
}/${urlSubPath}/${revision || 'HEAD'}`;
92+
}
93+
3394
export default Revision;

src/gitops/components/application/ApplicationSourcesTab.tsx

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import * as React from 'react';
22
import { RouteComponentProps } from 'react-router';
33
import ExternalLink from 'src/components/utils/ExternalLink/ExternalLink';
44

5-
// import { getReferenceForModel } from 'src/components/utils/useClusterVersion';
65
import { ApplicationKind, ApplicationSource } from '@gitops/models/ApplicationModel';
6+
import { GitIcon } from '@gitops/utils/components/Icons/GitIcon';
7+
import { HelmIcon } from '@gitops/utils/components/Icons/HelmIcon';
8+
import { OciIcon } from '@gitops/utils/components/Icons/OciIcon';
79
import { ArgoServer, getArgoServer } from '@gitops/utils/gitops';
810
import { t } from '@gitops/utils/hooks/useGitOpsTranslation';
911
import { repoUrl, revisionUrl } from '@gitops/utils/urls';
10-
import gitImage from '@images/git.png';
11-
import helmImage from '@images/helm.png';
1212
import { useK8sModel } from '@openshift-console/dynamic-plugin-sdk';
1313
import {
1414
EmptyState,
@@ -23,7 +23,7 @@ import DataViewTable, {
2323
DataViewTh,
2424
DataViewTr,
2525
} from '@patternfly/react-data-view/dist/esm/DataViewTable';
26-
import { CubesIcon } from '@patternfly/react-icons';
26+
import { CubesIcon, GithubIcon } from '@patternfly/react-icons';
2727
import { Tbody, Td, Tr } from '@patternfly/react-table';
2828

2929
import ArgoCDLink from '../shared/ArgoCDLink/ArgoCDLink';
@@ -74,7 +74,7 @@ export const useColumnsDV = () => {
7474
},
7575
},
7676
{
77-
cell: 'Path',
77+
cell: 'Path / Chart',
7878
id: 'path',
7979
props: {
8080
key: 'path',
@@ -92,25 +92,31 @@ export const useColumnsDV = () => {
9292
return columns;
9393
};
9494

95+
function processPath(path: string) {
96+
if (path !== null && path !== undefined) {
97+
if (path === '.') {
98+
return '(root)';
99+
}
100+
return path;
101+
}
102+
return '';
103+
}
104+
95105
export const useRowsDV = (sources: ApplicationSource[]): DataViewTr[] => {
96106
const rows: DataViewTr[] = [];
107+
97108
sources.forEach((source, index) => {
109+
const isOci = source?.repoURL?.startsWith('oci://');
98110
rows.push([
99111
{
100112
id: index + '-type',
101113
cell: (
102-
<Tooltip content={source.chart ? 'Helm' : 'Git'}>
103-
<img
104-
loading="lazy"
105-
src={
106-
source.chart
107-
? helmImage //require('@images/helm.png').default || require('@images/helm.png')
108-
: gitImage //require('@images/git.png').default || require('@images/git.png')
109-
}
110-
alt={source.chart ? 'Helm' : 'Git'}
111-
width="19px"
112-
height="24px"
113-
/>
114+
// eslint-disable-next-line no-nested-ternary
115+
<Tooltip content={source.chart ? 'Helm' : isOci ? 'OCI' : 'Git'}>
116+
<div>
117+
{/* eslint-disable-next-line no-nested-ternary */}
118+
{source.chart ? <HelmIcon /> : isOci ? <OciIcon /> : <GitIcon />}
119+
</div>
114120
</Tooltip>
115121
),
116122
dataLabel: 'Type',
@@ -119,7 +125,17 @@ export const useRowsDV = (sources: ApplicationSource[]): DataViewTr[] => {
119125
id: index + '-repository',
120126
cell: (
121127
<div>
122-
<ExternalLink href={source.repoURL}>{repoUrl(source.repoURL)}</ExternalLink>
128+
{/* eslint-disable-next-line no-nested-ternary */}
129+
{source.chart ? (
130+
<ExternalLink href={source.repoURL}>{source.repoURL}</ExternalLink>
131+
) : isOci ? (
132+
<div>{source.repoURL}</div>
133+
) : (
134+
<ExternalLink href={source.repoURL}>
135+
{source.repoURL.indexOf('github') > 0 && <GithubIcon />}
136+
{repoUrl(source.repoURL)}
137+
</ExternalLink>
138+
)}
123139
</div>
124140
),
125141
dataLabel: 'Repository',
@@ -129,26 +145,32 @@ export const useRowsDV = (sources: ApplicationSource[]): DataViewTr[] => {
129145
cell: <div>{source.targetRevision}</div>,
130146
dataLabel: 'TargetRevision',
131147
},
132-
133148
{
134149
id: index + '-path',
135150
cell: (
136151
<div>
137152
{/* eslint-disable-next-line no-nested-ternary */}
138153
{source.chart ? (
139154
source.chart
140-
) : source.path ? (
141-
<ExternalLink
142-
href={revisionUrl(source.repoURL, source.targetRevision, true) + '/' + source.path}
143-
>
144-
{source.path}
145-
</ExternalLink>
155+
) : // eslint-disable-next-line no-nested-ternary
156+
source.path ? (
157+
!isOci ? (
158+
<ExternalLink
159+
href={
160+
revisionUrl(source.repoURL, source.targetRevision, true) + '/' + source.path
161+
}
162+
>
163+
{source.path}
164+
</ExternalLink>
165+
) : (
166+
<div>{processPath(source.path)}</div>
167+
)
146168
) : (
147169
'-'
148170
)}
149171
</div>
150172
),
151-
dataLabel: 'Path',
173+
dataLabel: 'Chart / Path',
152174
},
153175
{
154176
id: index + '-ref',

src/gitops/components/application/History/History.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ const useRowsDV = (history: ApplicationHistory[], app: ApplicationKind): DataVie
132132
? 'Automated'
133133
: '' + (initBy.username ? initBy.username : '-');
134134

135+
const isOci = obj.source?.repoURL?.startsWith('oci://');
135136
let revisionValue = <>-</>;
136137
if (obj.revision) {
137138
revisionValue = (
@@ -141,8 +142,19 @@ const useRowsDV = (history: ApplicationHistory[], app: ApplicationKind): DataVie
141142
repoURL={obj.source.repoURL || ''}
142143
helm={obj.source.helm ? true : false}
143144
/>
144-
{' , '}
145-
<ExternalLink href={obj.source.repoURL}>{repoUrl(obj.source.repoURL)}</ExternalLink>
145+
{!isOci ? (
146+
<span style={{ marginLeft: '5px' }}>
147+
{'('}
148+
<ExternalLink href={obj.source.repoURL}>{repoUrl(obj.source.repoURL)}</ExternalLink>
149+
{')'}
150+
</span>
151+
) : (
152+
<span style={{ marginLeft: '5px' }}>
153+
{'('}
154+
{obj.source.repoURL}
155+
{')'}
156+
</span>
157+
)}
146158
</>
147159
);
148160
} else if (obj.revisions && app.spec.sources) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as React from 'react';
2+
3+
export const GitIcon: React.FC<{ className?: string; style?: React.CSSProperties }> = ({
4+
className,
5+
style,
6+
}) => (
7+
<svg
8+
className={className}
9+
style={style}
10+
xmlns="http://www.w3.org/2000/svg"
11+
viewBox="0 0 512 512"
12+
width="24px"
13+
height="24px"
14+
>
15+
<g transform="matrix(1 0 0 -1 0 512)">
16+
<path
17+
fill="currentColor"
18+
d="M479 286l-193 193q-13 13 -30 13t-30 -13l-38 -38l47 -47q28 15 50 -7t6 -49l47 -47q27 16 49 -6q12 -12 12 -29t-12 -29t-29 -12t-29 12q-21 23 -6 50l-46 46q-5 -3 -11 -4v-126q14 -3 22.5 -14t8.5 -25q0 -17 -12 -29t-29 -12t-29 12t-12 29q0 14 8.5 25t22.5 14v126
19+
q-13 4 -19 10q-21 23 -6 50l-48 47l-140 -140q-13 -13 -13 -30t13 -30l193 -193q13 -13 30 -13t30 13l193 193q13 13 13 30t-13 30z"
20+
/>
21+
</g>
22+
</svg>
23+
);
24+
25+
export default GitIcon;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import * as React from 'react';
2+
3+
export const HelmIcon: React.FC<{ className?: string; style?: React.CSSProperties }> = ({
4+
className,
5+
style,
6+
}) => (
7+
<svg
8+
className={className}
9+
style={style}
10+
viewBox="0 0 500 500"
11+
xmlns="http://www.w3.org/2000/svg"
12+
width="24px"
13+
height="24px"
14+
>
15+
<path
16+
fill="currentColor"
17+
d="m254.28 303.41c-0.50074-2.8223-0.39948-103.6 0.0975-105.52h27.162v77.765c1.1717 0.0608 2.0912 0.14921 3.0108 0.15005q16.128 0.0147 32.256 7e-3h2.9073v27.596zm-96.707-0.04025v-105.17c1.617-0.52913 61.545-0.73586 65.462-0.20457v22.414c-0.87869 0.063-1.7857 0.18341-2.6928 0.18454q-16.009 0.0199-32.017 9e-3h-2.9677v17.434h33.347v23.192h-33.048c-0.55339 1.9851-0.70531 15.817-0.25622 19.646 0.84488 0.0568 1.75 0.16952 2.6553 0.17059q16.009 0.0186 32.017 8e-3h2.9694v22.321zm-59.941-105.49h27.263c0.55054 1.7525 0.65821 102.97 0.0947 105.52h-27.288c-0.15021-6.7034-0.04736-13.384-0.06622-20.061-0.01871-6.6226-0.0041-13.245-0.0041-20.04h-33.788v39.741c-2.0595 0.61518-25.334 0.67417-27.648 0.123v-105.28h27.538v37.189c1.9679 0.56844 30.923 0.67339 33.872 0.12942 0.0082-2.9771 0.02-6.0265 0.024-9.0758q0.0063-4.7433 9.4e-4 -9.4866 0-4.625 0-9.25c1e-5 -3.0784 0-6.1567 0-9.5178zm253.1-0.12062c2.7871 0 5.4704 0.18919 8.1149-0.0501 2.9951-0.271 5.139 0.8001 7.3235 2.8131 12.613 11.622 25.357 23.101 38.059 34.627 0.63855 0.57948 1.2904 1.1443 2.1101 1.8701 0.76445-0.65718 1.4812-1.2432 2.1648-1.8655q19.639-17.877 39.248-35.787a5.4477 5.4477 0 0 1 4.2036-1.6458c3.2189 0.13038 6.4467 0.0375 9.8412 0.0375v105.37c-1.7231 0.50368-24.876 0.60366-27.639 0.0611v-53.362l-0.53656-0.25427c-9.0108 8.2178-18.022 16.436-27.238 24.841-9.2258-8.3112-18.342-16.523-27.458-24.736l-0.52449 0.19192c-0.023 4.4536-8e-3 8.9083-0.0105 13.362q-4e-3 6.6394-5.8e-4 13.279v26.872h-27.428c-0.51411-1.773-0.75283-99.662-0.22996-105.62zm43.794 150.15a176.64 176.64 0 0 1-23.973 27.163c0.70941 0.59068 1.2859 1.0704 1.8621 1.5506a108.31 108.31 0 0 1 33.683 48.146 34.618 34.618 0 0 1 2.202 14.42 14.885 14.885 0 0 1-0.74786 3.6921 7.2076 7.2076 0 0 1-8.1579 5.0231 22.233 22.233 0 0 1-6.7628-2.0063 51.232 51.232 0 0 1-9.1815-5.8151 107.59 107.59 0 0 1-32.936-46.707c-0.18746-0.51334-0.39218-1.0204-0.72243-1.8769a194.65 194.65 0 0 1-25.012 14.008 181.67 181.67 0 0 1-26.687 9.7244 187.56 187.56 0 0 1-28.304 5.388c0.16807 0.84015 0.26446 1.5098 0.43745 2.1591a109.17 109.17 0 0 1 2.9708 36.443 80.804 80.804 0 0 1-4.4229 22.477 78.25 78.25 0 0 1-4.1648 8.7447 13.39 13.39 0 0 1-2.3386 2.9708c-3.9801 4.109-8.7322 4.144-12.612-0.0737a27.28 27.28 0 0 1-3.907-5.6178c-3.0768-5.7757-4.6604-12.056-5.791-18.46a116.86 116.86 0 0 1-1.3589-26.465 94.48 94.48 0 0 1 2.8847-19.185c0.14009-0.53269 0.268-1.0696 0.37134-1.6103 0.0263-0.13754-0.0634-0.2973-0.17067-0.73825a176.12 176.12 0 0 1-80.969-24.994c-0.40992 0.90921-0.76206 1.6747-1.1017 2.4458a110.48 110.48 0 0 1-30.901 41.42 38.161 38.161 0 0 1-12.047 6.9591 12.09 12.09 0 0 1-6.5152 0.70023 7.1186 7.1186 0 0 1-5.4033-4.4892c-1.4161-3.424-1.1653-6.985-0.68438-10.517a55.453 55.453 0 0 1 4.3077-14.25 112.5 112.5 0 0 1 26.511-37.763c0.459-0.43461 0.92981-0.857 1.3809-1.2995a3.7603 3.7603 0 0 0 0.36534-0.65529 178.9 178.9 0 0 1-28.469-31.317c0.98458-0.0802 1.6433-0.18 2.302-0.1806 10.514-0.01 21.029 0.0274 31.543-0.0436a4.7055 4.7055 0 0 1 3.7034 1.6262 146.95 146.95 0 0 0 39.403 28.885 139.95 139.95 0 0 0 49.704 14.774q70.68 6.8707 121.6-42.855a7.6457 7.6457 0 0 1 5.9926-2.4435c9.8014 0.12121 19.605 0.0499 29.408 0.0499h2.5335zm-258-226.78c-0.572-0.54252-1.1946-1.1264-1.81-1.7176-12.617-12.121-22.381-26.136-28.279-42.702-1.6507-4.6364-2.8969-9.3652-2.6759-14.359 0.021-0.4739 0.0196-0.94915 0.0523-1.4221 0.445-6.4459 4.7591-9.7032 11.058-8.1767a27.325 27.325 0 0 1 5.7315 2.1965c6.8902 3.4554 12.506 8.5636 17.671 14.166a112.53 112.53 0 0 1 21.722 33.43 8.2964 8.2964 0 0 0 0.38946 0.861c0.0712 0.12855 0.22232 0.21282 0.55927 0.51883a176.36 176.36 0 0 1 81.02-24.861c-0.17651-0.8761-0.28195-1.5457-0.44772-2.2a112.49 112.49 0 0 1-2.6529-36.956 84.075 84.075 0 0 1 4.4444-21.764 31.326 31.326 0 0 1 5.4765-10.171 15.687 15.687 0 0 1 3.1634-2.8215 7.026 7.026 0 0 1 8.0326-0.056 17.279 17.279 0 0 1 5.8402 6.7318 53.054 53.054 0 0 1 5.2622 14.677 112.5 112.5 0 0 1 2.1226 33.004 95.598 95.598 0 0 1-3.4905 19.911c7.1217 1.3119 14.21 2.3287 21.147 3.9771a186.38 186.38 0 0 1 20.441 6.0033 188.32 188.32 0 0 1 19.77 8.5693c6.3454 3.1643 12.386 6.9407 18.718 10.538 0.20571-0.433 0.50439-0.94982 0.706-1.5021a108.66 108.66 0 0 1 32.901-46.762 37.758 37.758 0 0 1 11.822-6.883 17.246 17.246 0 0 1 3.6783-0.84512c6.264-0.71729 8.8935 3.2244 9.3565 7.9318a29.944 29.944 0 0 1-0.77381 10.355 87.906 87.906 0 0 1-10.73 24.688c-6.7902 10.972-14.85 20.855-25.093 28.83-0.30234 0.2354-0.56784 0.51814-1.0799 0.99029a177.78 177.78 0 0 1 26.593 30.882 10.962 10.962 0 0 1-1.689 0.29762c-10.595 0.015-21.191-0.0183-31.786 0.0461a4.004 4.004 0 0 1-3.1725-1.69 147.88 147.88 0 0 0-88.178-46.548 143.36 143.36 0 0 0-30.28-1.1692 146.41 146.41 0 0 0-82.537 31.811 140.07 140.07 0 0 0-16.976 15.842 4.7284 4.7284 0 0 1-3.8633 1.7574c-10.121-0.0703-20.242-0.035-30.363-0.0349h-2.1521c0.618-2.408 6.8403-10.938 13.884-18.553 5.2525-5.6788 10.817-11.069 16.468-16.818z"
18+
/>
19+
</svg>
20+
);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as React from 'react';
2+
3+
export const OciIcon: React.FC<{ className?: string; style?: React.CSSProperties }> = ({
4+
className,
5+
style,
6+
}) => (
7+
<svg
8+
className={className}
9+
style={style}
10+
viewBox="0 0 580 580"
11+
width="24px"
12+
height="24px"
13+
xmlns="http://www.w3.org/2000/svg"
14+
>
15+
<g>
16+
<g>
17+
<g>
18+
<polygon
19+
fill="#808184"
20+
points="326.6,212.6 326.6,132.6 128.6,132.6 128.6,444.6 326.6,444.6 326.6,364.6 208.6,364.6 208.6,212.6"
21+
/>
22+
<g>
23+
<rect x="366.5" y="132.6" fill="currentColor" width="79.9" height="79.9" />
24+
<rect x="366.5" y="252.6" fill="currentColor" width="79.9" height="192" />
25+
</g>
26+
</g>
27+
<path
28+
fill="currentColor"
29+
d="M8.5,9.5v558.2h558.2V9.5H8.5z M486.4,484.7H88.7V92.6h397.8V484.7z"
30+
/>
31+
</g>
32+
</g>
33+
</svg>
34+
);
35+
36+
export default OciIcon;

src/gitops/utils/gitops.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,6 @@ export function getFriendlyClusterName(cluster: string) {
4141
}
4242
}
4343

44-
export function getIconForSourceType(sourceType: string) {
45-
switch (sourceType) {
46-
case 'Helm': {
47-
return '../../../../images/helm.png';
48-
}
49-
case 'Kustomize': {
50-
return '../../../../images/kustomize.png';
51-
}
52-
default: {
53-
return '../../../../images/git.png';
54-
}
55-
}
56-
}
57-
5844
export function getDuration(startAt: string, finishAt: string) {
5945
try {
6046
const start: Date = new Date(startAt);

src/images/git.png

-2.33 KB
Binary file not shown.

src/images/git.svg

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/images/helm.png

-8.6 KB
Binary file not shown.

0 commit comments

Comments
 (0)