Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Versions page closes #410, credits to EliasVal <3 #432

Merged
merged 5 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions src/components/docs/versions/builds/build-failure-details.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { useReducer } from 'react';
import CodeBlock from '@theme/CodeBlock';

interface Props {
ciJob;
ciBuild;
repoVersionInfo;
editorVersionInfo;
style;
}

const BuildFailureDetails = ({
ciJob,
repoVersionInfo,
editorVersionInfo,
ciBuild,
...rest
}: Props) => {
const { editorVersion, baseOs, targetPlatform } = ciBuild.buildInfo;
const { major, minor, patch } = repoVersionInfo;

const reducer = (state, action) => {
const { tag, value } = action;
return { ...state, [tag]: value };
};

const [tags /* , dispatch */] = useReducer(reducer, {
[`${baseOs}-${editorVersion}-${targetPlatform}-${major}`]: '❓',
[`${baseOs}-${editorVersion}-${targetPlatform}-${major}.${minor}`]: '❓',
[`${baseOs}-${editorVersion}-${targetPlatform}-${major}.${minor}.${patch}`]: '❓',
[`${editorVersion}-${targetPlatform}-${major}`]: '❓',
[`${editorVersion}-${targetPlatform}-${major}.${minor}`]: '❓',
[`${editorVersion}-${targetPlatform}-${major}.${minor}.${patch}`]: '❓',
});

// Todo - fetch docker info from dockerhub for all tags, or do it on the server
// useEffect(() => {
// (async () => {
// const repo = 'unityci/editor';
// for (const tag of Object.keys(tags)) {
// const requestUrl = `https://index.docker.io/v1/repositories/${repo}/tags/${tag}`;
// try {
// const response = await fetch(requestUrl);
// dispatch({ tag, value: response.status === 0 });
// } catch (error) {
// dispatch({ tag, value: false });
// }
// }
// })();
// }, []);

const { changeSet } = editorVersionInfo;
const buildCommand = `#!/usr/bin/env bash
git clone git@github.com:game-ci/docker.git
cd docker

editor_version=${editorVersion}
change_set=${changeSet}
base_os=${baseOs}
target_platform=${targetPlatform}
image_name=unityci-editor:$editor_version-$target_platform

docker build . \\
--file ./images/$base_os/editor/Dockerfile \\
-t $image_name \\
--build-arg=version=$editor_version \\
--build-arg=changeSet=$change_set \\
--build-arg=module=$target_platform
`;

const pullCommand = `docker pull unityci/editor:${baseOs}-${editorVersion}-${targetPlatform}-${major}.${minor}.${patch}`;

return (
<div {...rest}>
<h4>CI Job identification</h4>
<CodeBlock language="json">{JSON.stringify(ciJob, null, 2)}</CodeBlock>
<br />
<h4>Commands</h4>
<p>Build the docker image locally for debugging:</p>
<CodeBlock language="bash">{buildCommand}</CodeBlock>
<p>Pull this docker image:</p>
<CodeBlock language="bash">{pullCommand}</CodeBlock>
<br />
<h4>Associated tags on docker hub</h4>
<CodeBlock language="json">{JSON.stringify(tags, null, 2)}</CodeBlock>
<br />
<h4>CI Build details</h4>
<CodeBlock language="json">{JSON.stringify(ciBuild, null, 2)}</CodeBlock>
</div>
);
};

export default BuildFailureDetails;
83 changes: 83 additions & 0 deletions src/components/docs/versions/builds/build-row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useState } from 'react';
import DockerImageLinkOrRetryButton, {
type Record,
} from '@site/src/components/docs/versions/docker-image-link-or-retry-button';
import Spinner from '@site/src/components/molecules/spinner';
import Tooltip from '@site/src/components/molecules/tooltip/tooltip';
import styles from './builds.module.scss';

const mapBuildStatusToIcon = {
started: <Spinner type="slow" />,
failed: '⚠',
published: '✅',
};

type Props = {
children: React.JSX.Element | React.JSX.Element[];
build: Record;
};

const CopyToClipboard = (copyString: string) => {
navigator.clipboard.writeText(copyString);
};

export default function BuildRow({ children, build }: Props) {
const [expanded, setExpanded] = useState(false);
const [toolbarContent, setToolbarContent] = useState('Click to copy');

const MapBuildStatusToElement = (status: string) => {
const icon = mapBuildStatusToIcon[status];

switch (status) {
case 'started':
return <Spinner type="slow" />;
case 'failed':
return <Tooltip content={build.failure?.reason}>{icon}</Tooltip>;
case 'published':
return icon;
default:
return status;
}
};

return (
<>
<tr className={styles.tableRow}>
<td
onClick={() => setExpanded(!expanded)}
className="text-center select-none cursor-pointer text-2xl"
>
{expanded ? '-' : '+'}
</td>
<td className="text-center">{MapBuildStatusToElement(build.status)}</td>
<td>
<span>
<Tooltip content={toolbarContent}>
<button
onClick={() => {
CopyToClipboard(build.buildId);
setToolbarContent('Copied to clipboard!');
}}
onMouseLeave={() => {
setToolbarContent('Click to copy');
}}
type="button"
>
{build.buildId}
</button>
</Tooltip>
<DockerImageLinkOrRetryButton record={build} />
</span>
</td>
<td>{build.imageType}</td>
<td>{build.buildInfo.baseOs}</td>
<td>{build.buildInfo.targetPlatform}</td>
</tr>
{expanded && (
<tr className={styles.expandedContentRow}>
<td colSpan={6}>{children}</td>
</tr>
)}
</>
);
}
22 changes: 22 additions & 0 deletions src/components/docs/versions/builds/builds.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.stickyRow:global(.ant-table-row.ant-table-row-level-0) > :global(td) {
position: sticky;
top: 99px; /* height of the collapse-item-header + the parent tr > td sticky */
background-color: rgb(255, 255, 255);
z-index: 2;
box-shadow: 0 0 25px rgba(255,255,255,1), 0 0 15px rgba(255,255,255,1), 0 0 20px rgba(255,255,255,1);
clip-path: inset(-25px 0 0 0);
}

.stickyRow:global(.ant-table-row.ant-table-row-level-0) > :global(td:not(:last-child)) {
clip-path: inset(-25px -1px 0 0); /* fix for space from responsive vs fixed width on cells */
}

.expandedContentRow {
height: 0;
overflow: hidden;
}


.tableRow {
width: 100%;
}
62 changes: 62 additions & 0 deletions src/components/docs/versions/builds/builds.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { useFirestore, useFirestoreCollectionData } from 'reactfire';
import BuildFailureDetails from '@site/src/components/docs/versions/builds/build-failure-details';
import styles from './builds.module.scss';
import BuildRow from './build-row';
import { Record } from '../docker-image-link-or-retry-button';

interface RepoVersionInfo {
version: string;
major: number;
minor: number;
patch: number;
}

interface Props {
ciJobId: string;
repoVersionInfo: RepoVersionInfo;
editorVersionInfo;
}

const Builds = ({ ciJobId, repoVersionInfo, editorVersionInfo }: Props) => {
const loading = <p>Fetching builds...</p>;

const ciBuilds = useFirestore().collection('ciBuilds').where('relatedJobId', '==', ciJobId);

const { status, data } = useFirestoreCollectionData<{ [key: string]: any }>(ciBuilds);
const isLoading = status === 'loading';

if (isLoading) {
return loading;
}

const expandable = {
expandedRowRender: (record) => (
<BuildFailureDetails
style={{ margin: 0 }}
ciJob={ciJobId}
editorVersionInfo={editorVersionInfo}
repoVersionInfo={repoVersionInfo}
ciBuild={record}
/>
),
};

return (
<table className="w-full max-w-screen-lg block border-collapse">
<tr className={styles.tableRow}>
<th> </th>
<th className="text-center">Status</th>
<th>Build ID</th>
<th>Image type</th>
<th>OS</th>
<th>Target Platform</th>
</tr>
{data.map((build: Record) => (
<BuildRow build={build}>{expandable.expandedRowRender(build)}</BuildRow>
))}
</table>
);
};

export default Builds;
11 changes: 9 additions & 2 deletions src/components/docs/versions/date-time.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import Tooltip from '../../molecules/tooltip/tooltip';

interface Props {
utcSeconds: number;
Expand All @@ -10,16 +11,22 @@ const options: Intl.DateTimeFormatOptions = {
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
timeZoneName: 'short',
hour12: true,
};

const DateTime = ({ utcSeconds }: Props) => {
const date = new Date(0); // Use epoch

date.setUTCSeconds(utcSeconds);

return <span>{`${date.toLocaleString('en-GB', options)}`}</span>;
return (
<Tooltip content={`${date.toLocaleString('en-GB', options)}`}>
<span style={{ color: 'rgba(255, 255, 255, 0.4)' }}>
<u>( ... )</u>
</span>
</Tooltip>
);
};

export default DateTime;
40 changes: 23 additions & 17 deletions src/components/docs/versions/docker-image-link-or-retry-button.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,36 @@
import { Tooltip } from 'antd';
import React, { useState } from 'react';
import { HiOutlineRefresh } from 'react-icons/hi';
import { SimpleAuthCheck } from '@site/src/components/auth/safe-auth-check';
import DockerImageLink from '@site/src/components/docs/versions/docker-image-link';
import { useAuthenticatedEndpoint } from '@site/src/core/hooks/use-authenticated-endpoint';
import { useNotification } from '@site/src/core/hooks/use-notification';
import Spinner from '@site/src/components/molecules/spinner';
import Tooltip from '@site/src/components/molecules/tooltip/tooltip';

interface Props {
record: {
buildId: string;
relatedJobId: string;
buildInfo: {
baseOs: string;
editorVersion: string;
targetPlatform: string;
repoVersion: string;
};
dockerInfo: {
imageRepo: string;
imageName: string;
};
status: string;
type Record = {
buildId: string;
relatedJobId: string;
buildInfo: {
baseOs: string;
editorVersion: string;
targetPlatform: string;
repoVersion: string;
};
dockerInfo: {
digest: string;
imageRepo: string;
imageName: string;
};
status: string;
[key: string]: any;
};

interface Props {
record: Record;
}

export { Record };

const DockerImageLinkOrRetryButton = ({ record }: Props) => {
const { buildInfo, dockerInfo, buildId, relatedJobId, status } = record;
const { baseOs, editorVersion, targetPlatform, repoVersion } = buildInfo;
Expand Down Expand Up @@ -55,7 +61,7 @@ const DockerImageLinkOrRetryButton = ({ record }: Props) => {

return (
<SimpleAuthCheck fallback={<span />} requiredClaims={{ admin: true }}>
<Tooltip title={`Delete tag "${imageTag}" then click this retry button.`}>
<Tooltip content={`Delete tag "${imageTag}" then click this retry button.`}>
<button
type="button"
onClick={onClick}
Expand Down
26 changes: 15 additions & 11 deletions src/components/docs/versions/docker-image-link.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { SiDocker } from 'react-icons/si';
import Tooltip from '../../molecules/tooltip/tooltip';

interface Props {
imageRepo: string;
Expand All @@ -9,17 +10,20 @@ interface Props {

const DockerImageLink = ({ imageRepo, imageName, imageTag }: Props) => {
return (
<a
aria-label="Image url"
target="_blank"
rel="noreferrer"
href={
`https://hub.docker.com/repository/docker/${imageRepo}/${imageName}/tags` +
`?page=1&ordering=last_updated&name=${imageTag}`
}
>
<SiDocker />
</a>
<Tooltip content="Dockerhub Image">
<a
aria-label="Image url"
target="_blank"
rel="noreferrer"
href={
`https://hub.docker.com/repository/docker/${imageRepo}/${imageName}/tags` +
`?page=1&ordering=last_updated&name=${imageTag}`
}
className="align-middle ml-2 text-blue-600"
>
<SiDocker />
</a>
</Tooltip>
);
};

Expand Down
Loading
Loading