Skip to content

Commit 4c88760

Browse files
authored
Merge pull request #169 from WebFiori/dev
Improvements to Scheduler Web Interface
2 parents 0b47999 + 861176f commit 4c88760

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+995
-545
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/app export-ignore
44
/public export-ignore
55
/themes export-ignore
6+
/webfiori/framework/db export-ignore
67
/.github export-ignore
78
/.gitignore export-ignore
89
/.travis.yml export-ignore

assets/js/scheduler-logic.js

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
/* global ajax, data */
2+
ajax.setOnDisconnected(function () {
3+
this.props.vue.showDialog('Check your internet connection and try again.');
4+
});
5+
ajax.setOnSuccess({
6+
id:'Set Password',
7+
call:function() {
8+
return this.url === 'scheduler/apis/set-password';
9+
},
10+
callback:function() {
11+
if (this.jsonResponse) {
12+
window.location.href = data.base+'/scheduler/login';
13+
} else {
14+
this.props.vue.showDialog('Something went wrong. Try again.');
15+
}
16+
}
17+
});
18+
ajax.setOnSuccess({
19+
id:'Login',
20+
call:function() {
21+
return this.url === 'scheduler/apis/login';
22+
},
23+
callback:function() {
24+
if (this.jsonResponse) {
25+
window.location.href = data.base+'/scheduler/tasks';
26+
} else {
27+
this.props.vue.showDialog('Something went wrong. Try again.');
28+
}
29+
}
30+
});
31+
ajax.setOnClientError({
32+
id:'Login Failed',
33+
call:function() {
34+
return this.url === 'scheduler/apis/login';
35+
},
36+
callback:function() {
37+
if (this.jsonResponse) {
38+
this.props.vue.showDialog(this.jsonResponse.message);
39+
} else {
40+
this.props.vue.showDialog('Something went wrong. Try again.');
41+
}
42+
}
43+
});
44+
ajax.setBeforeAjax(function () {
45+
this.props.vue.loading = true;
46+
});
47+
ajax.setAfterAjax(function () {
48+
this.props.vue.loading = false;
49+
});
50+
ajax.setOnSuccess({
51+
id:'Logout',
52+
call:function() {
53+
return this.url === 'scheduler/apis/logout';
54+
},
55+
callback:function() {
56+
if (this.jsonResponse) {
57+
window.location.href = data.base+'/scheduler/login';
58+
} else {
59+
this.props.vue.showDialog('Something went wrong. Try again.');
60+
}
61+
}
62+
});
63+
ajax.setOnSuccess({
64+
id:'Get Tasks',
65+
call:function() {
66+
return this.url === 'scheduler/apis/get-tasks';
67+
},
68+
callback:function() {
69+
if (this.jsonResponse) {
70+
this.props.vue.tasks = this.jsonResponse.tasks;
71+
} else {
72+
this.props.vue.showDialog('Something went wrong. Try again.');
73+
}
74+
}
75+
});
76+
ajax.setOnSuccess({
77+
id:'After Force Execution',
78+
call:function() {
79+
return this.url === 'scheduler/apis/force-execution';
80+
},
81+
callback:function() {
82+
var vue = this.props.vue;
83+
vue.loading = false;
84+
vue.active_task.executing = false;
85+
var icon = 'mdi-check-decagram';
86+
var iconColor = 'green';
87+
88+
if (this.status === 200 && this.jsonResponse) {
89+
var output = '';
90+
var info = this.jsonResponse['more-info'];
91+
92+
if (info === undefined) {
93+
info = this.jsonResponse['more_info'];
94+
}
95+
96+
if (info === undefined) {
97+
info = this.jsonResponse['moreInfo'];
98+
}
99+
for (var x = 0 ; x < info.log.length ; x++) {
100+
output += info.log[x]+'<br/>';
101+
}
102+
vue.output_dialog.output = output;
103+
104+
if (info.failed.indexOf(vue.active_task.name) !== -1) {
105+
vue.output_dialog.failed = true;
106+
icon = 'mdi-alert-octagram';
107+
iconColor = 'red';
108+
} else {
109+
vue.output_dialog.failed = false;
110+
}
111+
} else {
112+
vue.output_dialog.output = this.response;
113+
vue.output_dialog.failed = true;
114+
icon = 'mdi-alert-octagram';
115+
iconColor = 'red';
116+
}
117+
vue.showDialog(this.jsonResponse.message, icon, iconColor);
118+
}
119+
});
120+
ajax.setOnServerError({
121+
id:'Server Error',
122+
call:true,
123+
callback:function() {
124+
if (this.jsonResponse) {
125+
if (this.jsonResponse.message) {
126+
this.props.vue.showDialog(this.jsonResponse.message);
127+
} else {
128+
this.props.vue.showDialog(this.status+' - Server Error.');
129+
}
130+
} else {
131+
this.props.vue.showDialog(this.status+' - Server Error.');
132+
}
133+
}
134+
});
135+
ajax.setOnClientError({
136+
id:'Client Error',
137+
call:true,
138+
callback:function() {
139+
if (this.jsonResponse) {
140+
if (this.jsonResponse.message) {
141+
this.props.vue.showDialog(this.jsonResponse.message);
142+
} else {
143+
this.props.vue.showDialog(this.status+' - Client Error.');
144+
}
145+
} else {
146+
this.props.vue.showDialog(this.status+' - Client Error.');
147+
}
148+
}
149+
});
150+
var app = new Vue({
151+
el:'#app',
152+
vuetify: new Vuetify(),
153+
data: {
154+
password:'',
155+
search:'',
156+
loading:false,
157+
tasks:[],
158+
expanded:[],
159+
tasks_table_headers:[
160+
{value:'info', text:''},
161+
{value:'name', text:'Job Name'},
162+
{value:'expression', text:'CRON Expression'},
163+
{value:'time.is_minute', text:'Is Minute'},
164+
{value:'time.is_hour', text:'Is Hour'},
165+
{value:'time.is_day_of_week', text:'Is Day of Week'},
166+
{value:'time.is_day_of_month', text:'Is Day of Month'},
167+
{value:'time.is_month', text:'Is Month'},
168+
{value:'actions', text:'Actions'},
169+
],
170+
execution_dialog:{
171+
visible:false,
172+
title:'Message',
173+
message:'',
174+
icon_color:'',
175+
icon:''
176+
},
177+
output_dialog:{
178+
show:false,
179+
output:'',
180+
failed:false
181+
}
182+
},
183+
computed:{
184+
login_btn_disabled:function() {
185+
var pass = this.password+'';
186+
return pass.length < 6;
187+
},
188+
set_password_btn_disabled:function () {
189+
var pass = this.password+'';
190+
return pass.length < 6;
191+
}
192+
},
193+
mounted:function () {
194+
ajax.bind({
195+
vue:this
196+
});
197+
ajax.setBase(data.base);
198+
if (data.title === 'Scheduled Tasks') {
199+
this.loadTasks();
200+
}
201+
},
202+
methods:{
203+
forceExec:function (job) {
204+
this.active_task = job;
205+
var params = {
206+
'task-name':job.name
207+
};
208+
for(var x = 0 ; x < job.args.length ; x++) {
209+
var argVal = job.args[x].value;
210+
if (argVal !== undefined && argVal !== null && argVal.length !== 0) {
211+
params[job.args[x].name] = argVal;
212+
}
213+
}
214+
ajax.setURL('scheduler/apis/force-execution');
215+
ajax.setMethod('post');
216+
ajax.setParams(params);
217+
ajax.send();
218+
},
219+
setPassword:function() {
220+
ajax.setURL('scheduler/apis/set-password');
221+
ajax.setMethod('post');
222+
ajax.setParams({
223+
password:this.password
224+
});
225+
ajax.send();
226+
},
227+
checkIfEnterHit:function(e) {
228+
if (e.keyCode === 13) {
229+
this.login();
230+
}
231+
},
232+
loadTasks:function() {
233+
ajax.setURL('scheduler/apis/get-tasks');
234+
ajax.setMethod('get');
235+
ajax.send();
236+
},
237+
dialogClosed:function() {
238+
this.execution_dialog.visible = false;
239+
},
240+
showDialog(message, icon = 'mdi-information', iconColor = 'gray') {
241+
this.execution_dialog.message = message;
242+
this.execution_dialog.icon = icon;
243+
this.execution_dialog.icon_color = iconColor;
244+
this.execution_dialog.visible = true;
245+
},
246+
logout:function() {
247+
ajax.setURL('scheduler/apis/logout');
248+
ajax.setMethod('get');
249+
ajax.send();
250+
},
251+
login:function() {
252+
ajax.setURL('scheduler/apis/login');
253+
ajax.setMethod('post');
254+
ajax.setParams({
255+
password:this.password
256+
});
257+
ajax.send();
258+
}
259+
}
260+
});

assets/js/server-err.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const app = new Vue({
2+
el: '#app',
3+
vuetify: new Vuetify({
4+
5+
}),
6+
data:{
7+
8+
},
9+
methods:{
10+
11+
},
12+
mounted:function () {
13+
14+
},
15+
computed:{
16+
17+
}
18+
});

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
"ext-openssl": "*",
2121
"webfiori/err":"v1.0.6",
2222
"webfiori/cli":"v1.1.1",
23-
"webfiori/file":"v1.3.1",
23+
"webfiori/file":"v1.3.2",
2424
"webfiori/collections":"v1.1.3",
2525
"webfiori/ui":"v2.5.2",
2626
"webfiori/jsonx":"v3.2.1",
2727
"webfiori/http":"v3.3.2 ",
28-
"webfiori/database":"v0.7.0",
28+
"webfiori/database":"v0.7.1",
2929
"webfiori/mailer":"v1.0.4"
3030
},
3131
"require-dev": {

public/favicon.ico

1.12 KB
Binary file not shown.

public/favicon.png

98.4 KB
Loading

public/index.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace webfiori;
4+
5+
use Exception;
6+
use webfiori\framework\router\Router;
7+
use webfiori\framework\session\SessionsManager;
8+
use webfiori\framework\App;
9+
use webfiori\http\Request;
10+
use webfiori\http\Response;
11+
/**
12+
* The name of the directory at which the developer will have his own application
13+
* code.
14+
*
15+
* @since 2.3.0
16+
*/
17+
define('APP_DIR', 'app');
18+
19+
20+
/**
21+
* The entry point of all requests.
22+
*
23+
* @author Ibrahim
24+
*/
25+
class Index {
26+
private static $instance;
27+
private function __construct() {
28+
$DS = DIRECTORY_SEPARATOR;
29+
/**
30+
* The root directory that is used to load all other required system files.
31+
*/
32+
if (!defined('ROOT_PATH')) {
33+
$publicFolder = $DS.'public';
34+
35+
if (substr(__DIR__, strlen(__DIR__) - strlen($publicFolder)) == $publicFolder) {
36+
//HTTP run
37+
define('ROOT_PATH', substr(__DIR__,0, strlen(__DIR__) - strlen($DS.'public')));
38+
} else {
39+
//CLI run
40+
define('ROOT_PATH', __DIR__);
41+
}
42+
}
43+
$this->loadAppClass();
44+
/**
45+
* This where magic will start.
46+
*
47+
* Planting application seed into the ground and make your work bloom.
48+
*/
49+
App::start();
50+
51+
if (App::getRunner()->isCLI() === true) {
52+
App::getRunner()->start();
53+
} else {
54+
//route user request.
55+
SessionsManager::start('wf-session');
56+
Router::route(Request::getRequestedURI());
57+
Response::send();
58+
}
59+
}
60+
/**
61+
* Try to load the class 'App'.
62+
*
63+
* @throws Exception
64+
*/
65+
private function loadAppClass() {
66+
$DS = DIRECTORY_SEPARATOR;
67+
$frameworkPath = ROOT_PATH.$DS.'webfiori'.$DS.'framework';
68+
$corePath = $frameworkPath;
69+
$rootClass = $DS.'App.php';
70+
71+
if (file_exists($corePath.$rootClass)) {
72+
define('WF_CORE_PATH', $corePath);
73+
require_once $corePath.$rootClass;
74+
} else {
75+
throw new Exception('Unable to locate the class "App".');
76+
}
77+
}
78+
/**
79+
* Creates a single instance of the class.
80+
*/
81+
public static function create() {
82+
if (self::$instance === null) {
83+
self::$instance = new Index();
84+
}
85+
}
86+
}
87+
Index::create();

0 commit comments

Comments
 (0)