From 29f8de63fd741757559113734c81fd56d86e5ca5 Mon Sep 17 00:00:00 2001 From: Brian Read Date: Sat, 6 Sep 2025 08:23:59 +0100 Subject: [PATCH] Fix error on json5 lint fail and add AdminLTE theme generated templates --- Targets/Example1/AdminLTE/_ex1_PARAMS.html.ep | 53 +++ Targets/Example1/AdminLTE/_ex1_TABLE.html.ep | 57 ++++ Targets/Example1/AdminLTE/example1.css | 20 ++ Targets/Example1/AdminLTE/example1.html.ep | 58 ++++ Targets/Example1/AdminLTE/example1.js | 5 + Targets/Example1/Example1-Custom.pm | 192 +++++++++++ Targets/Example1/Example1.pm | 321 ++++++++++++++++++ Targets/Example1/_ex1_PARAMS.html.ep | 50 +++ Targets/Example1/_ex1_TABLE.html.ep | 54 +++ Targets/Example1/example1.css | 20 ++ Targets/Example1/example1.html.ep | 56 +++ Targets/Example1/example1.js | 5 + Targets/Example1/example1_en.lex | 18 + copySM2.sh | 15 +- json5/example1.json5 | 48 +++ lex_scan.py | 4 +- sm2gen.py | 286 ++++++++-------- 17 files changed, 1116 insertions(+), 146 deletions(-) create mode 100644 Targets/Example1/AdminLTE/_ex1_PARAMS.html.ep create mode 100644 Targets/Example1/AdminLTE/_ex1_TABLE.html.ep create mode 100644 Targets/Example1/AdminLTE/example1.css create mode 100644 Targets/Example1/AdminLTE/example1.html.ep create mode 100644 Targets/Example1/AdminLTE/example1.js create mode 100644 Targets/Example1/Example1-Custom.pm create mode 100644 Targets/Example1/Example1.pm create mode 100644 Targets/Example1/_ex1_PARAMS.html.ep create mode 100644 Targets/Example1/_ex1_TABLE.html.ep create mode 100644 Targets/Example1/example1.css create mode 100644 Targets/Example1/example1.html.ep create mode 100644 Targets/Example1/example1.js create mode 100644 Targets/Example1/example1_en.lex mode change 100755 => 100644 copySM2.sh create mode 100644 json5/example1.json5 diff --git a/Targets/Example1/AdminLTE/_ex1_PARAMS.html.ep b/Targets/Example1/AdminLTE/_ex1_PARAMS.html.ep new file mode 100644 index 0000000..330bca6 --- /dev/null +++ b/Targets/Example1/AdminLTE/_ex1_PARAMS.html.ep @@ -0,0 +1,53 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +%# +%# Specific for AdminLTE theme +%# +
+%# + % if (config->{debug} == 1) { +
+			%= dumper $ex1_data
+		
+ % } + % my $btn = l('ex1_SAVE'); + % $c->param(Selected => undef); #This may need deleting for a params panel - only needed for a table + + %= form_for "example1u" => (method => 'POST') => begin + % param 'trt' => $ex1_data->{trt} unless param 'trt'; + %= hidden_field 'trt' => $ex1_data->{trt} + %# Inputs etc in here. +
+

<%=l('ex1_Example_Contrib')%>


+
+

<%=l('ex1_Manage_Ibay_settings:')%>


+
+

+ %=l('ex1_These_parameters_will_be_effective') + +


+
+ %=l('ex1_Information_Bay_name') +
+ % param 'IbayName' => $ex1_data->{IbayName} unless param 'IbayName'; + %= text_field 'IbayName', size => '50', class => 'textinput IbayName' , pattern=>'.*' , placeholder=>'IbayName', title =>'Pattern regex mismatch', id => 'IbayName_text' +
+

+
+ %=l('ex1_Share_owner_Group') +
+ % my @ShareOwnerGrp_options = [['Write = admin, Read = group' => 'All'], ['Write = group, Read = everyone' => 'Read:All-Write:Grp']]; + % param 'ShareOwnerGrp' => $ex1_data->{ShareOwnerGrp} unless param 'ShareOwnerGrp'; + %= select_field 'ShareOwnerGrp' => @ShareOwnerGrp_options, class => 'input', id => 'ShareOwnerGrp_select' +
+

+ %# .... + %# Probably finally by a submit. + %= submit_button $btn, class => 'action' + %end +
+
\ No newline at end of file diff --git a/Targets/Example1/AdminLTE/_ex1_TABLE.html.ep b/Targets/Example1/AdminLTE/_ex1_TABLE.html.ep new file mode 100644 index 0000000..d5d4b58 --- /dev/null +++ b/Targets/Example1/AdminLTE/_ex1_TABLE.html.ep @@ -0,0 +1,57 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +%# +%# Specific for AdminLTE theme +%# +
+%# + % if (config->{debug} == 1) { +
+			%= dumper $ex1_data
+		
+ % } + % my $btn = l('ex1_SAVE'); + % $c->param(Selected => undef); #This may need deleting for a params panel - only needed for a table + + %= form_for "example1u" => (method => 'POST') => begin + % param 'trt' => $ex1_data->{trt} unless param 'trt'; + %= hidden_field 'trt' => $ex1_data->{trt} + %# Inputs etc in here. +
+

<%=l('ex1_NFS_Share_Contrib')%>


+
+

<%=l('ex1_Manage_NFS_Ibay_settings:')%>


+
+
+ + + + + + + + + + % my $control_data = $c->stash('ibays'); + % foreach my $row (@$control_data) { + + + + + + + %} + +
<%=l('ex1_Name')%><%=l('ex1_Description')%><%=l('ex1_Status')%><%=l('ex1_Action')%>
<%=$c->render_to_string(inline=>$row->{'Name'})%><%=$c->render_to_string(inline=>$row->{'Description'})%><%=$c->render_to_string(inline=>$row->{'flag'})%><%=$c->render_to_string(inline=>$row->{'Modify'})%>
+

+ + %# .... + %# Probably finally by a submit. + %= submit_button $btn, class => 'action' + %end +
+
\ No newline at end of file diff --git a/Targets/Example1/AdminLTE/example1.css b/Targets/Example1/AdminLTE/example1.css new file mode 100644 index 0000000..b16f6dd --- /dev/null +++ b/Targets/Example1/AdminLTE/example1.css @@ -0,0 +1,20 @@ +/* +Generated by: SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +*/ +.Example1-panel {} +.name {} +.rout {} +.head {} +.subh {} +.para1 {} +.text1 {} +.sele2 {} +.name {} +.rout {} +.head {} +.subh {} +.next {} +.tabl1 {} +thead .tabl1 {} +tbody .tabl1 {} +.next {} diff --git a/Targets/Example1/AdminLTE/example1.html.ep b/Targets/Example1/AdminLTE/example1.html.ep new file mode 100644 index 0000000..382b271 --- /dev/null +++ b/Targets/Example1/AdminLTE/example1.html.ep @@ -0,0 +1,58 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +%# +%# AdminLTE specific layout +%# +% layout 'default', title => "Sme server 2 - Example 1", share_dir => './'; +%# css specific to this panel: +% content_for 'module' => begin +%= stylesheet '/css/example1.css' +%= javascript '/js/example1.js' +
+ + % if (config->{debug} == 1) { +
+		%= dumper $c->current_route
+		%= dumper $ex1_data->{trt}
+	
+ % } + +

<%=$title%>

+ + % if ( stash('modul')) { + %= $c->render_to_string(inline => stash('modul') ); + % } + + %if ($c->stash('first')) { +
+ %=$c->render_to_string(inline =>$c->l($c->stash('first'))) +
+ + %} elsif ($c->stash('success')) { +
+ %= $c->l($c->stash('success')); +
+ + %} elsif ($c->stash('error')) { +
+ %= $c->l($c->stash('error')); +
+ %} + + %#Routing to partials according to trt parameter. + %#This ought to be cascading if/then/elsif, but is easier to just stack the if/then's rather like a case statement' + +
+ % if ($ex1_data->{trt} eq "PARAMS") { + %= include 'partials/_ex1_PARAMS' + %} + +
+ % if ($ex1_data->{trt} eq "TABLE") { + %= include 'partials/_ex1_TABLE' + %} + +
+ +
+%end \ No newline at end of file diff --git a/Targets/Example1/AdminLTE/example1.js b/Targets/Example1/AdminLTE/example1.js new file mode 100644 index 0000000..49ddfcb --- /dev/null +++ b/Targets/Example1/AdminLTE/example1.js @@ -0,0 +1,5 @@ +// +//Generated by: SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +// +$(document).ready(function() { +}); diff --git a/Targets/Example1/Example1-Custom.pm b/Targets/Example1/Example1-Custom.pm new file mode 100644 index 0000000..64c8059 --- /dev/null +++ b/Targets/Example1/Example1-Custom.pm @@ -0,0 +1,192 @@ +# +# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +# +# +# Routines to be edited by the developer to provide content and validation for parameters +# and provison of the control data for table(s) +# +use esmith::util; +use esmith::util::network; +use esmith::ConfigDB::UTF8; +use esmith::AccountsDB; +use esmith::NetworksDB::UTF8; +use esmith::HostsDB; +use esmith::DomainsDB::UTF8; + +use constant FALSE => 0; +use constant TRUE => 1; + + +#The most common ones - open DB when required. +#my $cdb; +#my $adb; +#my $ndb; +#my $hdb; +#my $ddb; + +#The most common ones - you might want to use these if you need to make sure that the DB is refreshed. +#$cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db"); +#$adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db"); +#$ndb = esmith::NetworksDB->open() || die("Couldn't open Network db"); +#$hdb = esmith::HostsDB::UTF8->open() || die("Couldn't open Hosts db"); +#$ddb = esmith::DomainsDB::UTF8->open() || die("Couldn't open Domains db"); + + +# Validation routines - parameters for each panel + + sub validate_PARAMS { + my $c = shift; + my $ex1_data = shift; #Data hash as parameter + # Validation for each field + my $ret = ''; + + if (! TRUE) #validate $c->param('IbayName') + {$ret .= 'Validation for IbayName failed';} + if (! TRUE) #validate $c->param('ShareOwnerGrp') + {$ret .= 'Validation for ShareOwnerGrp failed';} + if ($ret eq '') {$ret = 'ok';} + return $ret; + } + + sub validate_TABLE { + my $c = shift; + my $ex1_data = shift; #Data hash as parameter + # Validation for each field + my $ret = ''; + + if ($ret eq '') {$ret = 'ok';} + return $ret; + } + + +# Get singleton data for each panel + + sub get_data_for_panel_PARAMS { + # Return a hash with the fields required which will be loaded into the shared data + my $c = shift; + my %ret = ( + 'Data1'=>'Data for PARAMS', #Example + # fields from Inputs in PARAMS $fields['PARAMS'] + 'IbayName'=>'IbayName contents', + 'ShareOwnerGrp'=>'ShareOwnerGrp contents', + + ); + return %ret; + } + + sub get_data_for_panel_TABLE { + # Return a hash with the fields required which will be loaded into the shared data + my $c = shift; + my %ret = ( + 'Data1'=>'Data for TABLE', #Example + # fields from Inputs in TABLE $fields['TABLE'] + + ); + return %ret; + } + + + +# Get control data for table(s) + + # Define a constant hash for field name mapping + use constant ibays_FIELD_MAPPING => ( + 'Name' => 'Source-for-Name', + 'Description' => 'Source-for-Description', + 'flag' => 'Source-for-flag', + 'Modify' => 'Source-for-Modify' + #'target_field2' => 'source_field2', + # Add more mappings as needed + ); + +sub actual_ibays { + my $c = shift; + my @ret = (); + # Actual code for extracting ibays + return @ret; +} + +sub get_ibays { + # Return an array of hashes of the contents for each row and column for ibays + my $c = shift; + my @source_records = $c->actual_ibays(); + my @transformed_records; + my %Field_Mapping = ibays_FIELD_MAPPING(); + # Iterate over each record in the source array + for my $source_record (@source_records) { + my %transformed_record; + # Iterate over each key-value pair in the $Field_Mapping constant + while (my ($target, $source) = each %Field_Mapping) { + # Check if the source field exists in the source record + if (exists $source_record->{$source}) { + # Assign the source field value to the target field in the transformed record + $transformed_record{$target} = $source_record->{$source}; + } + } + # Add transformed record to the array if it's not empty + push @transformed_records, \%transformed_record if %transformed_record; + } + return \@transformed_records; +} + + + +# Return hash with values from row in which link clicked on table + + sub get_selected_PARAMS { + my $c = shift; + my $selected = shift; #Parameter is name of selected row. + my $is_new_record = shift; #Indicates new record required (defaults) + my %ret = (); + #gather the values here + return %ret; + } + + sub get_selected_TABLE { + my $c = shift; + my $selected = shift; #Parameter is name of selected row. + my $is_new_record = shift; #Indicates new record required (defaults) + my %ret = (); + #gather the values here + return %ret; + } + + +#after sucessful modify or create or whatever and submit then perfom (if the params validate) + + sub perform_PARAMS { + my $c = shift; + my $ex1_data = shift; #Data hash as parameter + my $ret = ''; + my $db = $cdb; #maybe one of the others + my $dbkey = 'ChangeThis'; + # To make it write to DB as comment, delete this (regex) string in each if statement "TRUE\) \#copy or perform with value: .* e.g." + + if (! TRUE) #copy or perform with value: IbayName e.g. $db->set_prop($dbkey,'IbayName',$c->param('IbayName'),type=>'service')) + {$ret .= 'Perform/save failed for IbayName';} + if (! TRUE) #copy or perform with value: ShareOwnerGrp e.g. $db->set_prop($dbkey,'ShareOwnerGrp',$c->param('ShareOwnerGrp'),type=>'service')) + {$ret .= 'Perform/save failed for ShareOwnerGrp';} + if ($ret eq '') {$ret = 'ok';} + return $ret; + } + + sub perform_TABLE { + my $c = shift; + my $ex1_data = shift; #Data hash as parameter + my $ret = ''; + my $db = $cdb; #maybe one of the others + my $dbkey = 'ChangeThis'; + # To make it write to DB as comment, delete this (regex) string in each if statement "TRUE\) \#copy or perform with value: .* e.g." + + if ($ret eq '') {$ret = 'ok';} + return $ret; + } + + +sub create_link{ + # WIP + my ($c,$route, $panel, $index) = @_; + my $link = "$route?trt=$panel&Selected=$index"; + return $link; +} +1; \ No newline at end of file diff --git a/Targets/Example1/Example1.pm b/Targets/Example1/Example1.pm new file mode 100644 index 0000000..2461f35 --- /dev/null +++ b/Targets/Example1/Example1.pm @@ -0,0 +1,321 @@ +package SrvMngr::Controller::Example1; +# +# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +# Remember that each route must be unique (else they just overwrite each other). +# you cannot have get and post on the same name and url. +# +#---------------------------------------------------------------------- +# heading : Network +# description : Example 1 +# navigation : 2000 400 +# +# name : example1, method : get, url : /example1, ctlact : Example1#main +# name : example1u, method : post, url : /example1u, ctlact : Example1#do_update +# name : example1d, method : get, url : /example1d, ctlact : Example1#do_display +# +# routes : end +# +# Documentation: https://wiki.contribs.org/Example1 +#---------------------------------------------------------------------- + +# +# Scheme of things: +# +# TBA!! + +use strict; +use warnings; +use Mojo::Base 'Mojolicious::Controller'; + +use constant FALSE => 0; +use constant TRUE => 1; + +use Locale::gettext; +use SrvMngr::I18N; +use SrvMngr qw(theme_list init_session); + +use Data::Dumper; + +use esmith::util; +use esmith::util::network; +use esmith::ConfigDB::UTF8; +use esmith::AccountsDB; +use esmith::NetworksDB::UTF8; +use esmith::HostsDB; +use esmith::DomainsDB::UTF8; + +our $cdb; +our $adb; +our $ndb; +our $hdb; +our $ddb; + +our %ex1_data; + +require '/usr/share/smanager/lib/SrvMngr/Controller/Example1-Custom.pm'; #The code that is to be added by the developer + +sub main { +# +# Initial entry - route is "/" +# +#set initial panel +#for initial panel: + #Specifiy panel to enter + #load up _data hash with DB fields + #load up stash with pointer(s) to control fields hash(= get-)) + #and a pointer to the prefix_data hash +#render initial panel + + my $c = shift; + $c->app->log->info( $c->log_req ); + + #The most common ones - you might want to delete some of these if they are not used. + $cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db"); + $adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db"); + $ndb = esmith::NetworksDB->open() || die("Couldn't open Network db"); + $hdb = esmith::HostsDB::UTF8->open() || die("Couldn't open Hosts db"); + $ddb = esmith::DomainsDB::UTF8->open() || die("Couldn't open Domains db"); + + %ex1_data = (); + my $title = $c->l('ex1_Example_1'); + my $modul = ''; + + $ex1_data{'trt'} = 'TABLE'; + + #Load any DB entries into the _data area so as they are preset in the form + # which DB - this only really works if the initial panel is a PARAMS type panel and not a TABLE + my $db = $cdb; #pickup local or global db or Default to config + + + $c->do_display($ex1_data{'trt'}); + +} + +# Post request with params - submit from the form +sub do_update { +# +# Return after submit pushed on panel (this is a post) - route is "/u" +# parameters in the params hash. +# +#load up all params into prefix_data hash: +#By panel (series of if statements - only one executed): + #call validate-PANEL() - return ret = ok or error message + +#if validation not ok: + #render back to current panel with error message in stash +#otherwise: + #By panel (series of if statements - only one executed): + #do whatever is required: call perform-PANEL() - return 'ok' or Error Message + #call signal-event for any global actions specified (check it exists - error and continue?) + #if action smeserver--update exists + #signal_event smeserver--update + #call signal-event for any specific actions for thids panel (check it exists first - error and continue) + #set success in stash + #if no "nextpanel" entry: + #set firstpanel + #else + #set nextpanel + #call render + + my $c = shift; + $c->app->log->info($c->log_req); + my $modul = ''; + + #The most common ones - you might want to delete some of these if they are not used. + $cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db"); + $adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db"); + $ndb = esmith::NetworksDB->open() || die("Couldn't open Network db"); + $hdb = esmith::HostsDB::UTF8->open() || die("Couldn't open Hosts db"); + $ddb = esmith::DomainsDB::UTF8->open() || die("Couldn't open Domains db"); + + my $title = $c->l('ex1_Example_1'); + + # Accessing all POST/GET parameters + my $params = $c->req->params->to_hash; + + # Get number of POST parameters + #my $num_params = keys scaler %$params; + + #Params are available in the hash "params" - copy to the prefix_data hash + #while (my ($key, $value) = each %{$c->req->params->to_hash}) { + # $ex1_data{$key} = $value; + #} + + # the value of trt will tell you which panel has returned + my $trt = $c->param('trt') || 'TABLE'; #hidden control on every form. + my $ret = 'ok'; + + #Validate the parameters in a custom sub one for each panel (although only one of these will be executed) + my $thispanel; + + if ($trt eq 'PARAMS'){ + #Validate form parameters for panel PARAMS + $ret = $c->validate_PARAMS(\%ex1_data); + $thispanel = 'PARAMS'; + } + + if ($trt eq 'TABLE'){ + #Validate form parameters for panel TABLE + $ret = $c->validate_TABLE(\%ex1_data); + $thispanel = 'TABLE'; + } + + if ($ret ne 'ok'){ + $c->stash(error => $c->l($ret)); + $c->do_display($thispanel); + } else { + #Do whatever is needed, including writing values to the DB + + + if ($trt eq 'PARAMS'){ + #do whatever is required ... + $ret = $c->perform_PARAMS(\%ex1_data); + if ($ret ne 'ok') { + # return to the panel with error message + $c->stash(error => $c->l($ret)); + $c->stash( + title => $title, + modul => $modul, + ex1_data => \%ex1_data + ); + $c->render(template => "example1"); + return + } else { + $c->stash( success => $c->l('ex1_PARAMS_panel_action_was_successful')); #A bit bland - edit it in the lex file + } + } + + if ($trt eq 'TABLE'){ + #do whatever is required ... + $ret = $c->perform_TABLE(\%ex1_data); + if ($ret ne 'ok') { + # return to the panel with error message + $c->stash(error => $c->l($ret)); + $c->stash( + title => $title, + modul => $modul, + ex1_data => \%ex1_data + ); + $c->render(template => "example1"); + return + } else { + $c->stash( success => $c->l('ex1_TABLE_panel_action_was_successful')); #A bit bland - edit it in the lex file + } + } + + # and call any signal-events needed + #TBD + # Setup shared data and call panel + if ('none' eq 'none') { + $ex1_data{'trt'} = 'TABLE'; + } else { + $ex1_data{'trt'} = 'none'; + } + $c->do_display($ex1_data{'trt'}); + } +} + +sub do_display { +# +# Return after link clicked in table (this is a get) - route is "/d" +# Expects ?trt=PANEL&selected="TableRowName" plus any other required +# +# OR it maybe a post from the main panel to add a new record +# +#load up all supplied params into prefix_data hash +#call get-selected-PANEL() - returns hash of all relevent parameters +#load up returned hash into prefix_data +#render - to called panel + + my ($c,$trt) = @_; + $c->app->log->info($c->log_req); + + #The most common ones - you might want to delete some of these if they are not used. + $cdb = esmith::ConfigDB::UTF8->open() || die("Couldn't open config db"); + $adb = esmith::AccountsDB->open() || die("Couldn't open Accounts db"); + $ndb = esmith::NetworksDB->open() || die("Couldn't open Network db"); + $hdb = esmith::HostsDB::UTF8->open() || die("Couldn't open Hosts db"); + $ddb = esmith::DomainsDB::UTF8->open() || die("Couldn't open Domains db"); + + my $title = $c->l('ex1_Example_1'); + my $modul = ''; + + # Accessing all parameters + my $params = $c->req->params->to_hash; + + # Get number of parameters + my $num_params = keys %$params; + + #Tag as Post or Get (ie. create new entry or edit existing one + my $is_new_record = ($c->req->method() eq 'POST'); + + #Params are available in the hash "params" - copy to the prefix_data hash + #while (my ($key, $value) = each %{$c->req->params->to_hash}) { + # $ex1_data{$key} = $value; + #} + + # the value of trt will tell you which panel has returned + if (! $trt){ + $trt = $c->param('trt') || 'TABLE'; #Indicates where to go now + } + + # Now add in the params from the selected row from the table + + my %selectedrow; + + if ($trt eq 'PARAMS'){ + #Validate Get selected row (if applicable) PARAMS + %selectedrow = $c->get_selected_PARAMS($ex1_data{'Selected'},$is_new_record); + } + + if ($trt eq 'TABLE'){ + #Validate Get selected row (if applicable) TABLE + %selectedrow = $c->get_selected_TABLE($ex1_data{'Selected'},$is_new_record); + } + + + #Copy in the selected row params to the prefix_data hash to pass to the panel + while (my ($key, $value) = each %selectedrow){ + $ex1_data{$key} = $value; + } + # Where to go now + $ex1_data{'trt'} = $trt; + + # Set up other shared data according to the panel to go to + + if ($trt eq 'PARAMS'){ + # pickup any other contents needed and load them into hash shared with panel + my %returned_hash; + # subroutine returns a hash directly + %returned_hash = $c->get_data_for_panel_PARAMS(); + # Copy each key-value pair from the returned hash to the prefix data hash + while (my ($key, $value) = each %returned_hash) { + $ex1_data{$key} = $value; + } + } + + if ($trt eq 'TABLE'){ + # pickup any other contents needed and load them into hash shared with panel + my %returned_hash; + # subroutine returns a hash directly + %returned_hash = $c->get_data_for_panel_TABLE(); + # Copy each key-value pair from the returned hash to the prefix data hash + while (my ($key, $value) = each %returned_hash) { + $ex1_data{$key} = $value; + } + } + + + # and table control fields + $c->stash(ibays=>$c->get_ibays()); + + + # Data for panel + $c->stash( + title => $title, + modul => $modul, + ex1_data => \%ex1_data + ); + $c->render(template => "example1"); +} +1; \ No newline at end of file diff --git a/Targets/Example1/_ex1_PARAMS.html.ep b/Targets/Example1/_ex1_PARAMS.html.ep new file mode 100644 index 0000000..6bee400 --- /dev/null +++ b/Targets/Example1/_ex1_PARAMS.html.ep @@ -0,0 +1,50 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +%# +
+%# + % if (config->{debug} == 1) { +
+			%= dumper $ex1_data
+		
+ % } + % my $btn = l('SAVE'); + % $c->param(Selected => undef); #This may need deleting for a params panel - only needed for a table + + %= form_for "example1u" => (method => 'POST') => begin + % param 'trt' => $ex1_data->{trt} unless param 'trt'; + %= hidden_field 'trt' => $ex1_data->{trt} + %# Inputs etc in here. + +

<%=l('Example Contrib')%>

+ +

<%=l('Manage Ibay settings:')%>

+ +

+ %=l('These parameters will be effective only if the share is enabled. The share is in /home/e-smith/files/ibays//files') +

+ +

+ %=l('ex1_Information Bay name') + + % param 'IbayName' => $ex1_data->{IbayName} unless param 'IbayName'; + %= text_field 'IbayName', size => '50', class => 'textinput IbayName' , pattern=>'.*' , placeholder=>'IbayName', title =>'Pattern regex mismatch', id => 'IbayName_text' +

+ +

+ %=l('ex1_Share owner Group') + + % my @ShareOwnerGrp_options = [['Write = admin, Read = group' => 'All'], ['Write = group, Read = everyone' => 'Read:All-Write:Grp']]; + % param 'ShareOwnerGrp' => $ex1_data->{ShareOwnerGrp} unless param 'ShareOwnerGrp'; + %= select_field 'ShareOwnerGrp' => @ShareOwnerGrp_options, class => 'input', id => 'ShareOwnerGrp_select' +

+ + %# .... + %# Probably finally by a submit. + %= submit_button $btn, class => 'action' + %end +
\ No newline at end of file diff --git a/Targets/Example1/_ex1_TABLE.html.ep b/Targets/Example1/_ex1_TABLE.html.ep new file mode 100644 index 0000000..d2b69cb --- /dev/null +++ b/Targets/Example1/_ex1_TABLE.html.ep @@ -0,0 +1,54 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +%# +
+%# + % if (config->{debug} == 1) { +
+			%= dumper $ex1_data
+		
+ % } + % my $btn = l('SAVE'); + % $c->param(Selected => undef); #This may need deleting for a params panel - only needed for a table + + %= form_for "example1u" => (method => 'POST') => begin + % param 'trt' => $ex1_data->{trt} unless param 'trt'; + %= hidden_field 'trt' => $ex1_data->{trt} + %# Inputs etc in here. + +

<%=l('NFS Share Contrib')%>

+ +

<%=l('Manage NFS Ibay settings:')%>

+ +
+ + + + + + + + + + % my $control_data = $c->stash('ibays'); + % foreach my $row (@$control_data) { + + + + + + + %} + +
<%=l('Name')%><%=l('Description')%><%=l('Status')%><%=l('Action')%>
<%=$c->render_to_string(inline=>$row->{'Name'})%><%=$c->render_to_string(inline=>$row->{'Description'})%><%=$c->render_to_string(inline=>$row->{'flag'})%><%=$c->render_to_string(inline=>$row->{'Modify'})%>
+ + + %# .... + %# Probably finally by a submit. + %= submit_button $btn, class => 'action' + %end +
\ No newline at end of file diff --git a/Targets/Example1/example1.css b/Targets/Example1/example1.css new file mode 100644 index 0000000..b16f6dd --- /dev/null +++ b/Targets/Example1/example1.css @@ -0,0 +1,20 @@ +/* +Generated by: SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +*/ +.Example1-panel {} +.name {} +.rout {} +.head {} +.subh {} +.para1 {} +.text1 {} +.sele2 {} +.name {} +.rout {} +.head {} +.subh {} +.next {} +.tabl1 {} +thead .tabl1 {} +tbody .tabl1 {} +.next {} diff --git a/Targets/Example1/example1.html.ep b/Targets/Example1/example1.html.ep new file mode 100644 index 0000000..a7e5f48 --- /dev/null +++ b/Targets/Example1/example1.html.ep @@ -0,0 +1,56 @@ +%# +%# Generated by SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +%# +% layout 'default', title => "Sme server 2 - Example 1", share_dir => './'; +%# css specific to this panel: +% content_for 'module' => begin +%= stylesheet '/css/example1.css' +%= javascript '/js/example1.js' +
+ + % if (config->{debug} == 1) { +
+		%= dumper $c->current_route
+		%= dumper $ex1_data->{trt}
+	
+ % } + +

<%=$title%>

+ + % if ( stash('modul')) { + %= $c->render_to_string(inline => stash('modul') ); + % } + + %if ($c->stash('first')) { +

+ %=$c->render_to_string(inline =>$c->l($c->stash('first'))) +

+ + %} elsif ($c->stash('success')) { +
+ %= $c->l($c->stash('success')); +
+
+ + %} elsif ($c->stash('error')) { +
+ %= $c->l($c->stash('error')); +
+
+ %} + + %#Routing to partials according to trt parameter. + %#This ought to be cascading if/then/elsif, but is easier to just stack the if/then's rather like a case statement' + + % if ($ex1_data->{trt} eq "PARAMS") { + %= include 'partials/_ex1_PARAMS' + %} + + % if ($ex1_data->{trt} eq "TABLE") { + %= include 'partials/_ex1_TABLE' + %} + + + +
+%end \ No newline at end of file diff --git a/Targets/Example1/example1.js b/Targets/Example1/example1.js new file mode 100644 index 0000000..49ddfcb --- /dev/null +++ b/Targets/Example1/example1.js @@ -0,0 +1,5 @@ +// +//Generated by: SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +// +$(document).ready(function() { +}); diff --git a/Targets/Example1/example1_en.lex b/Targets/Example1/example1_en.lex new file mode 100644 index 0000000..350c5f2 --- /dev/null +++ b/Targets/Example1/example1_en.lex @@ -0,0 +1,18 @@ +# +# Generated by SM2Gen version: SM2Gen version:0.9(20Jan2025) Chameleon version:4.5.4 On Python:3.12.3 at 2025-09-06 06:03:54 +# +'ex1_PARAMS_panel_action_was_successful' => 'PARAMS panel action was successful', +'ex1_Example_1' => 'Example 1', +'ex1_Description' => 'Description', +'ex1_Status' => 'Status', +'ex1_Action' => 'Action', +'ex1_Name' => 'Name', +'ex1_Information_Bay_name' => 'Information Bay name', +'ex1_Example_Contrib' => 'Example control', +'ex1_NFS_Share_Contrib' => 'NFS Share control', +'ex1_These_parameters_will_be_effective' => 'These parameters will be effective only if the share is enabled The share is in /home/e-smith/files/ibays//files', +'ex1_Manage_NFS_Ibay_settings:' => 'Manage NFS bay settings', +'ex1_Share_owner_Group' => 'Share owner Group', +'ex1_SAVE' => 'Save', +'ex1_TABLE_panel_action_was_successful' => 'TABLE panel action was successful', +'ex1_Manage_Ibay_settings:' => 'Manage bay settings', diff --git a/copySM2.sh b/copySM2.sh old mode 100755 new mode 100644 index ebb1e31..52e1dc9 --- a/copySM2.sh +++ b/copySM2.sh @@ -26,15 +26,24 @@ mkdir -p $REMOTE/lib/SrvMngr/Controller mkdir -p $REMOTE/themes/default/templates/partials/ mkdir -p $REMOTE/themes/default/public/css mkdir -p $REMOTE/themes/default/public/js + +mkdir -p $REMOTE/themes/AdminLTE/templates/partials/ +mkdir -p $REMOTE/themes/AdminLTE/public/koozali/css +mkdir -p $REMOTE/themes/AdminLTE/public/koozali/js + cp -fv *.pm $REMOTE/lib/SrvMngr/Controller cp -fv *.css $REMOTE/themes/default/public/css cp -fv *.js $REMOTE/themes/default/public/js cp -fv _$2*.html.ep $REMOTE/themes/default/templates/partials/ find . -maxdepth 1 -type f -name "[!_]*\.ep" | xargs -I% bash -c 'cp -fv % $REMOTE/themes/default/templates/' + +cp -fv AdminLTE/*.css $REMOTE/themes/AdminLTE/public/koozali/css +cp -fv AdminLTE/*.js $REMOTE/themes/AdminLTE/public/koozali/js +cp -fv AdminLTE/_$2*.html.ep $REMOTE/themes/AdminLTE/templates/partials/ +find . -maxdepth 1 -type f -name "AdminLTE/[!_]*\.ep" | xargs -I% bash -c 'cp -fv % $REMOTE/themes/AdminLTE/templates/' + mkdir -p $REMOTE/lib/SrvMngr/I18N/Modules/$3 cp -fv *.lex $REMOTE/lib/SrvMngr/I18N/Modules/$3 rm -f $REMOTE/lib/SrvMngr/I18N/Modules/$3/*.pm ssh -p 1234 root@$SME11IP 'signal-event smanager-refresh' -exit 0 - - +exit 0 \ No newline at end of file diff --git a/json5/example1.json5 b/json5/example1.json5 new file mode 100644 index 0000000..f00e535 --- /dev/null +++ b/json5/example1.json5 @@ -0,0 +1,48 @@ +// Comment +{ + //and another comment + PackageName: 'Example1', //and yet another comment + prefix: 'ex1', + MenuHeading: 'Network', + MenuDescription: 'Example 1', + MenuNavigation: '2000 400', + firstPanel: 'TABLE', + signalEvent: 'smeserver-example1-update', + html: [ { + Name: 'params', + route: 'PARAMS', + Header: 'Example Contrib', + SubHeader: 'Manage Ibay settings:', + Paragraph1: 'These parameters will be effective only if the share is enabled. The share is in /home/e-smith/files/ibays//files', + Input1: { + Name: 'IbayName', + Type: 'Text', + Label: 'Information Bay name', + Value: 'stash("IbayName")', + }, + Input2: { + Name: 'ShareOwnerGrp', + Type: 'Select', + Label: 'Share owner Group', + Options: [ + { Value : "All", Text : "Write = admin, Read = group"}, + { Value : "Read:All-Write:Grp", Text : "Write = group, Read = everyone"}, + ], + } + }, + { + Name: 'select_ibay', + route:'TABLE', + Header: 'NFS Share Contrib', + SubHeader: 'Manage NFS Ibay settings:', + Nextpanel: 'PARAMS', + Table1: { + Type:'Table', + TableControl:"ibays", + TopHeadings: ['Name','Description','Status', 'Action'], + Columns: ['Name','Description','flag','Modify'] + }, + NextPanel:'PARAMS' + } + ] +} \ No newline at end of file diff --git a/lex_scan.py b/lex_scan.py index d4217a0..b07d360 100644 --- a/lex_scan.py +++ b/lex_scan.py @@ -3,8 +3,8 @@ # -a - Make sure all lex stringsa in code and tmeplates are in en lex file # - delete any that aren't needed # -e - Move all single word vqalues for lex strings to gthe general category -# -m - Examine all the controller files and make sure all headings and Descriptions are in the en general file -# - remove them from the controller en.lex file +# -m - Examine all the controller files and make sure all headings and Descriptions are in the en general file - WIP +# - remove them from the controller en.lex file - WIP # -l - Copy all panel and general files to each equivalent language file, fill in all translations over english where they exist in old .lex file # import argparse diff --git a/sm2gen.py b/sm2gen.py index 770d8cb..72d11cf 100644 --- a/sm2gen.py +++ b/sm2gen.py @@ -204,9 +204,8 @@ def lint_json5(filename): json5.loads(data) logger.info(f"{filename} as JSON5 data is valid") except Exception as e: - logger.warning(f"{filename} as JSON5 data is invalid") - logger.warning("Error:", str(e)) - sys.exit() + logger.error(f"{filename} as JSON5 data is invalid {e}") + quit(1) def flatten_hash_of_lists(hash_of_lists): @@ -631,20 +630,11 @@ if __name__ == "__main__": directory_path = Path("Targets/" + hl("PackageName")) # Create the directory if it doesn't exist directory_path.mkdir(parents=True, exist_ok=True) - target_directory_path = "Targets/" + hl("PackageName") + "/" - + base_target_directory_path = "Targets/" + hl("PackageName") + "/" + target_directory_path = base_target_directory_path controller_file = check_file_version(target_directory_path + hl("PackageName") + ".pm",force_Files) custom_controller_file = check_file_version(target_directory_path + hl("PackageName") + "-Custom.pm",force_Files) #logger.info(custom_controller_file) - layout_file = check_file_version(target_directory_path + hl("PackageName").lower() + ".html.ep",force_Files) - css_file = check_file_version(target_directory_path + hl("PackageName").lower() + ".css",force_Files) - js_file = check_file_version(target_directory_path + hl("PackageName").lower() + ".js",force_Files) - partial_files = list() - for panel in routes: - partial_files.append(check_file_version( - target_directory_path + '_' + hl("prefix") + "_" + panel + ".html.ep",force_Files) - ) - logger.debug(f"Partial files to be created:{partial_files}") lex_file = check_file_version(target_directory_path + hl("PackageName").lower() + "_en.lex",force_Files) logger.info(lex_file) tablecontrols = extract_tables(json5_dict) @@ -703,153 +693,167 @@ if __name__ == "__main__": except Exception as e: logger.info(f"A Chameleon custom controller *template* error occurred: {e} {traceback.format_exc()}") - # generate Layout file - layout_template = PageTemplateFile("Templates/layout.html.ep.tem") - try: - try: - layout_mojo = layout_template.render( - version=strVersion, **json5_dict, conditions=routes, - lcPackageName=json5_dict["PackageName"].lower() + for theme_name in ["","AdminLTE_"]: #the _ is important!! + target_directory_path = base_target_directory_path; + if theme_name: + theme_directory = theme_name.replace("_","") #Take out the trailing _ + target_directory_path = target_directory_path + theme_directory + "/" + Path(target_directory_path).mkdir(parents=True, exist_ok=True) + layout_file = check_file_version(target_directory_path + hl("PackageName").lower() + ".html.ep",force_Files) + css_file = check_file_version(target_directory_path + hl("PackageName").lower() + ".css",force_Files) + js_file = check_file_version(target_directory_path + hl("PackageName").lower() + ".js",force_Files) + partial_files = list() + for panel in routes: + partial_files.append(check_file_version( + target_directory_path + '_' + hl("prefix") + "_" + panel + ".html.ep",force_Files) ) - with open(layout_file, "w") as file: - file.write(layout_mojo) - logger.info(f"{highlight_occurrences(layout_file)} mojo template layout file generated ok") - except Exception as e: - logger.info(f"A Chameleon *render* on layout file error occurred: {e}") - except Exception as e: - logger.info(f"A Chameleon *template* layout file error occurred: {e}") - - - # Generate a partial file for each of the entries in the html list - # Pull in the template code for each of the input types - # html_controls = json5_to_dict('Templates/html_controls.html.ep.tem') - html_controls = parse_xml_to_dict("Templates/html_controls.html.ep.xml") - i = 0 - acc_css_entries = ""; #One entry for each class created for html entries - for html in json5_html_list: - # Generate a mojo template file, and then add in the controls - # main file first + logger.debug(f"Partial files to be created:{partial_files}") + # generate Layout file + layout_template = PageTemplateFile(f"Templates/{theme_name}layout.html.ep.tem") try: - partial_template = PageTemplateFile("Templates/partial.html.ep.tem") - partial_mojo_context = {**json5_dict, **html} try: - partial_mojo_template = partial_template.render( - version=strVersion, **partial_mojo_context, + layout_mojo = layout_template.render( + version=strVersion, **json5_dict, conditions=routes, lcPackageName=json5_dict["PackageName"].lower() - ) - with open(partial_files[i], "w") as file: - file.write(partial_mojo_template) - logger.info(f"{highlight_occurrences(partial_files[i])} mojo template generated ok - phase 1") + with open(layout_file, "w") as file: + file.write(layout_mojo) + logger.info(f"{highlight_occurrences(layout_file)} mojo template layout file generated ok") except Exception as e: - logger.info( - f"A Chameleon render error on partial file {html['route']} occurred: {e}" - ) + logger.info(f"A Chameleon *render* on layout file error occurred: {e}") except Exception as e: - logger.info(f"A Chameleon html {html['route']} error occurred: {e}") - - # Now generate the controls from the rest of the entries in the dict. - all_controls_html = "" - for html_control in html: - inner_html = html[html_control] - if isinstance(inner_html, dict): - # input or table - html_Type = inner_html['Type'] - type_serial = "".join(char for char in html_control if char.isdigit()) - class_name = html_Type.lower()[:4]+type_serial - acc_css_entries += f".{class_name} {{}}\n" - OptionsInPerl = python_to_perl_structure(inner_html.get("Options", "")) - #if html_Type == "Select": - # example_function(**inner_html) - # quit(1) - if html_Type == "Table": - acc_css_entries += f"thead .{class_name} {{}}\n" - acc_css_entries += f"tbody .{class_name} {{}}\n" + logger.info(f"A Chameleon *template* layout file error occurred: {e}") + + # Generate a partial file for each of the entries in the html list + # Pull in the template code for each of the input types + # html_controls = json5_to_dict('Templates/html_controls.html.ep.tem') + html_controls = parse_xml_to_dict(f"Templates/{theme_name}html_controls.html.ep.xml") + i = 0 + acc_css_entries = ""; #One entry for each class created for html entries + for html in json5_html_list: + # Generate a mojo template file, and then add in the controls + # main file first + try: + partial_template = PageTemplateFile(f"Templates/{theme_name}partial.html.ep.tem") + partial_mojo_context = {**json5_dict, **html} try: - control_template = PageTemplate(html_controls[inner_html["Type"]]) - try: - control_html = control_template.render( - version=strVersion, **inner_html, prefix=prefix_is, - classname=class_name, - type_serial=type_serial, - OptionsInPerl=OptionsInPerl - ) - all_controls_html = all_controls_html + control_html - except Exception as e: - logger.info( - f"A Chameleon *render* on partial file control {html_control} error occurred: {e}" - ) + partial_mojo_template = partial_template.render( + version=strVersion, **partial_mojo_context, + lcPackageName=json5_dict["PackageName"].lower() + + ) + with open(partial_files[i], "w") as file: + file.write(partial_mojo_template) + logger.info(f"{highlight_occurrences(partial_files[i])} mojo template generated ok - phase 1") except Exception as e: logger.info( - f"A Chameleon *template* on partial file control {html_control} error occurred: {e}" + f"A Chameleon render error on partial file {html['route']} occurred: {e}" ) - else: - # just a simple entry - name less numerics is type - # If the html does not include any Chameleon / TAL symbols, then do not run the Template extraction, just - # insert the result of the html directly. This avoids Chameleon aborting things when a closing tag is on its own - # such as the "Endgroup" token. - html_Type = "".join(char for char in html_control if not char.isdigit()) - type_serial = "".join(char for char in html_control if char.isdigit()) - class_name = html_Type.lower()[:4]+type_serial - acc_css_entries += f".{class_name} {{}}\n" - simple_control_html = "" - logger.debug(f"Partial ep generation html type:{html_Type}") - if not type_serial == "": - logger.debug(f"{html_control},{html_Type},{type_serial}") - if html_Type in html_controls: - if contains_chameleon_code(html_controls[html_Type]): + except Exception as e: + logger.info(f"A Chameleon html {html['route']} error occurred: {e}") + + # Now generate the controls from the rest of the entries in the dict. + all_controls_html = "" + for html_control in html: + inner_html = html[html_control] + if isinstance(inner_html, dict): + # input or table + html_Type = inner_html['Type'] + type_serial = "".join(char for char in html_control if char.isdigit()) + class_name = html_Type.lower()[:4]+type_serial + acc_css_entries += f".{class_name} {{}}\n" + OptionsInPerl = python_to_perl_structure(inner_html.get("Options", "")) + #if html_Type == "Select": + # example_function(**inner_html) + # quit(1) + if html_Type == "Table": + acc_css_entries += f"thead .{class_name} {{}}\n" + acc_css_entries += f"tbody .{class_name} {{}}\n" + try: + control_template = PageTemplate(html_controls[inner_html["Type"]]) try: - simple_control_template = PageTemplate(html_controls[html_Type]) + control_html = control_template.render( + version=strVersion, **inner_html, prefix=prefix_is, + classname=class_name, + type_serial=type_serial, + OptionsInPerl=OptionsInPerl + ) + all_controls_html = all_controls_html + control_html + except Exception as e: + logger.info( + f"A Chameleon *render* on partial file control {html_control} error occurred: {e}" + ) + except Exception as e: + logger.info( + f"A Chameleon *template* on partial file control {html_control} error occurred: {e}" + ) + else: + # just a simple entry - name less numerics is type + # If the html does not include any Chameleon / TAL symbols, then do not run the Template extraction, just + # insert the result of the html directly. This avoids Chameleon aborting things when a closing tag is on its own + # such as the "Endgroup" token. + html_Type = "".join(char for char in html_control if not char.isdigit()) + type_serial = "".join(char for char in html_control if char.isdigit()) + class_name = html_Type.lower()[:4]+type_serial + acc_css_entries += f".{class_name} {{}}\n" + simple_control_html = "" + logger.debug(f"Partial ep generation html type:{html_Type}") + if not type_serial == "": + logger.debug(f"{html_control},{html_Type},{type_serial}") + if html_Type in html_controls: + if contains_chameleon_code(html_controls[html_Type]): try: - simple_control_html = simple_control_template.render( - version=strVersion, Value=inner_html, prefix=prefix_is, - type_serial=type_serial - ) + simple_control_template = PageTemplate(html_controls[html_Type]) + try: + simple_control_html = simple_control_template.render( + version=strVersion, Value=inner_html, prefix=prefix_is, + type_serial=type_serial + ) + except Exception as e: + logger.warning( + f"A Chameleon *render* on partial file control {html_control} error occurred: {e}" + ) except Exception as e: logger.warning( - f"A Chameleon *render* on partial file control {html_control} error occurred: {e}" + f"A Chameleon *template* partial file control {html_control} error occurred: {e}" ) - except Exception as e: - logger.warning( - f"A Chameleon *template* partial file control {html_control} error occurred: {e}" - ) + else: + logger.debug(f"Skipping Chameleon expansion for {html_control}") + simple_control_html = html_controls[html_Type] + all_controls_html = all_controls_html + simple_control_html else: - logger.debug(f"Skipping Chameleon expansion for {html_control}") - simple_control_html = html_controls[html_Type] - all_controls_html = all_controls_html + simple_control_html - else: - logger.debug(f"{html_Type} not found in html_controls xml") - # Now insert it into the partial file in the correct place. - # Read in the text file and split at "%# Inputs etc in here." - with open(partial_files[i], "r") as file: - lines = file.readlines() - index = next( - (i for i, line in enumerate(lines) if "%# Inputs etc in here." in line), - len(lines), - ) + logger.debug(f"{html_Type} not found in html_controls xml") + # Now insert it into the partial file in the correct place. + # Read in the text file and split at "%# Inputs etc in here." + with open(partial_files[i], "r") as file: + lines = file.readlines() + index = next( + (i for i, line in enumerate(lines) if "%# Inputs etc in here." in line), + len(lines), + ) - # Insert the string at the specified index - lines.insert(index + 1, all_controls_html + "\n") + # Insert the string at the specified index + lines.insert(index + 1, all_controls_html + "\n") - # Write the modified content back to the file - with open(partial_files[i], "w") as file: - file.writelines(lines) - logger.info(f"Content modified and saved to {highlight_occurrences(partial_files[i])}") - i += 1 + # Write the modified content back to the file + with open(partial_files[i], "w") as file: + file.writelines(lines) + logger.info(f"Content modified and saved to {highlight_occurrences(partial_files[i])}") + i += 1 - # Create the css file (the header, followed by a dummy entry for each class created/used above) - with open(css_file, "w") as file: - file.write(f"/*\nGenerated by: {strVersion}\n*/\n") - file.write(f".{hl('PackageName')}-panel {{}}\n") - file.write(acc_css_entries); - logger.info(f"Css generated and saved to {highlight_occurrences(css_file)}") - - # and create a js file (empty)) - with open(js_file, "w") as file: - file.write(f"//\n//Generated by: {strVersion}\n//\n") - file.write("$(document).ready(function() {\n") - file.write("});\n"); - logger.info(f"js generated and saved to {highlight_occurrences(js_file)}") + # Create the css file (the header, followed by a dummy entry for each class created/used above) + with open(css_file, "w") as file: + file.write(f"/*\nGenerated by: {strVersion}\n*/\n") + file.write(f".{hl('PackageName')}-panel {{}}\n") + file.write(acc_css_entries); + logger.info(f"Css generated and saved to {highlight_occurrences(css_file)}") + + # and create a js file (empty)) + with open(js_file, "w") as file: + file.write(f"//\n//Generated by: {strVersion}\n//\n") + file.write("$(document).ready(function() {\n") + file.write("});\n"); + logger.info(f"js generated and saved to {highlight_occurrences(js_file)}") # Now generate the .en file # Look through the generated files for the /l[\s|(]['|"](.*)['|"]\)/ strings.