in source/idea/idea-cluster-manager/webapp/src/pages/hpc/update-hpc-application.tsx [479:809]
render() {
const isVariableReferencedInScript = (name: string) => {
if (this.state.updatedApplication.job_script_type === "jinja2") {
const matches = this.state.jobScriptTemplate.match(`{{.*(\\b${name}\\b).*}}`);
if (matches == null || matches.length === 0) {
return false;
}
return matches[1] === name;
} else {
return this.state.jobScriptTemplate.search(`%${name}%`) >= 0;
}
};
return (
<IdeaAppLayout
ideaPageId={this.props.ideaPageId}
toolsOpen={this.props.toolsOpen}
tools={this.props.tools}
onToolsChange={this.props.onToolsChange}
onPageChange={this.props.onPageChange}
sideNavHeader={this.props.sideNavHeader}
sideNavItems={this.props.sideNavItems}
onSideNavChange={this.props.onSideNavChange}
onFlashbarChange={this.props.onFlashbarChange}
flashbarItems={this.props.flashbarItems}
breadcrumbItems={[
{
text: "IDEA",
href: "#/",
},
{
text: "Scale-Out Computing",
href: "#/soca/active-jobs",
},
{
text: "Applications",
href: "#/soca/applications",
},
{
text: this.isCreate() ? "Create Application" : `Update Application${this.state.updatedApplication.title ? ": " + this.state.updatedApplication.title : ""}`,
href: "#",
},
]}
contentType={"wizard"}
content={
this.isReady() && (
<Wizard
i18nStrings={{
stepNumberLabel: (stepNumber) => `Step ${stepNumber}`,
collapsedStepsLabel: (stepNumber, stepsCount) => `Step ${stepNumber} of ${stepsCount}`,
skipToButtonLabel: (step, stepNumber) => `Skip to ${step.title}`,
cancelButton: "Cancel",
previousButton: "Previous",
nextButton: "Next",
submitButton: "Submit",
optional: "optional",
}}
onNavigate={(event) => {
this.onWizardNavigate(event.detail.requestedStepIndex);
}}
onSubmit={this.onSubmit}
onCancel={() => {
this.props.navigate("/soca/applications");
}}
activeStepIndex={this.state.activeStep}
steps={[
{
title: "Design Job Submission Form",
info: (
<Link variant="info" onFollow={() => this.showHelp("job-design-form")}>
Info
</Link>
),
content: (
<IdeaFormBuilder
ref={this.formBuilder}
params={this.getRecommendedJobParameters()}
infoSection={
this.isCreate() && (
<div>
<p>
We have generated a test job submission form for you. You can customize it as needed or click <strong>Reset Form</strong> to start from scratch.
</p>
</div>
)
}
/>
),
},
{
title: "Design the Job Script",
content: (
<Container variant="default">
<SpaceBetween direction="vertical" size="xl">
<IdeaForm
columns={2}
ref={this.jobScriptForm}
name="job-script-interpreter"
showHeader={false}
showActions={false}
onStateChange={(event) => {
if (event.param.name === "job_script_type") {
this.setState({
updatedApplication: {
...this.state.updatedApplication,
job_script_type: event.value,
},
});
}
}}
values={{
job_script_interpreter: this.state.updatedApplication.job_script_interpreter,
job_script_type: this.state.updatedApplication.job_script_type,
}}
params={[
{
name: "job_script_interpreter",
title: "Script Interpreter",
description: "Select the interpreter you want to use",
data_type: "str",
param_type: "select",
default: "pbs",
choices: [
{
title: "PBS Job Script",
description: "This is a PBS job script (will use qsub)",
value: "pbs",
},
{
title: "Linux Shell Script",
description: "This is a Linux shell script (will use /bin/bash)",
value: "bash",
},
],
},
{
name: "job_script_type",
title: "Script Template Type",
description: "Select the script template type",
data_type: "str",
param_type: "select",
default: "jinja2",
choices: [
{
title: "Simple",
description: "Simple replacement of %foo%",
value: "default",
},
{
title: "Advanced (Jinja2)",
description: "Use Jinja2 template to write your job scripts",
value: "jinja2",
},
],
},
]}
/>
<FormField label="Available Variables" description="Below variables are available for use in your job script, based on the form designed in the previous step.">
<ul>
<li>
<AvailableVariable name="project_name" isReferenced={isVariableReferencedInScript("project_name")} isDefined={this.isVariableDefined("project_name")} required={true} description={"included automatically"} />
</li>
<li>
<AvailableVariable name="cpus" isReferenced={isVariableReferencedInScript("cpus")} required={true} isDefined={this.isVariableDefined("cpus")} description={"used for node count computation"} />
</li>
{this.isFormDesigned() &&
this.getDesignedFormVariables().map((param) => {
if (param.param_type!.startsWith("heading")) {
return "";
}
if (param.name === "cpus") {
return "";
}
if (param.name === "project_name") {
return "";
}
if (!param.name) {
return "";
}
return (
<li key={param.name}>
<AvailableVariable name={param.name} isReferenced={isVariableReferencedInScript(param.name)} isDefined={this.isVariableDefined(param.name)} required={Utils.isTrue(param.validate?.required)} />
</li>
);
})}
</ul>
</FormField>
<FormField label="Job Script" description="Build the job script template based on your simulation requirements" stretch={true}>
<SpaceBetween size="xs" direction="vertical">
<CodeEditor
id="job-script-editor"
ace={this.state.ace}
language={this.state.language}
value={this.state.jobScriptTemplate}
preferences={this.state.preferences}
onPreferencesChange={(e) =>
this.setState({
preferences: e.detail,
})
}
onChange={(e) => {
this.setState({
jobScriptTemplate: e.detail.value,
});
}}
loading={false}
i18nStrings={{
loadingState: "Loading code editor",
errorState: "There was an error loading the code editor.",
errorStateRecovery: "Retry",
editorGroupAriaLabel: "Code editor",
statusBarGroupAriaLabel: "Status bar",
cursorPosition: (row, column) => `Ln ${row}, Col ${column}`,
errorsTab: "Errors",
warningsTab: "Warnings",
preferencesButtonAriaLabel: "Preferences",
paneCloseButtonAriaLabel: "Close",
preferencesModalHeader: "Preferences",
preferencesModalCancel: "Cancel",
preferencesModalConfirm: "Confirm",
preferencesModalWrapLines: "Wrap lines",
preferencesModalTheme: "Theme",
preferencesModalLightThemes: "Light themes",
preferencesModalDarkThemes: "Dark themes",
}}
/>
<Button variant="normal" onClick={this.onResetJobScript}>
Reset Job Script
</Button>
</SpaceBetween>
</FormField>
</SpaceBetween>
</Container>
),
},
{
title: "Create Application Profile",
content: (
<ColumnLayout columns={2}>
<Container variant="default">
<SpaceBetween size="m" direction="vertical">
<IdeaFormField
ref={this.titleFormField}
module="submit-application-profile"
param={{
name: "title",
title: "Title",
description: "Enter a user friendly title for the application profile",
data_type: "str",
param_type: "text",
validate: {
required: true,
},
default: this.state.updatedApplication.title,
}}
/>
<IdeaFormField
ref={this.projectsFormField}
module="submit-application-profile"
value={this.state.project_ids}
onFetchOptions={(event) => {
return AppContext.get()
.client()
.projects()
.listProjects({
paginator: {
page_size: 100,
},
})
.then((result) => {
let choices: any = [];
result.listing?.forEach((project) => {
choices.push({
title: project.title,
value: project.project_id,
description: `Project Code: ${project.name}`,
});
});
return {
listing: choices,
};
});
}}
param={{
name: "project_ids",
title: "Projects",
description: "Select applicable projects for the Queue Profile",
param_type: "select",
multiple: true,
data_type: "str",
validate: {
required: true,
},
dynamic_choices: true,
}}
/>
<FormField label="Select Thumbnail" description="Select an image (.jpg or .png) to use as thumbnail">
<Box>
<input
type="file"
accept="image/png,image/jpeg"
onChange={(event) => {
this.resizeImage(event.target.files![0])
.then((file) => {
let reader = new FileReader();
reader.onload = () => {
this.setState({
thumbnailData: `${reader.result}`,
});
};
reader.readAsDataURL(file);
})
.catch((error) => console.error(error));
}}
/>
</Box>
{this.state.thumbnailData && (
<Box padding="m">
<img width={80} src={this.state.thumbnailData} alt="thumbnail" />
</Box>
)}
</FormField>
</SpaceBetween>
</Container>
</ColumnLayout>
),
},
]}
/>
)
}