in packages/serverless-logic-web-tools/src/editor/CreateGitHubRepositoryModal.tsx [59:337]
export function CreateGitHubRepositoryModal(props: {
workspace: ActiveWorkspace;
isOpen: boolean;
onClose: () => void;
onSuccess: (args: { url: string }) => void;
currentFile: WorkspaceFile;
}) {
const history = useHistory();
const routes = useRoutes();
const workspaces = useWorkspaces();
const settingsDispatch = useSettingsDispatch();
const githubAuthInfo = useGitHubAuthInfo();
const { applyAccelerator, rollbackApply, canAcceleratorBeUsed, hasConflictsWithAccelerator, cleanUpTempResources } =
useAccelerator({
workspaceId: props.workspace.descriptor.workspaceId,
currentFile: props.currentFile,
accelerator: ACCELERATOR_TO_USE,
});
const [isPrivate, setPrivate] = useState(false);
const [isLoading, setLoading] = useState(false);
const [error, setError] = useState<string | undefined>(undefined);
const [name, setName] = useState(getSuggestedRepositoryName(props.workspace.descriptor.name));
const [shouldUseAccelerator, setShouldUseAccelerator] = useState(false);
useEffect(() => {
setName(getSuggestedRepositoryName(props.workspace.descriptor.name));
}, [props.workspace.descriptor.name]);
useEffect(() => {
if (props.isOpen) {
setShouldUseAccelerator(false);
}
}, [props.isOpen]);
const create = useCallback(async () => {
let applyAcceleratorResult: ApplyAcceleratorResult | undefined;
if (!githubAuthInfo) {
return;
}
setError(undefined);
setLoading(true);
try {
const repo = await settingsDispatch.github.octokit.repos.createForAuthenticatedUser({ name, private: isPrivate });
if (!repo.data.clone_url) {
throw new Error("Repository creation failed");
}
if (canAcceleratorBeUsed && shouldUseAccelerator) {
applyAcceleratorResult = await applyAccelerator();
if (!applyAcceleratorResult.success) {
throw new Error(applyAcceleratorResult.message);
}
} else {
await workspaces.createSavePoint({
workspaceId: props.workspace.descriptor.workspaceId,
gitConfig: {
name: githubAuthInfo.name,
email: githubAuthInfo.email,
},
});
}
await workspaces.addRemote({
workspaceId: props.workspace.descriptor.workspaceId,
url: repo.data.clone_url,
name: GIT_ORIGIN_REMOTE_NAME,
force: true,
});
await workspaces.push({
workspaceId: props.workspace.descriptor.workspaceId,
remote: GIT_ORIGIN_REMOTE_NAME,
ref: GIT_DEFAULT_BRANCH,
remoteRef: `refs/heads/${GIT_DEFAULT_BRANCH}`,
force: false,
authInfo: githubAuthInfo,
});
await workspaces.initGitOnWorkspace({
workspaceId: props.workspace.descriptor.workspaceId,
remoteUrl: new URL(repo.data.clone_url),
});
await workspaces.renameWorkspace({
workspaceId: props.workspace.descriptor.workspaceId,
newName: new URL(repo.data.html_url).pathname.substring(1),
});
props.onClose();
props.onSuccess({ url: repo.data.html_url });
if (applyAcceleratorResult?.success) {
history.replace({
pathname: routes.workspaceWithFilePath.path({
workspaceId: props.workspace.descriptor.workspaceId,
fileRelativePath: applyAcceleratorResult.currentFileAfterMoving.relativePathWithoutExtension,
extension: applyAcceleratorResult.currentFileAfterMoving.extension,
}),
});
}
} catch (err) {
if (applyAcceleratorResult?.success) {
await rollbackApply({ ...applyAcceleratorResult });
}
history.replace({
pathname: routes.workspaceWithFilePath.path({
extension: props.currentFile.extension,
fileRelativePath: props.currentFile.relativePathWithoutExtension,
workspaceId: props.workspace.descriptor.workspaceId,
}),
});
console.error(err);
setError(err);
} finally {
setLoading(false);
if (applyAcceleratorResult) {
await cleanUpTempResources({
backupBranchName: applyAcceleratorResult.backupBranchName,
tempBranchName: applyAcceleratorResult.tempBranchName,
});
}
}
}, [
githubAuthInfo,
canAcceleratorBeUsed,
shouldUseAccelerator,
settingsDispatch.github.octokit.repos,
name,
isPrivate,
workspaces,
props,
applyAccelerator,
history,
routes.workspaceWithFilePath,
rollbackApply,
cleanUpTempResources,
]);
const isNameValid = useMemo(() => {
return name.match(/^[._\-\w\d]+$/g);
}, [name]);
const validated = useMemo(() => {
if (isNameValid) {
return ValidatedOptions.success;
} else {
return ValidatedOptions.error;
}
}, [isNameValid]);
return (
<Modal
variant={ModalVariant.medium}
aria-label={"Create a new GitHub repository"}
isOpen={props.isOpen}
onClose={props.onClose}
title={"Create GitHub repository"}
titleIconVariant={GithubIcon}
description={`The contents of '${props.workspace.descriptor.name}' will be all in the new GitHub Repository.`}
actions={[
<Button isLoading={isLoading} key="create" variant="primary" onClick={create} isDisabled={!isNameValid}>
Create
</Button>,
]}
>
<br />
<Form
style={{ padding: "0 16px 0 16px" }}
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
return create();
}}
>
{error && (
<FormAlert>
<Alert variant="danger" title={"Error creating GitHub Repository. " + error} isInline={true} />
<br />
</FormAlert>
)}
<FormGroup label="Name" isRequired={true} fieldId="github-repository-name">
<TextInput
id={"github-repo-name"}
validated={validated}
isRequired={true}
placeholder={"Name"}
value={name}
onChange={(_event, val) => setName(val)}
/>
{validated === "error" ? (
<FormHelperText>
<HelperText>
<HelperTextItem variant="error">
{"Invalid name. Only letters, numbers, dashes (-), dots (.), and underscores (_) are allowed."}
</HelperTextItem>
</HelperText>
</FormHelperText>
) : (
<FormHelperText>
<HelperText>
<HelperTextItem variant="success"></HelperTextItem>
</HelperText>
</FormHelperText>
)}
</FormGroup>
<Divider inset={{ default: "inset3xl" }} />
<FormGroup fieldId="github-repo-visibility">
<Radio
isChecked={!isPrivate}
id={"github-repository-public"}
name={"github-repository-public"}
label={
<>
<UsersIcon />
Public
</>
}
description={"Anyone on the internet can see this repository. You choose who can commit."}
onChange={() => setPrivate(false)}
/>
<br />
<Radio
isChecked={isPrivate}
id={"github-repository-private"}
name={"github-repository-private"}
label={
<>
<LockIcon />
Private
</>
}
description={"You choose who can see and commit to this repository."}
onChange={() => setPrivate(true)}
/>
<br />
<Tooltip
content={`${ACCELERATOR_TO_USE.name} Accelerator cannot be applied to this workspace.`}
trigger={!canAcceleratorBeUsed ? "mouseenter click" : ""}
>
<Checkbox
id="check-use-accelerator"
label={`Use ${ACCELERATOR_TO_USE.name} Accelerator`}
description={
<>
{`A project structure is created and the workspace files are placed in '${ACCELERATOR_TO_USE.folderToMoveFiles}' folder.`}
<br />
{canAcceleratorBeUsed &&
hasConflictsWithAccelerator &&
`Note that conflicting files will be moved to '${ACCELERATOR_TO_USE.folderToMoveBlockedFiles}' folder.`}
</>
}
isChecked={shouldUseAccelerator}
onChange={(_event, checked) => setShouldUseAccelerator(checked)}
isDisabled={!canAcceleratorBeUsed}
/>
</Tooltip>
{
<FormHelperText>
<HelperText>
<HelperTextItem variant="default"></HelperTextItem>
</HelperText>
</FormHelperText>
}
</FormGroup>
</Form>
</Modal>
);
}