mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-01-11 19:56:44 +00:00
feat: add GitHub repository connection modal and integrate GitHub app client ID
This commit is contained in:
parent
3fa6f9e7b1
commit
8635726344
3 changed files with 555 additions and 210 deletions
|
|
@ -253,3 +253,6 @@ export const SlackAppClientId: string | null =
|
|||
|
||||
export const MicrosoftTeamsAppClientId: string | null =
|
||||
env("MICROSOFT_TEAMS_APP_CLIENT_ID") || null;
|
||||
|
||||
export const GitHubAppClientId: string | null =
|
||||
env("GITHUB_APP_CLIENT_ID") || null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,245 @@
|
|||
import React, {
|
||||
FunctionComponent,
|
||||
ReactElement,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react";
|
||||
import Modal from "Common/UI/Components/Modal/Modal";
|
||||
import { ButtonStyleType } from "Common/UI/Components/Button/Button";
|
||||
import API from "Common/Utils/API";
|
||||
import URL from "Common/Types/API/URL";
|
||||
import { HOME_URL } from "Common/UI/Config";
|
||||
import ModelAPI from "Common/UI/Utils/ModelAPI/ModelAPI";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
import { JSONObject } from "Common/Types/JSON";
|
||||
import HTTPResponse from "Common/Types/API/HTTPResponse";
|
||||
import HTTPErrorResponse from "Common/Types/API/HTTPErrorResponse";
|
||||
import Exception from "Common/Types/Exception/Exception";
|
||||
import Dropdown, {
|
||||
DropdownOption,
|
||||
DropdownValue,
|
||||
} from "Common/UI/Components/Dropdown/Dropdown";
|
||||
|
||||
export interface GitHubRepository {
|
||||
id: number;
|
||||
name: string;
|
||||
fullName: string;
|
||||
private: boolean;
|
||||
htmlUrl: string;
|
||||
description: string | null;
|
||||
defaultBranch: string;
|
||||
ownerLogin: string;
|
||||
}
|
||||
|
||||
export interface ComponentProps {
|
||||
projectId: ObjectID;
|
||||
installationId: string;
|
||||
onClose: () => void;
|
||||
onSuccess: () => void;
|
||||
}
|
||||
|
||||
const GitHubRepoSelectorModal: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps,
|
||||
): ReactElement => {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [isSaving, setIsSaving] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string | undefined>(undefined);
|
||||
const [repositories, setRepositories] = useState<Array<GitHubRepository>>([]);
|
||||
const [selectedRepository, setSelectedRepository] = useState<
|
||||
GitHubRepository | undefined
|
||||
>(undefined);
|
||||
const [customName, setCustomName] = useState<string>("");
|
||||
|
||||
const loadRepositories: () => Promise<void> = async (): Promise<void> => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(undefined);
|
||||
|
||||
const response: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
||||
await API.get({
|
||||
url: URL.fromString(
|
||||
`${HOME_URL.toString()}/api/github/repositories/${props.projectId.toString()}/${props.installationId}`,
|
||||
),
|
||||
headers: ModelAPI.getCommonHeaders(),
|
||||
});
|
||||
|
||||
if (response instanceof HTTPErrorResponse) {
|
||||
throw response;
|
||||
}
|
||||
|
||||
const repos: Array<GitHubRepository> =
|
||||
(response.data["repositories"] as unknown as Array<GitHubRepository>) ||
|
||||
[];
|
||||
setRepositories(repos);
|
||||
} catch (e: unknown) {
|
||||
setError(API.getFriendlyErrorMessage(e as Exception));
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadRepositories().catch((e: unknown) => {
|
||||
setError(API.getFriendlyErrorMessage(e as Exception));
|
||||
});
|
||||
}, []);
|
||||
|
||||
const getRepositoryDropdownOptions: () => Array<DropdownOption> =
|
||||
(): Array<DropdownOption> => {
|
||||
return repositories.map((repo: GitHubRepository) => {
|
||||
return {
|
||||
label: repo.fullName + (repo.private ? " (private)" : ""),
|
||||
value: repo.id.toString(),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const onRepositorySelect: (
|
||||
value: DropdownValue | Array<DropdownValue> | null,
|
||||
) => void = (value: DropdownValue | Array<DropdownValue> | null): void => {
|
||||
if (!value || Array.isArray(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const repo: GitHubRepository | undefined = repositories.find(
|
||||
(r: GitHubRepository) => {
|
||||
return r.id.toString() === value?.toString();
|
||||
},
|
||||
);
|
||||
setSelectedRepository(repo);
|
||||
if (repo) {
|
||||
setCustomName(repo.fullName);
|
||||
}
|
||||
};
|
||||
|
||||
const onSubmit: () => Promise<void> = async (): Promise<void> => {
|
||||
if (!selectedRepository) {
|
||||
setError("Please select a repository");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsSaving(true);
|
||||
setError(undefined);
|
||||
|
||||
const response: HTTPResponse<JSONObject> | HTTPErrorResponse =
|
||||
await API.post({
|
||||
url: URL.fromString(
|
||||
`${HOME_URL.toString()}/api/github/repository/connect`,
|
||||
),
|
||||
headers: ModelAPI.getCommonHeaders(),
|
||||
data: {
|
||||
projectId: props.projectId.toString(),
|
||||
installationId: props.installationId,
|
||||
repositoryName: selectedRepository.name,
|
||||
organizationName: selectedRepository.ownerLogin,
|
||||
name: customName || selectedRepository.fullName,
|
||||
defaultBranch: selectedRepository.defaultBranch,
|
||||
repositoryUrl: selectedRepository.htmlUrl,
|
||||
} as JSONObject,
|
||||
});
|
||||
|
||||
if (response instanceof HTTPErrorResponse) {
|
||||
throw response;
|
||||
}
|
||||
|
||||
props.onSuccess();
|
||||
} catch (e: unknown) {
|
||||
setError(API.getFriendlyErrorMessage(e as Exception));
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const getSelectedDropdownOption: () => DropdownOption | undefined = ():
|
||||
| DropdownOption
|
||||
| undefined => {
|
||||
if (!selectedRepository) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
label:
|
||||
selectedRepository.fullName +
|
||||
(selectedRepository.private ? " (private)" : ""),
|
||||
value: selectedRepository.id.toString(),
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Connect GitHub Repository"
|
||||
description="Select a repository from your GitHub App installation to connect."
|
||||
onClose={props.onClose}
|
||||
onSubmit={onSubmit}
|
||||
submitButtonText="Connect Repository"
|
||||
submitButtonStyleType={ButtonStyleType.PRIMARY}
|
||||
isBodyLoading={isLoading}
|
||||
isLoading={isSaving}
|
||||
error={error}
|
||||
disableSubmitButton={!selectedRepository}
|
||||
>
|
||||
<div className="space-y-4">
|
||||
{repositories.length === 0 && !isLoading && (
|
||||
<div className="text-sm text-gray-600">
|
||||
No repositories found. Make sure the GitHub App has access to at
|
||||
least one repository.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{repositories.length > 0 && (
|
||||
<>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Repository
|
||||
</label>
|
||||
<Dropdown
|
||||
options={getRepositoryDropdownOptions()}
|
||||
onChange={onRepositorySelect}
|
||||
placeholder="Select a repository"
|
||||
value={getSelectedDropdownOption()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{selectedRepository && (
|
||||
<>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Display Name
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
value={customName}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setCustomName(e.target.value);
|
||||
}}
|
||||
placeholder="Enter a display name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="text-sm text-gray-500 space-y-1">
|
||||
<div>
|
||||
<strong>Owner:</strong> {selectedRepository.ownerLogin}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Default Branch:</strong>{" "}
|
||||
{selectedRepository.defaultBranch}
|
||||
</div>
|
||||
{selectedRepository.description && (
|
||||
<div>
|
||||
<strong>Description:</strong>{" "}
|
||||
{selectedRepository.description}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default GitHubRepoSelectorModal;
|
||||
|
|
@ -9,236 +9,333 @@ import DropdownUtil from "Common/UI/Utils/Dropdown";
|
|||
import Navigation from "Common/UI/Utils/Navigation";
|
||||
import Label from "Common/Models/DatabaseModels/Label";
|
||||
import CodeRepository from "Common/Models/DatabaseModels/CodeRepository";
|
||||
import React, { FunctionComponent, ReactElement } from "react";
|
||||
import React, {
|
||||
FunctionComponent,
|
||||
ReactElement,
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react";
|
||||
import { FormStep } from "Common/UI/Components/Forms/Types/FormStep";
|
||||
import { GitHubAppClientId, HOME_URL } from "Common/UI/Config";
|
||||
import UserUtil from "Common/UI/Utils/User";
|
||||
import GitHubRepoSelectorModal from "../../Components/CodeRepository/GitHubRepoSelectorModal";
|
||||
import Button, { ButtonStyleType } from "Common/UI/Components/Button/Button";
|
||||
import IconProp from "Common/Types/Icon/IconProp";
|
||||
import Card from "Common/UI/Components/Card/Card";
|
||||
import ObjectID from "Common/Types/ObjectID";
|
||||
|
||||
const CodeRepositoryPage: FunctionComponent<
|
||||
PageComponentProps
|
||||
> = (): ReactElement => {
|
||||
const [showGitHubModal, setShowGitHubModal] = useState<boolean>(false);
|
||||
const [gitHubInstallationId, setGitHubInstallationId] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const [refreshToggle, setRefreshToggle] = useState<string>("");
|
||||
|
||||
const projectId: ObjectID | null = ProjectUtil.getCurrentProjectId();
|
||||
|
||||
useEffect(() => {
|
||||
// Check for installation_id in URL query params (returned from GitHub OAuth)
|
||||
const urlParams: URLSearchParams = new URLSearchParams(
|
||||
window.location.search,
|
||||
);
|
||||
const installationId: string | null = urlParams.get("installation_id");
|
||||
|
||||
if (installationId) {
|
||||
setGitHubInstallationId(installationId);
|
||||
setShowGitHubModal(true);
|
||||
|
||||
// Clean up the URL
|
||||
const newUrl: string = window.location.pathname;
|
||||
window.history.replaceState({}, document.title, newUrl);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleConnectWithGitHub: () => void = (): void => {
|
||||
if (!projectId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const userId: ObjectID = UserUtil.getUserId();
|
||||
|
||||
// Redirect to GitHub App installation
|
||||
const installUrl: string = `${HOME_URL.toString()}/api/github/auth/install?projectId=${projectId.toString()}&userId=${userId.toString()}`;
|
||||
window.location.href = installUrl;
|
||||
};
|
||||
|
||||
const handleGitHubModalClose: () => void = (): void => {
|
||||
setShowGitHubModal(false);
|
||||
setGitHubInstallationId(null);
|
||||
};
|
||||
|
||||
const handleGitHubRepoConnected: () => void = (): void => {
|
||||
setShowGitHubModal(false);
|
||||
setGitHubInstallationId(null);
|
||||
// Refresh the table
|
||||
setRefreshToggle(Date.now().toString());
|
||||
};
|
||||
|
||||
const isGitHubAppConfigured: boolean = Boolean(GitHubAppClientId);
|
||||
|
||||
return (
|
||||
<ModelTable<CodeRepository>
|
||||
modelType={CodeRepository}
|
||||
id="code-repository-table"
|
||||
userPreferencesKey="code-repository-table"
|
||||
isDeleteable={false}
|
||||
isEditable={false}
|
||||
isCreateable={true}
|
||||
name="Code Repositories"
|
||||
isViewable={true}
|
||||
cardProps={{
|
||||
title: "Code Repositories",
|
||||
description:
|
||||
"Connect and manage your GitHub and GitLab repositories here.",
|
||||
}}
|
||||
showViewIdButton={true}
|
||||
noItemsMessage={"No repositories connected."}
|
||||
formSteps={[
|
||||
{
|
||||
title: "Basic Info",
|
||||
id: "basic-info",
|
||||
} as FormStep<CodeRepository>,
|
||||
{
|
||||
title: "Repository Details",
|
||||
id: "repository-details",
|
||||
} as FormStep<CodeRepository>,
|
||||
{
|
||||
title: "Labels",
|
||||
id: "labels",
|
||||
} as FormStep<CodeRepository>,
|
||||
]}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: "Name",
|
||||
stepId: "basic-info",
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: "Repository Name",
|
||||
validation: {
|
||||
minLength: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
description: true,
|
||||
},
|
||||
title: "Description",
|
||||
stepId: "basic-info",
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: false,
|
||||
placeholder: "Description",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryHostedAt: true,
|
||||
},
|
||||
title: "Repository Host",
|
||||
stepId: "repository-details",
|
||||
description: "Where is this repository hosted?",
|
||||
fieldType: FormFieldSchemaType.Dropdown,
|
||||
required: true,
|
||||
placeholder: "Select Host",
|
||||
dropdownOptions:
|
||||
DropdownUtil.getDropdownOptionsFromEnum(CodeRepositoryType),
|
||||
},
|
||||
{
|
||||
field: {
|
||||
organizationName: true,
|
||||
},
|
||||
title: "Organization / Username",
|
||||
stepId: "repository-details",
|
||||
<>
|
||||
{/* GitHub Connect Button */}
|
||||
{isGitHubAppConfigured && (
|
||||
<Card
|
||||
title="Connect with GitHub"
|
||||
description="Install the OneUptime GitHub App to automatically import repositories with full access for code analysis and automatic improvements."
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<Button
|
||||
title="Connect with GitHub"
|
||||
icon={IconProp.Link}
|
||||
buttonStyle={ButtonStyleType.PRIMARY}
|
||||
onClick={handleConnectWithGitHub}
|
||||
/>
|
||||
<span className="text-sm text-gray-500">
|
||||
Or use the manual form below to add a repository without GitHub
|
||||
App access.
|
||||
</span>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
<ModelTable<CodeRepository>
|
||||
modelType={CodeRepository}
|
||||
id="code-repository-table"
|
||||
userPreferencesKey="code-repository-table"
|
||||
isDeleteable={false}
|
||||
isEditable={false}
|
||||
isCreateable={true}
|
||||
name="Code Repositories"
|
||||
isViewable={true}
|
||||
refreshToggle={refreshToggle}
|
||||
cardProps={{
|
||||
title: "Code Repositories",
|
||||
description:
|
||||
"The GitHub organization or username that owns the repository.",
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: "Organization Name",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryName: true,
|
||||
},
|
||||
title: "Repository Name",
|
||||
stepId: "repository-details",
|
||||
description: "The name of the repository.",
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: "Repository Name",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
mainBranchName: true,
|
||||
},
|
||||
title: "Main Branch",
|
||||
stepId: "repository-details",
|
||||
description:
|
||||
"The main branch of the repository (e.g., main, master).",
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: "main",
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: true,
|
||||
},
|
||||
title: "Labels",
|
||||
stepId: "labels",
|
||||
description:
|
||||
"Team members with access to these labels will only be able to access this resource. This is optional and an advanced feature.",
|
||||
fieldType: FormFieldSchemaType.MultiSelectDropdown,
|
||||
dropdownModal: {
|
||||
type: Label,
|
||||
labelField: "name",
|
||||
valueField: "_id",
|
||||
},
|
||||
required: false,
|
||||
placeholder: "Labels",
|
||||
},
|
||||
]}
|
||||
showRefreshButton={true}
|
||||
viewPageRoute={Navigation.getCurrentRoute()}
|
||||
filters={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: "Name",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryHostedAt: true,
|
||||
},
|
||||
title: "Repository Host",
|
||||
type: FieldType.Dropdown,
|
||||
filterDropdownOptions:
|
||||
DropdownUtil.getDropdownOptionsFromEnum(CodeRepositoryType),
|
||||
},
|
||||
{
|
||||
field: {
|
||||
organizationName: true,
|
||||
},
|
||||
title: "Organization",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryName: true,
|
||||
},
|
||||
title: "Repository",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: {
|
||||
"Connect and manage your GitHub and GitLab repositories here.",
|
||||
}}
|
||||
showViewIdButton={true}
|
||||
noItemsMessage={"No repositories connected."}
|
||||
formSteps={[
|
||||
{
|
||||
title: "Basic Info",
|
||||
id: "basic-info",
|
||||
} as FormStep<CodeRepository>,
|
||||
{
|
||||
title: "Repository Details",
|
||||
id: "repository-details",
|
||||
} as FormStep<CodeRepository>,
|
||||
{
|
||||
title: "Labels",
|
||||
id: "labels",
|
||||
} as FormStep<CodeRepository>,
|
||||
]}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
color: true,
|
||||
},
|
||||
title: "Name",
|
||||
stepId: "basic-info",
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: "Repository Name",
|
||||
validation: {
|
||||
minLength: 2,
|
||||
},
|
||||
},
|
||||
title: "Labels",
|
||||
type: FieldType.EntityArray,
|
||||
filterEntityType: Label,
|
||||
filterQuery: {
|
||||
projectId: ProjectUtil.getCurrentProjectId()!,
|
||||
{
|
||||
field: {
|
||||
description: true,
|
||||
},
|
||||
title: "Description",
|
||||
stepId: "basic-info",
|
||||
fieldType: FormFieldSchemaType.LongText,
|
||||
required: false,
|
||||
placeholder: "Description",
|
||||
},
|
||||
filterDropdownField: {
|
||||
label: "name",
|
||||
value: "_id",
|
||||
{
|
||||
field: {
|
||||
repositoryHostedAt: true,
|
||||
},
|
||||
title: "Repository Host",
|
||||
stepId: "repository-details",
|
||||
description: "Where is this repository hosted?",
|
||||
fieldType: FormFieldSchemaType.Dropdown,
|
||||
required: true,
|
||||
placeholder: "Select Host",
|
||||
dropdownOptions:
|
||||
DropdownUtil.getDropdownOptionsFromEnum(CodeRepositoryType),
|
||||
},
|
||||
},
|
||||
]}
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
{
|
||||
field: {
|
||||
organizationName: true,
|
||||
},
|
||||
title: "Organization / Username",
|
||||
stepId: "repository-details",
|
||||
description:
|
||||
"The GitHub organization or username that owns the repository.",
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: "Organization Name",
|
||||
},
|
||||
title: "Name",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryHostedAt: true,
|
||||
{
|
||||
field: {
|
||||
repositoryName: true,
|
||||
},
|
||||
title: "Repository Name",
|
||||
stepId: "repository-details",
|
||||
description: "The name of the repository.",
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: "Repository Name",
|
||||
},
|
||||
title: "Host",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
organizationName: true,
|
||||
{
|
||||
field: {
|
||||
mainBranchName: true,
|
||||
},
|
||||
title: "Main Branch",
|
||||
stepId: "repository-details",
|
||||
description:
|
||||
"The main branch of the repository (e.g., main, master).",
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
required: true,
|
||||
placeholder: "main",
|
||||
},
|
||||
title: "Organization",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryName: true,
|
||||
{
|
||||
field: {
|
||||
labels: true,
|
||||
},
|
||||
title: "Labels",
|
||||
stepId: "labels",
|
||||
description:
|
||||
"Team members with access to these labels will only be able to access this resource. This is optional and an advanced feature.",
|
||||
fieldType: FormFieldSchemaType.MultiSelectDropdown,
|
||||
dropdownModal: {
|
||||
type: Label,
|
||||
labelField: "name",
|
||||
valueField: "_id",
|
||||
},
|
||||
required: false,
|
||||
placeholder: "Labels",
|
||||
},
|
||||
title: "Repository",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
mainBranchName: true,
|
||||
},
|
||||
title: "Main Branch",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: {
|
||||
]}
|
||||
showRefreshButton={true}
|
||||
viewPageRoute={Navigation.getCurrentRoute()}
|
||||
filters={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
color: true,
|
||||
},
|
||||
title: "Name",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryHostedAt: true,
|
||||
},
|
||||
title: "Repository Host",
|
||||
type: FieldType.Dropdown,
|
||||
filterDropdownOptions:
|
||||
DropdownUtil.getDropdownOptionsFromEnum(CodeRepositoryType),
|
||||
},
|
||||
{
|
||||
field: {
|
||||
organizationName: true,
|
||||
},
|
||||
title: "Organization",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryName: true,
|
||||
},
|
||||
title: "Repository",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: {
|
||||
name: true,
|
||||
color: true,
|
||||
},
|
||||
},
|
||||
title: "Labels",
|
||||
type: FieldType.EntityArray,
|
||||
filterEntityType: Label,
|
||||
filterQuery: {
|
||||
projectId: ProjectUtil.getCurrentProjectId()!,
|
||||
},
|
||||
filterDropdownField: {
|
||||
label: "name",
|
||||
value: "_id",
|
||||
},
|
||||
},
|
||||
title: "Labels",
|
||||
type: FieldType.EntityArray,
|
||||
getElement: (item: CodeRepository): ReactElement => {
|
||||
return <LabelsElement labels={item["labels"] || []} />;
|
||||
]}
|
||||
columns={[
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: "Name",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{
|
||||
field: {
|
||||
repositoryHostedAt: true,
|
||||
},
|
||||
title: "Host",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
organizationName: true,
|
||||
},
|
||||
title: "Organization",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
repositoryName: true,
|
||||
},
|
||||
title: "Repository",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
mainBranchName: true,
|
||||
},
|
||||
title: "Main Branch",
|
||||
type: FieldType.Text,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
labels: {
|
||||
name: true,
|
||||
color: true,
|
||||
},
|
||||
},
|
||||
title: "Labels",
|
||||
type: FieldType.EntityArray,
|
||||
getElement: (item: CodeRepository): ReactElement => {
|
||||
return <LabelsElement labels={item["labels"] || []} />;
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
{/* GitHub Repository Selector Modal */}
|
||||
{showGitHubModal && gitHubInstallationId && projectId && (
|
||||
<GitHubRepoSelectorModal
|
||||
projectId={projectId}
|
||||
installationId={gitHubInstallationId}
|
||||
onClose={handleGitHubModalClose}
|
||||
onSuccess={handleGitHubRepoConnected}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue