250 lines
10 KiB
Python
250 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
import json
|
|
|
|
with open('/home/mdares/.node-red/flows.json', 'r') as f:
|
|
flows = json.load(f)
|
|
|
|
print("REWRITING STOP MODAL TO MATCH SCRAP MODAL PATTERN")
|
|
print("="*60)
|
|
|
|
for node in flows:
|
|
if node.get('id') == '1821c4842945ecd8':
|
|
template = node.get('format', '')
|
|
|
|
# STEP 1: Initialize stopPrompt in message handler (like scrapPrompt)
|
|
init_pos = template.find("if (!scope.scrapPrompt)")
|
|
if init_pos > 0:
|
|
# Add stopPrompt initialization right after scrapPrompt
|
|
scrap_init_end = template.find("};", init_pos) + 2
|
|
|
|
stop_init = '''
|
|
|
|
if (!scope.stopPrompt) {
|
|
scope.stopPrompt = {
|
|
show: false,
|
|
selectedCategory: null,
|
|
selectedReason: null,
|
|
notes: ''
|
|
};
|
|
}'''
|
|
|
|
template = template[:scrap_init_end] + stop_init + template[scrap_init_end:]
|
|
print("✅ Added stopPrompt initialization")
|
|
|
|
# STEP 2: Replace stop modal HTML to use ng-show (like scrap)
|
|
# Find current stop modal
|
|
stop_modal_start = template.find('<!-- Stop Reason Modal -->')
|
|
if stop_modal_start > 0:
|
|
# Find end of modal
|
|
stop_modal_end = template.find('</div>\n</div>', stop_modal_start + 100)
|
|
# Keep going until we find the actual end
|
|
count = 0
|
|
pos = stop_modal_start
|
|
while count < 3: # Modal has 3 nested divs
|
|
pos = template.find('</div>', pos + 1)
|
|
count += 1
|
|
stop_modal_end = pos + 6
|
|
|
|
# Replace entire modal with ng-show version
|
|
new_stop_modal = '''<!-- Stop Reason Modal -->
|
|
<div id="stopReasonModal" class="modal" ng-show="stopPrompt.show">
|
|
<div class="modal-card modal-card-stop">
|
|
<div class="modal-header-stop">
|
|
<span>⚠️ Production Stopped</span>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<p class="stop-question">Why are you stopping production?</p>
|
|
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1rem;">
|
|
<!-- Planned Stops Column -->
|
|
<div class="stop-category-section">
|
|
<div class="stop-category-header planned-header">
|
|
<span>📋 Planned</span>
|
|
</div>
|
|
<div class="stop-reasons-list">
|
|
<button class="stop-reason-option planned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'planned' && stopPrompt.selectedReason === 'Lunch break'}"
|
|
ng-click="selectStopReason('planned', 'Lunch break')">
|
|
🍽️ Lunch break
|
|
</button>
|
|
<button class="stop-reason-option planned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'planned' && stopPrompt.selectedReason === 'Scheduled break'}"
|
|
ng-click="selectStopReason('planned', 'Scheduled break')">
|
|
☕ Scheduled break
|
|
</button>
|
|
<button class="stop-reason-option planned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'planned' && stopPrompt.selectedReason === 'Shift change'}"
|
|
ng-click="selectStopReason('planned', 'Shift change')">
|
|
🔄 Shift change
|
|
</button>
|
|
<button class="stop-reason-option planned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'planned' && stopPrompt.selectedReason === 'Planned maintenance'}"
|
|
ng-click="selectStopReason('planned', 'Planned maintenance')">
|
|
🔧 Maintenance
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Unplanned Stops Column -->
|
|
<div class="stop-category-section">
|
|
<div class="stop-category-header unplanned-header">
|
|
<span>🚨 Unplanned</span>
|
|
</div>
|
|
<div class="stop-reasons-list">
|
|
<button class="stop-reason-option unplanned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'unplanned' && stopPrompt.selectedReason === 'Machine malfunction'}"
|
|
ng-click="selectStopReason('unplanned', 'Machine malfunction')">
|
|
⚙️ Malfunction
|
|
</button>
|
|
<button class="stop-reason-option unplanned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'unplanned' && stopPrompt.selectedReason === 'Material shortage'}"
|
|
ng-click="selectStopReason('unplanned', 'Material shortage')">
|
|
📦 Material
|
|
</button>
|
|
<button class="stop-reason-option unplanned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'unplanned' && stopPrompt.selectedReason === 'Quality issue'}"
|
|
ng-click="selectStopReason('unplanned', 'Quality issue')">
|
|
❌ Quality
|
|
</button>
|
|
<button class="stop-reason-option unplanned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'unplanned' && stopPrompt.selectedReason === 'Operator error'}"
|
|
ng-click="selectStopReason('unplanned', 'Operator error')">
|
|
👤 Operator
|
|
</button>
|
|
<button class="stop-reason-option unplanned"
|
|
ng-class="{selected: stopPrompt.selectedCategory === 'unplanned' && stopPrompt.selectedReason === 'Other'}"
|
|
ng-click="selectStopReason('unplanned', 'Other')">
|
|
❓ Other
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notes spanning both columns -->
|
|
<div class="stop-notes-section">
|
|
<label class="stop-notes-label">Additional notes (optional):</label>
|
|
<textarea class="stop-notes-input" ng-model="stopPrompt.notes"
|
|
placeholder="Enter any additional details..."></textarea>
|
|
</div>
|
|
|
|
<!-- Action buttons -->
|
|
<div class="modal-actions">
|
|
<button class="stop-reason-cancel" ng-click="stopPrompt.show = false">Cancel</button>
|
|
<button class="stop-reason-submit"
|
|
ng-disabled="!stopPrompt.selectedReason"
|
|
ng-click="submitStopReason()">
|
|
Submit
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>'''
|
|
|
|
template = template[:stop_modal_start] + new_stop_modal + template[stop_modal_end:]
|
|
print("✅ Replaced stop modal HTML with ng-show version")
|
|
|
|
# STEP 3: Rewrite functions to match scrap pattern
|
|
# Find and replace selectStopReason
|
|
select_fn_start = template.find('scope.selectStopReason')
|
|
if select_fn_start > 0:
|
|
select_fn_end = template.find('};', select_fn_start) + 2
|
|
|
|
new_select = '''scope.selectStopReason = function(category, reason) {
|
|
scope.stopPrompt.selectedCategory = category;
|
|
scope.stopPrompt.selectedReason = reason;
|
|
console.log('[SELECT] Reason:', category, reason);
|
|
};'''
|
|
|
|
template = template[:select_fn_start] + new_select + template[select_fn_end:]
|
|
print("✅ Simplified selectStopReason")
|
|
|
|
# Replace submitStopReason
|
|
submit_fn_start = template.find('scope.submitStopReason')
|
|
if submit_fn_start > 0:
|
|
submit_fn_end = template.find('};', template.find('};', submit_fn_start) + 1) + 2
|
|
|
|
new_submit = '''scope.submitStopReason = function() {
|
|
if (!scope.stopPrompt.selectedCategory || !scope.stopPrompt.selectedReason) {
|
|
return;
|
|
}
|
|
|
|
console.log('[STOP] Submitting reason:', scope.stopPrompt.selectedCategory, scope.stopPrompt.selectedReason);
|
|
|
|
// Send stop-reason to backend
|
|
scope.send({
|
|
action: 'stop-reason',
|
|
payload: {
|
|
category: scope.stopPrompt.selectedCategory,
|
|
reason: scope.stopPrompt.selectedReason,
|
|
notes: scope.stopPrompt.notes || ''
|
|
}
|
|
});
|
|
|
|
// Update UI - production stopped
|
|
scope.isProductionRunning = false;
|
|
|
|
// Close modal
|
|
scope.stopPrompt.show = false;
|
|
scope.stopPrompt.selectedCategory = null;
|
|
scope.stopPrompt.selectedReason = null;
|
|
scope.stopPrompt.notes = '';
|
|
};'''
|
|
|
|
template = template[:submit_fn_start] + new_submit + template[submit_fn_end:]
|
|
print("✅ Rewrote submitStopReason to match scrap pattern")
|
|
|
|
# STEP 4: Update toggleStartStop to set scope.stopPrompt.show = true
|
|
toggle_start = template.find('scope.toggleStartStop = function()')
|
|
if toggle_start > 0:
|
|
toggle_end = template.find('};', toggle_start) + 2
|
|
|
|
new_toggle = '''scope.toggleStartStop = function() {
|
|
if (scope.isProductionRunning) {
|
|
// STOP clicked - show prompt
|
|
console.log('[STOP] Showing stop prompt');
|
|
scope.stopPrompt.show = true;
|
|
scope.stopPrompt.selectedCategory = null;
|
|
scope.stopPrompt.selectedReason = null;
|
|
scope.stopPrompt.notes = '';
|
|
} else {
|
|
// START clicked
|
|
scope.send({ action: "start" });
|
|
scope.isProductionRunning = true;
|
|
}
|
|
};'''
|
|
|
|
template = template[:toggle_start] + new_toggle + template[toggle_end:]
|
|
print("✅ Updated toggleStartStop to use scope.stopPrompt.show")
|
|
|
|
# STEP 5: Update CSS for 2-column layout
|
|
css_pos = template.find('.stop-reasons-grid')
|
|
if css_pos > 0:
|
|
# Replace with stop-reasons-list for vertical layout
|
|
template = template.replace('.stop-reasons-grid {', '.stop-reasons-list {')
|
|
template = template.replace('grid-template-columns: 1fr 1fr;', 'display: flex; flex-direction: column;')
|
|
template = template.replace('gap: 0.75rem;', 'gap: 0.5rem;')
|
|
print("✅ Updated CSS for vertical button layout")
|
|
|
|
# Make modal more compact
|
|
template = template.replace('max-width: 700px;', 'max-width: 600px;')
|
|
template = template.replace('padding: 1.5rem;', 'padding: 1rem;')
|
|
|
|
node['format'] = template
|
|
break
|
|
|
|
with open('/home/mdares/.node-red/flows.json', 'w') as f:
|
|
json.dump(flows, f, indent=4)
|
|
|
|
print("\n" + "="*60)
|
|
print("✅ STOP MODAL NOW MATCHES SCRAP MODAL PATTERN")
|
|
print("="*60)
|
|
print("\nChanges:")
|
|
print(" 1. Uses ng-show (like scrap)")
|
|
print(" 2. Uses ng-click (like scrap)")
|
|
print(" 3. Uses ng-model for notes (like scrap)")
|
|
print(" 4. Uses ng-disabled for submit (like scrap)")
|
|
print(" 5. Simple scope functions (like scrap)")
|
|
print(" 6. 2-column layout with buttons in vertical lists")
|
|
print("\nRESTART NODE-RED - THIS WILL WORK LIKE SCRAP!")
|