Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cb30859
remove (Something wrong) default script content. Since we will not re…
monicagiraldochica Jan 7, 2026
9469f7a
created helper function to re-write only the lines that start with SB…
monicagiraldochica Jan 7, 2026
cd370fd
add comments in updateValues to make it clear where the script area i…
monicagiraldochica Jan 7, 2026
878ba73
fix script area issue that replaces all content instead of only the h…
monicagiraldochica Jan 7, 2026
72bfb2b
the space after the schebang is fixed for subsequent runs but not the…
monicagiraldochica Jan 7, 2026
1f2c978
fixed space after schebang in first run
monicagiraldochica Jan 7, 2026
d12dad5
form.erb edits
monicagiraldochica Jan 16, 2026
cb94527
Update form.erb
monicagiraldochica Jan 16, 2026
8efcd5a
Update form.erb
monicagiraldochica Jan 19, 2026
b9c278f
Change form.erb and .gitignore
monicagiraldochica Jan 20, 2026
7894774
Update form.erb
monicagiraldochica Jan 20, 2026
bd29972
Update form.erb, do the trimming in splitText
monicagiraldochica Jan 20, 2026
ea119ea
Replace old rebuildwithSbatchHeader with the new
monicagiraldochica Jan 20, 2026
b4ae073
remove console lines and comments
monicagiraldochica Jan 20, 2026
5e9e8a6
Messages to print in console for debugging
monicagiraldochica Jan 26, 2026
24e35ce
Give priority to currentBody in rebuildWithSbatchHeader
monicagiraldochica Jan 26, 2026
e58327b
Fix error, function called the wrong way
monicagiraldochica Jan 26, 2026
f01c8cc
remove mpirun test line from our rcc app
monicagiraldochica Jan 26, 2026
890a324
If body has an empty line, return empty body
monicagiraldochica Jan 26, 2026
e3f1e61
allow other directives depending on the scheduler selected in conf.yml
monicagiraldochica Jan 26, 2026
6112236
Remove console printing
monicagiraldochica Jan 26, 2026
c441293
remove MCW RCC files
monicagiraldochica Jan 27, 2026
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# General
.DS_Store
.swp

# bundle
Gemfile.lock
vendor/
.bundle
.bundle
4 changes: 1 addition & 3 deletions lib/history.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ def output_action_modal(action)
<div class="modal" id="#{id}" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-body" id="#{id}Body">
(Something wrong)
</div>
<div class="modal-body" id="#{id}Body"></div>
<div class="modal-footer">
<form action="#{form_action}" method="post" id="#{id}Form">
<input type="hidden" name="action" value="#{action}">
Expand Down
110 changes: 98 additions & 12 deletions views/form.erb
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@
<!-- Script Content Section -->
<div class="col py-3 d-flex flex-column">
<label id="label_<%= OC_SCRIPT_CONTENT %>" class="fw-semibold" for="<%= OC_SCRIPT_CONTENT %>"><%= @script_label %></label>
<textarea id="<%= OC_SCRIPT_CONTENT %>" name="<%= OC_SCRIPT_CONTENT %>" class="form-control mt-1 mb-3 flex-grow-1" tabindex="<%= @table_index %>" accesskey="s" oninput="ocForm.updateHeight(ocForm.scriptArea)" required>
(Something wrong)
</textarea>
<textarea id="<%= OC_SCRIPT_CONTENT %>" name="<%= OC_SCRIPT_CONTENT %>" class="form-control mt-1 mb-3 flex-grow-1" tabindex="<%= @table_index %>" accesskey="s" oninput="ocForm.updateHeight(ocForm.scriptArea)" required></textarea>
<!-- Submit Button -->
<% if @form_action == "confirm" || @form_action == "confirm-save" %>
<button class="btn btn-primary d-block w-100" id="<%= SUBMIT_BUTTON %>" type="button" data-bs-toggle="modal" data-bs-target="#modal-<%= SUBMIT_CONFIRM %>" tabindex="<%= @table_index + 1 %>">
Expand Down Expand Up @@ -93,12 +91,35 @@
</div>
</div>
</form>

<script>
var ocForm = ocForm || {};
ocForm.scriptArea = document.getElementById('<%= OC_SCRIPT_CONTENT %>');
ocForm.submitArea = document.getElementById('<%= SUBMIT_CONTENT %>');
</script>

<script src="form.js"></script>

<%
require "yaml"
require "erb"
require "pathname"

app_root = Pathname.new(__dir__).join("..").expand_path
conf_path = app_root.join("conf.yml.erb")

conf_hash =
if conf_path.exist?
rendered = ERB.new(conf_path.read).result(binding)
YAML.safe_load(rendered) || {}
else
{}
end

# If scheduler is missing, this becomes "slurm"
scheduler = conf_hash.fetch("scheduler", "slurm")
%>

<script>
// Executes functions that should run once.
ocForm.onceExec = function() {
Expand Down Expand Up @@ -157,9 +178,67 @@ document.addEventListener('keydown', function(event) {
}
});

// Split text into shebang, header (scheduler directive lines lines) and body
function splitText(text){
text = (text ?? '').toString();
const lines = text.split('\n');
let shebang = '';
const header = [];
const body = [];

// Choose a directive for the header depending on the scheduler selected in conf.yml.erb
const scheduler = "<%= scheduler.to_s %>".trim().toLowerCase();
let directive;
if (scheduler === "slurm") { directive = "#SBATCH"; }
else if (scheduler === "pbs" || scheduler === "pbspro" || scheduler === "torque") { directive = "#PBS"; }
else if (scheduler === "grid_engine" || scheduler === "sge") { directive = "#$"; }
else if (scheduler === "lsf") { directive = "#BSUB"; }
else { directive = "#SBATCH"; }

for (const line of lines) {
const trimmed = line.trim();
if (!shebang && trimmed.startsWith("#!")) { shebang = trimmed; }
else if (trimmed.startsWith(directive)) { header.push(trimmed); }
else if (body.at(-1)!="" || trimmed!="") { body.push(trimmed); }
}

if (body.length === 1 && body[0] === "") return { shebang, header, body: [] };

return { shebang, header, body }
}

// Rebuild script area content by replacing only the content of the header
function rebuildWithSbatchHeader(currentText, headerText) {
const { shebang: currentShebang, header: currentHeader, body: currentBody } = splitText(currentText);
const { shebang: renderedShebang, header: renderedHeader, body: renderedBody } = splitText(headerText);

const finalShebang = renderedShebang ? renderedShebang : currentShebang || '';
const finalHeader = renderedHeader?.length>0 ? renderedHeader : currentHeader?.length>0 ? currentHeader : [];

const filteredRenderedBody = renderedBody.filter(item => item.trim() !== "");
const filteredCurrentBody = currentBody.filter(item => item.trim() !== "");
let finalBody;
if (filteredRenderedBody.length === 0 && filteredCurrentBody.length === 0) { finalBody = []; }
else if (filteredCurrentBody.length>0) { finalBody = currentBody; } // Give priority to currentBody if not empty
else { finalBody = renderedBody; }
if (finalBody[0] === "") { finalBody.shift(); } // Remove first line if empty (it will be introduced if hasTopSection)
if (finalBody.at(-1) === "") { finalBody.pop(); } // Remove empty line at the end

const hasTopSection = (finalShebang?.trim()!=='') || (finalHeader.length>0);
const combined = [
...(finalShebang ? [finalShebang] : []),
...finalHeader,
...(hasTopSection && finalBody.length>0 ? [""] : []),
...finalBody
];

return combined.join("\n");
}

ocForm.isFirst = true;
ocForm.multiSelectDisabledIndexes = {};
ocForm.updateValues = function(fromId) {
console.group("updateValues");
let scriptValues = [];
let submitValues = [];
ocForm.initDynamicWidget(fromId);
Expand All @@ -170,25 +249,32 @@ ocForm.updateValues = function(fromId) {
ocForm.onceExec();
ocForm.updateScriptContents(scriptValues);
ocForm.updateSubmitContents(submitValues);
ocForm.scriptArea.value = ocForm.isScriptCache() ? ocForm.loadScriptCache() : Object.values(scriptValues).join('\n');

// Overwrite of script textarea (first run)
const newHeaderFirst = Object.values(scriptValues).join('\n');
const baseTextFirst = ocForm.isScriptCache() ? ocForm.loadScriptCache() : (ocForm.scriptArea.value || '');
ocForm.scriptArea.value = rebuildWithSbatchHeader(baseTextFirst, newHeaderFirst);

// Overwrite of submit textarea (first run)
ocForm.submitArea.value = ocForm.isSubmitCache() ? ocForm.loadSubmitCache() : Object.values(submitValues).join('\n');
}

else {
ocForm.updateScriptContents(scriptValues);
ocForm.updateSubmitContents(submitValues);
ocForm.scriptArea.value = Object.values(scriptValues).join('\n');

// Overwrite of script textarea (subsequent runs)
const newHeaderNext = Object.values(scriptValues).join('\n');
ocForm.scriptArea.value = rebuildWithSbatchHeader(ocForm.scriptArea.value || '', newHeaderNext);

// Overwrite of submit textarea (subsequent runs)
ocForm.submitArea.value = Object.values(submitValues).join('\n')
}

// Add a newline if it is not the last one
//if (!ocForm.scriptArea.value.endsWith('\n')){
// ocForm.scriptArea.value += '\n';
//}
//if (!ocForm.submitArea.value.endsWith('\n')){
// ocForm.submitArea.value += '\n';
//}
// Height adjustments
ocForm.updateHeight(ocForm.scriptArea);
ocForm.updateHeight(ocForm.submitArea);
console.groupEnd();
};

window.onload = ocForm.updateValues();
Expand Down