Skip to content

Commit 006b666

Browse files
committed
feat: intergrated graphql for reservoir
1 parent 364a7f4 commit 006b666

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+3301
-1656
lines changed

data/schema.graphql

Lines changed: 395 additions & 7 deletions
Large diffs are not rendered by default.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Button } from 'antd';
2+
import { ArrowLeft } from 'lucide-react';
3+
import { NavigateOptions, To, useNavigate } from 'react-router-dom';
4+
5+
export interface BAIBackButtonProps {
6+
to: To;
7+
options?: NavigateOptions;
8+
}
9+
10+
const BAIBackButton = ({ to, options }: BAIBackButtonProps) => {
11+
const navigate = useNavigate();
12+
return (
13+
<Button
14+
type="text"
15+
icon={<ArrowLeft size={18} />}
16+
onClick={() => navigate(to, options)}
17+
/>
18+
);
19+
};
20+
21+
export default BAIBackButton;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Typography } from 'antd';
2+
import { createStyles } from 'antd-style';
3+
import { isUndefined } from 'lodash';
4+
import React from 'react';
5+
import { Link, LinkProps } from 'react-router-dom';
6+
7+
const useStyles = createStyles(({ css, token }) => ({
8+
hover: css`
9+
text-decoration: none;
10+
/* color: ${token.colorLink}; */
11+
12+
&:hover {
13+
/* color: ${token.colorLinkHover}; */
14+
text-decoration: underline;
15+
}
16+
`,
17+
disabled: css`
18+
color: ${token.colorTextDisabled};
19+
cursor: not-allowed;
20+
pointer-events: none;
21+
`,
22+
}));
23+
24+
export interface BAILinkProps extends Omit<LinkProps, 'to'> {
25+
type?: 'hover' | 'disabled' | undefined;
26+
to?: LinkProps['to'];
27+
}
28+
const BAILink: React.FC<BAILinkProps> = ({ type, to, ...linkProps }) => {
29+
const { styles } = useStyles();
30+
return type !== 'disabled' && to ? (
31+
<Link
32+
className={isUndefined(type) ? undefined : styles?.[type] || undefined}
33+
to={to}
34+
{...linkProps}
35+
/>
36+
) : (
37+
<Typography.Link
38+
className={isUndefined(type) ? undefined : styles?.[type] || undefined}
39+
onClick={linkProps.onClick}
40+
disabled={type === 'disabled'}
41+
{...linkProps}
42+
/>
43+
);
44+
};
45+
46+
export default BAILink;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { ConfigProvider, Tag, theme } from 'antd';
2+
import { TagProps } from 'antd/lib/tag';
3+
import React from 'react';
4+
5+
interface BAITagProps extends TagProps {}
6+
7+
const BAITag: React.FC<BAITagProps> = ({ ...tagProps }) => {
8+
const { token } = theme.useToken();
9+
return (
10+
<ConfigProvider
11+
theme={{
12+
components: {
13+
Tag: {
14+
borderRadiusSM: 11,
15+
colorText: '#999999',
16+
defaultBg: 'transparent',
17+
colorInfoBg: 'transparent',
18+
colorWarningBg: 'transparent',
19+
colorErrorBg: 'transparent',
20+
colorSuccessBg: 'transparent',
21+
},
22+
},
23+
}}
24+
>
25+
<Tag
26+
style={{ paddingLeft: token.paddingSM, paddingRight: token.paddingSM }}
27+
{...tagProps}
28+
/>
29+
</ConfigProvider>
30+
);
31+
};
32+
33+
export default BAITag;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Typography } from 'antd';
2+
import type { TextProps as AntdTextProps } from 'antd/es/typography/Text';
3+
import React from 'react';
4+
5+
export interface BAITextProps extends AntdTextProps {
6+
monospace?: boolean;
7+
}
8+
9+
const BAIText: React.FC<BAITextProps> = ({
10+
type,
11+
style,
12+
monospace,
13+
children,
14+
...restProps
15+
}) => {
16+
// If monospace prop is true, apply monospace font styling
17+
if (monospace) {
18+
return (
19+
<Typography.Text
20+
type={type}
21+
{...restProps}
22+
style={{
23+
fontFamily: 'monospace',
24+
...style,
25+
}}
26+
>
27+
{children}
28+
</Typography.Text>
29+
);
30+
}
31+
32+
// For non-monospace text, pass all props directly to antd Text
33+
return (
34+
<Typography.Text type={type} style={style} {...restProps}>
35+
{children}
36+
</Typography.Text>
37+
);
38+
};
39+
40+
export default BAIText;
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import {
2+
BAIArtifactRevisionTableArtifactRevisionFragment$data,
3+
BAIArtifactRevisionTableArtifactRevisionFragment$key,
4+
} from '../../__generated__/BAIArtifactRevisionTableArtifactRevisionFragment.graphql';
5+
import { BAIArtifactRevisionTableLatestRevisionFragment$key } from '../../__generated__/BAIArtifactRevisionTableLatestRevisionFragment.graphql';
6+
import { convertToDecimalUnit, filterOutEmpty } from '../../helper';
7+
import BAIFlex from '../BAIFlex';
8+
import BAITag from '../BAITag';
9+
import BAIText from '../BAIText';
10+
import { BAIColumnsType, BAITable, BAITableProps } from '../Table';
11+
import { Button, Tag } from 'antd';
12+
import dayjs from 'dayjs';
13+
import relativeTime from 'dayjs/plugin/relativeTime';
14+
import { Download } from 'lucide-react';
15+
import { useTranslation } from 'react-i18next';
16+
import { graphql, useFragment } from 'react-relay';
17+
18+
dayjs.extend(relativeTime);
19+
20+
export type ArtifactRevision = NonNullable<
21+
NonNullable<BAIArtifactRevisionTableArtifactRevisionFragment$data>[number]
22+
>;
23+
24+
export interface BAIArtifactRevisionTableProps
25+
extends Omit<
26+
BAITableProps<ArtifactRevision>,
27+
'dataSource' | 'columns' | 'rowKey'
28+
> {
29+
artifactRevisionFrgmt: BAIArtifactRevisionTableArtifactRevisionFragment$key;
30+
onClickDownload: (revisionId: string) => void;
31+
latestRevisionFrgmt:
32+
| BAIArtifactRevisionTableLatestRevisionFragment$key
33+
| null
34+
| undefined;
35+
}
36+
37+
const BAIArtifactRevisionTable = ({
38+
artifactRevisionFrgmt,
39+
onClickDownload,
40+
latestRevisionFrgmt,
41+
...tableProps
42+
}: BAIArtifactRevisionTableProps) => {
43+
const { t } = useTranslation();
44+
45+
const artifactRevision =
46+
useFragment<BAIArtifactRevisionTableArtifactRevisionFragment$key>(
47+
graphql`
48+
fragment BAIArtifactRevisionTableArtifactRevisionFragment on ArtifactRevision
49+
@relay(plural: true) {
50+
id
51+
version
52+
size
53+
status
54+
updatedAt
55+
}
56+
`,
57+
artifactRevisionFrgmt,
58+
);
59+
const latestRevision =
60+
useFragment<BAIArtifactRevisionTableLatestRevisionFragment$key>(
61+
graphql`
62+
fragment BAIArtifactRevisionTableLatestRevisionFragment on ArtifactRevision {
63+
id
64+
}
65+
`,
66+
latestRevisionFrgmt,
67+
);
68+
69+
const columns: BAIColumnsType<ArtifactRevision> = [
70+
{
71+
title: t('comp:BAIArtifactRevisionTable.Version'),
72+
dataIndex: 'version',
73+
key: 'version',
74+
width: '30%',
75+
render: (version: string, record: ArtifactRevision) => (
76+
<div>
77+
<BAIFlex align="center" gap={'xs'}>
78+
<BAIText monospace strong>
79+
{version}
80+
</BAIText>
81+
{latestRevision && latestRevision.id === record.id && (
82+
<Tag color="blue">Latest</Tag>
83+
)}
84+
{record.status === 'PULLED' && <BAITag>{record.status}</BAITag>}
85+
</BAIFlex>
86+
</div>
87+
),
88+
},
89+
{
90+
title: t('comp:BAIArtifactRevisionTable.Status'),
91+
dataIndex: 'status',
92+
key: 'status',
93+
width: '15%',
94+
render: (value: string) => {
95+
return <BAITag>{value}</BAITag>;
96+
},
97+
},
98+
{
99+
title: t('comp:BAIArtifactRevisionTable.Action'),
100+
key: 'action',
101+
width: '15%',
102+
render: (_, record: ArtifactRevision) => {
103+
const status = record.status;
104+
const isDownloadable = status === 'SCANNED';
105+
const isLoading = status === 'PULLING' || status === 'VERIFYING';
106+
107+
return (
108+
<Button
109+
icon={<Download size={16} />}
110+
type={'primary'}
111+
size="small"
112+
onClick={() => {
113+
if (isDownloadable) {
114+
onClickDownload(record.id);
115+
}
116+
}}
117+
disabled={isLoading || !isDownloadable}
118+
loading={isLoading}
119+
>
120+
Pull
121+
</Button>
122+
);
123+
},
124+
},
125+
{
126+
title: t('comp:BAIArtifactRevisionTable.Size'),
127+
dataIndex: 'size',
128+
key: 'size',
129+
width: '15%',
130+
render: (size: number) => {
131+
if (!size) return <BAIText monospace>N/A</BAIText>;
132+
return (
133+
<BAIText monospace>
134+
{convertToDecimalUnit(size, 'auto')?.displayValue}
135+
</BAIText>
136+
);
137+
},
138+
},
139+
{
140+
title: t('comp:BAIArtifactTable.Updated'),
141+
dataIndex: 'updatedAt',
142+
key: 'updatedAt',
143+
width: '15%',
144+
render: (updated_at: string) => (
145+
<BAIText type="secondary" title={dayjs(updated_at).toString()}>
146+
{dayjs(updated_at).fromNow()}
147+
</BAIText>
148+
),
149+
},
150+
];
151+
152+
return (
153+
<BAITable<ArtifactRevision>
154+
rowKey={(record) => record.id}
155+
resizable
156+
columns={filterOutEmpty(columns)}
157+
dataSource={artifactRevision}
158+
scroll={{ x: 'max-content' }}
159+
{...tableProps}
160+
></BAITable>
161+
);
162+
};
163+
164+
export default BAIArtifactRevisionTable;

0 commit comments

Comments
 (0)