diff --git a/htdocs/css/style.css b/htdocs/css/style.css index 167ed65..9206f11 100644 --- a/htdocs/css/style.css +++ b/htdocs/css/style.css @@ -650,7 +650,6 @@ td.table_label { tr.focus td { animation: 4s focus; - } body.dark span.color_label.gray { @@ -781,11 +780,16 @@ td.table_label { .flex-container { display: flex; white-space: nowrap; - flex-wrap: wrap; + flex-wrap: nowrap; justify-content: space-between; /* align-items: center; */ } + .flex-container.widget { + align-items: center; + justify-content:space-between; + } + .flex-container-stats { display: flex; white-space: nowrap; @@ -796,34 +800,23 @@ td.table_label { .upcoming.grid-container { display: grid; - grid-template-columns: repeat(6, minmax(240px, 1fr)); - gap: 14px; - padding: 12px; + grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); + gap: 12px; + padding: 10px; direction: ltr; } - @media (max-width: 1600px) { /* Adjust the max-width value based on when you want the change to occur */ - .upcoming.grid-container { - grid-template-columns: repeat(4, minmax(240px, 1fr)); /* Change to 6 columns when screen width is 768px or smaller */ - } - } - - @media (max-width: 1200px) { /* Adjust the max-width value based on when you want the change to occur */ - .upcoming.grid-container { - grid-template-columns: repeat(3, minmax(240px, 1fr)); /* Change to 6 columns when screen width is 768px or smaller */ - } - } - - @media (max-width: 900px) { /* Adjust the max-width value based on when you want the change to occur */ - .upcoming.grid-container { - grid-template-columns: repeat(2, minmax(240px, 1fr)); /* Change to 6 columns when screen width is 768px or smaller */ - } + .upcoming.schedule.grid-container { + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + padding-top: 0px; + gap: 14px; + } .stats.grid-container { display: grid; /* grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); */ - grid-template-columns: repeat(10, 1fr); + grid-template-columns: repeat(10, auto); align-items: center; gap: 14px; padding: 4px; @@ -833,47 +826,135 @@ td.table_label { } - @media (max-width: 1200px) { /* Adjust the max-width value based on when you want the change to occur */ - .stats.grid-container { - grid-template-columns: repeat(5, 1fr); /* Change to 6 columns when screen width is 768px or smaller */ - } - } - - .upcoming.grid-item { + .stats.grid-item { border: 1px solid #ccccccde; + background-color: var(--box-background-color); + /* background-color: #FAFAFA; */ /* transition: border-width 0.3s; */ - padding: 8px; + padding: 4px; border-radius: 12px; word-wrap: break-word; white-space: wrap; overflow: hidden; /* white-space: normal; */ direction: ltr; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* vertical-align: middle; */ } - .stats.grid-item { + body.dark .stats.grid-item { + background-color: initial; + } + body.dark .stats.grid-item:hover { + color: #FFF; + background-color: initial; + } + .stats.grid-item:hover { + background-color: rgba(128,128,128, 0.1); + } + + @media (max-width: 1200px) { + .stats.grid-container { + grid-template-columns: repeat(5, 1fr); + } + } + + .job-details.grid-container { + display: grid; + /* grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); */ + grid-template-columns: repeat(7, auto); + align-items: center; + gap: 6px; + padding: 0px; + padding-bottom: 12px; + margin-top: 12px; + /* background-color: var(--box-background-color); */ + background-color: initial; + border: 0px solid var( --border-color); + border-radius: 6px; + } + + .job-details.running.grid-container { + grid-template-columns: repeat(6, auto); + } + + body.dark .job-details.grid-container { + background-color: var(--background-color); + } + + .job-details.grid-item { + display: flex; + align-items: baseline; + justify-content: space-evenly; + border: 1px solid var( --border-color); + background-color: var(--box-background-color); + flex-wrap: wrap; + padding-top: 8px; + border-radius: 6px; + } + + body.dark .job-details.grid-item:hover div.info_value { + color: white; + text-shadow: none; + } + + .upcoming.grid-item { border: 1px solid #ccccccde; - background-color: #FAFAFA; /* transition: border-width 0.3s; */ - padding: 4px; + padding: 8px; border-radius: 12px; word-wrap: break-word; white-space: wrap; overflow: hidden; /* white-space: normal; */ direction: ltr; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* vertical-align: middle; */ } - body.dark .stats.grid-item { - background-color: initial; + + .upcoming.grid-item.focus { + animation: 4s focus; } - body.dark .stats.grid-item:hover { - color: #FFF; + + + body.dark .upcoming.schedule.grid-item { + background-color: #44444444 + /* color: #fff */ + } + + .upcoming.schedule.grid-item { + background-color: #fafafa + /* color: #fff */ + } + + .event-error { + color: #bb4444cc; + } + .event-success { + color: #44bb4460; + } + .event-warning { + color: #dbdb34bb; } + .event-none { + color: #44444400; + } + + .section-divider { + grid-column: 1 / -1; + text-align: left; + /* color: initial; */ + font-size: 1.4em; + font-weight: bold; + } + .upcoming.warning.grid-item { + background-color: #f5e05870;; + } + + .upcoming.error.grid-item { + background-color: pink; + } body.dark .upcoming.grid-item { box-shadow: 0px 4px 8px 0px rgba(0,0,0,0.75); @@ -887,75 +968,82 @@ td.table_label { background-color: #b7ffb770 } - body.dark .upcoming.minute.grid-item { - background-color: #2c702cDD; - transition: background-color 3s; - /* rgb(0,108,0); */ - /* color: #FFF; */ - color: #d3c7c7 - } + body.dark .upcoming.minute.grid-item { + background-color: #2c702cDD; + transition: background-color 3s; + color: #d3c7c7 + } - .upcoming.grid-item a { - font-size: 1.1em; - } + .upcoming.grid-item a { + font-size: 1.1em; + } - body.dark .upcoming.grid-item a { - color: #3a639b; - } - - body.dark .upcoming.minute.grid-item a { - color: #d3c7c7 !important; - font-size: 1.2em; - } + body.dark .upcoming.grid-item a { + color: #3a639b; + } + + body.dark .upcoming.minute.grid-item a { + color: #d3c7c7 !important; + font-size: 1.2em; + } - body.dark .upcoming.soon.grid-item a { - /* color: #301919!important; - */ - /* color: #efd2d2 !important; */ - /* color: #d3c7c7; */ - color: #d3c7c7 !important; - font-size: 1.2em; - } + body.dark .upcoming.soon.grid-item a { + color: #d3c7c7 !important; + font-size: 1.2em; + } - .upcoming.minute.grid-item a { - color: rgb(84, 84, 84) !important; - font-size: 1.2em; - } - - .upcoming.soon.grid-item a { - color: rgb(84, 84, 84) !important; - font-size: 1.2em; - } + .upcoming.minute.grid-item a { + color: rgb(84, 84, 84) !important; + font-size: 1.2em; + } - /* body.dark upcoming.minute.grid-item a { - color: #FFF !important; - } */ + .upcoming.soon.grid-item a { + color: rgb(84, 84, 84) !important; + font-size: 1.2em; + } .upcoming.soon.grid-item { background-color: #f5e05870; - - /* border-color: white; */ } body.dark .upcoming.soon.grid-item { background-color: rgba(255, 115, 0, 0.7); - /* color: #301919!important; */ - /* color: #fff; */ color: #d3c7c7; - /* color: rgb(84, 84, 84); */ } .upcoming.grid-item:hover { border-color: rgba(46, 38, 12, 0.4); - /* background-color:rgb(0, 255, 0) */ - + /* background-color:rgb(0, 255, 0) */ } - body.dark .upcoming.grid-item:hover { + body.dark .upcoming.grid-item:hover:not(.schedule) { /* border-color: rgba(46, 38, 12, 0.4); */ color: #FFF; } + .event-action { + font-weight: bold; + color:#817c7c; + text-decoration: none; + } + + .event-action:hover { + text-decoration: underline; + } + + .search { + width : 100px; + background-color:gray; + -webkit-transition: all 0.3s linear; + -moz-transition: all 0.3s linear; + border-radius : 15px; + outline:none; + } + + body.dark .event-action:hover { + font-weight: bold; + color:#555; + } body.dark .upcoming.grid-item { border: 1px solid #cccccc26; @@ -970,4 +1058,11 @@ td.table_label { font-size: 1.2em; } + .event-search { + padding-left:30px; + border:0.3px solid #ccccccaa; + border-radius:8px; + font-size: 1.2em; + } + diff --git a/htdocs/js/app.js b/htdocs/js/app.js index 1c9f46b..4ba5340 100644 --- a/htdocs/js/app.js +++ b/htdocs/js/app.js @@ -819,6 +819,18 @@ function get_pretty_int_list(arr, ranges) { return arr.slice(0, arr.length - 1).join(', ') + ' and ' + arr[ arr.length - 1 ]; } +function summarize_event_timing_short(timing) { + if(!timing) return "On Demand" + let type = 'Hourly' + let total = (timing.minutes || []).length || 60 + if(timing.hours) { total = total*(timing.hours.length || 24); type = 'Daily'} else { total = total*24} + if(timing.weekdays) { total = total*(timing.weekdays.length || 1); type = 'Weekly'} + if(timing.days) { total = total*(timing.days.length || 1); type = 'Monthly'} + if(timing.months) { total = total*(timing.months.length || 1); type = 'Yearly'} + if(timing.years) { total = total*(timing.years.length || 1); type = 'Custom'} + return `${type} :: ${total}` +} + function summarize_event_timing(timing, timezone, extra) { // summarize event timing into human-readable string if (!timing && extra) { diff --git a/htdocs/js/pages/Base.class.js b/htdocs/js/pages/Base.class.js index 192f69a..602b619 100644 --- a/htdocs/js/pages/Base.class.js +++ b/htdocs/js/pages/Base.class.js @@ -60,18 +60,31 @@ Class.subclass(Page, "Page.Base", { return '
- | + | ` } @@ -956,13 +1070,24 @@ Class.subclass(Page.Base, "Page.Schedule", { update_job_last_runs: function () { // update last run state for all jobs, called when state is updated if (!app.state.jobCodes) return; + let isGrid = app.getPref('event_view') === 'grid' || app.getPref('event_view') == 'gridall' for (var event_id in app.state.jobCodes) { - var last_code = app.state.jobCodes[event_id]; - var status_html = last_code ? ' Error' : ' Success'; - if (last_code == 255) status_html = ' Warning' - // this.div.find('#ss_' + event_id).html(status_html); - document.getElementById('ss_' + event_id).innerHTML = status_html + let last_code = app.state.jobCodes[event_id]; + let status_html; + + if (isGrid) { + status_html = last_code ? 'event-error' : 'event-success' + if (last_code == 255) status_html = 'event-warning' + status_html = `` + } + else { + status_html = last_code ? ' Error' : ' Success'; + if (last_code == 255) status_html = ' Warning' + } + + let statusIcon = document.getElementById('ss_' + event_id) + if (statusIcon) statusIcon.innerHTML = status_html } }, @@ -990,6 +1115,14 @@ Class.subclass(Page.Base, "Page.Schedule", { this.gosub_events(this.args); }, + change_event_view: function (view_type) { + // if( ['Grid', 'Details', 'Grid-All'].indexOf(view_type) < 0 ) view_type = 'Details' + if (['details', 'grid', 'gridall'].indexOf(view_type) < 0) view_type = 'details' + app.setPref('event_view', view_type) + this.gosub_events(this.args); + + }, + toggle_group_by: function () { let args = this.args args.collapse ^= true @@ -1524,7 +1657,7 @@ Class.subclass(Page.Base, "Page.Schedule", { } // check for update delete this.old_event; - if (event.secret_value && typeof event.secret_value === 'string' ) { + if (event.secret_value && typeof event.secret_value === 'string') { delete event.secret_value $('#fe_ee_secret').val('').attr('placeholder', '[*****]') } @@ -1734,9 +1867,9 @@ Class.subclass(Page.Base, "Page.Schedule", { } // Secret - let sph = event.secret_preview ? '[' + event.secret_preview + ']' : ''; + let sph = event.secret_preview ? '[' + event.secret_preview + ']' : ''; html += get_form_table_row('Secret', ``); - html += get_form_table_caption("Specify KEY=VALUE pairs to be mounted as env variables (to this job process)"); + html += get_form_table_caption("Specify KEY=VALUE pairs to be mounted as env variables (to this job process). When using Docker plugin, KEY should be prefixed with DOCKER_ to pass custom variable to docker container. When using SSH plugin, KEY should be prefixed with SSH_ to pass to remote machine."); html += get_form_table_spacer(); // max children @@ -2537,13 +2670,13 @@ Class.subclass(Page.Base, "Page.Schedule", { this.refresh_plugin_params(); }, - - setScriptEditor: function() { - + + setScriptEditor: function () { + let params = this.event.params || {} let el = document.getElementById("fe_ee_pp_script") - if(!el) return + if (!el) return let privs = app.user.privileges; let canEdit = privs.admin || privs.edit_events || privs.create_events; @@ -2585,45 +2718,45 @@ Class.subclass(Page.Base, "Page.Schedule", { gutters: [gutter], lint: lint, extraKeys: { - "F11": (cm) => cm.setOption("fullScreen", !cm.getOption("fullScreen")), - "Esc": (cm) => cm.getOption("fullScreen") ? cm.setOption("fullScreen", false) : null, - "Ctrl-/": (cm) => cm.execCommand('toggleComment') - } - }); + "F11": (cm) => cm.setOption("fullScreen", !cm.getOption("fullScreen")), + "Esc": (cm) => cm.getOption("fullScreen") ? cm.setOption("fullScreen", false) : null, + "Ctrl-/": (cm) => cm.execCommand('toggleComment') + } + }); editor.on('change', (cm) => { el.value = cm.getValue() }) // syntax selector - document.getElementById("fe_ee_pp_lang").addEventListener("change", function(){ + document.getElementById("fe_ee_pp_lang").addEventListener("change", function () { let ln = this.options[this.selectedIndex].value; editor.setOption("gutters", ['']); editor.setOption("lint", false) - if(ln == 'java') {ln = 'text/x-java'} - if(ln == 'scala') {ln = 'text/x-scala'} - if(ln == 'csharp') {ln = 'text/x-csharp'} + if (ln == 'java') { ln = 'text/x-java' } + if (ln == 'scala') { ln = 'text/x-scala' } + if (ln == 'csharp') { ln = 'text/x-csharp' } if (ln == 'sql') { ln = 'text/x-sql' } if (ln == 'dockerfile') { ln = 'text/x-dockerfile' } if (ln == 'toml') { ln = 'text/x-toml' } - if (ln == 'json') { + if (ln == 'json') { ln = 'application/json' editor.setOption("lint", CodeMirror.lint.json) - } + } if (ln == 'props') { ln = 'text/x-properties' } if (ln == 'yaml') { ln = 'text/x-yaml' editor.setOption("gutters", ['CodeMirror-lint-markers']); editor.setOption("lint", CodeMirror.lint.yaml) } - editor.setOption("mode", ln); + editor.setOption("mode", ln); }); // theme - document.getElementById("fe_ee_pp_theme").addEventListener("change", function(){ + document.getElementById("fe_ee_pp_theme").addEventListener("change", function () { var thm = this.options[this.selectedIndex].value; - if(thm === 'default' && app.getPref('theme') === 'dark') thm = 'gruvbox-dark'; - if(thm === 'light') thm = 'default'; + if (thm === 'default' && app.getPref('theme') === 'dark') thm = 'gruvbox-dark'; + if (thm === 'light') thm = 'default'; editor.setOption("theme", thm); }); }, @@ -2725,7 +2858,7 @@ Class.subclass(Page.Base, "Page.Schedule", { refresh_plugin_params: function () { // redraw plugin param area after change $('#d_ee_plugin_params').html(this.get_plugin_params_html()); - this.setScriptEditor(); + this.setScriptEditor(); }, get_random_event: function () { |