Skip to content

Commit

Permalink
adding wizard on community branch + syncup with enterprise branch
Browse files Browse the repository at this point in the history
  • Loading branch information
jdetaeye committed Oct 22, 2020
1 parent dbfa2a1 commit 046f37c
Show file tree
Hide file tree
Showing 82 changed files with 2,617 additions and 137 deletions.
2 changes: 1 addition & 1 deletion contrib/installer/pgsql/README.txt
Expand Up @@ -5,7 +5,7 @@ obtained from:
We redistribute this product unmodified.

Initialising a database with the provided binaries is easy.
The frePPLe installer runs the following steps for you, but you're
The frePPLe installer runs the following steps for you, but you're
always free to redo the initialisation to meet your needs:
initdb --pgdata YOUR_DATA_FOLDER --encoding UTF8
pg_ctl --pgdata YOUR_DATA_FOLDER --log YOUR_LOG_FILE -w start
Expand Down
9 changes: 0 additions & 9 deletions contrib/linux/debian-10/debian/httpd.conf
Expand Up @@ -43,15 +43,6 @@
#LoadModule authz_host_module modules/mod_authz_host.so
#LoadModule env_module modules/mod_env.so

# Extra settings for websocket proxying support
#LoadModule proxy
#LoadModule proxy_wstunnel
# Modify the next lines to match the name of your scenarios name and FREPPLE_PORT settings
Proxypass "/ws/default" "ws://localhost:8002" retry=0
Proxypass "/ws/scenario1/" "ws://localhost:8003" retry=0
Proxypass "/ws/scenario2/" "ws://localhost:8004" retry=0
Proxypass "/ws/scenario3/" "ws://localhost:8005" retry=0

WSGIRestrictStdout Off

## HINT: All of the frePPLe-specific configurations can be put in a virtual host. This is
Expand Down
3 changes: 2 additions & 1 deletion djangosettings.py
Expand Up @@ -239,6 +239,7 @@
# Add any project specific apps here
# "freppledb.odoo",
#'freppledb.erpconnection',
"freppledb.wizard",
"freppledb.input",
"freppledb.output",
"freppledb.metrics",
Expand All @@ -252,7 +253,7 @@
# The next two apps allow users to run their own SQL statements on
# the database, using the SQL_ROLE configured above.
"freppledb.reportmanager",
# "freppledb.executesql",
"freppledb.executesql",
)

# Custom attribute fields in the database
Expand Down
1 change: 1 addition & 0 deletions doc/installation-guide/linux-binaries.rst
Expand Up @@ -203,6 +203,7 @@ Here are the steps to get a fully working environment.
'bootstrap3',
'freppledb.boot',
# << ADD YOUR CUSTOM EXTENSION APPS HERE
'freppledb.wizard', << COMMENT IF MODEL BUILDING WIZARD ISN'T NEEDED
'freppledb.input',
#'freppledb.odoo', # << UNCOMMENT TO ACTIVATE THE ODOO INTEGRATION
#'freppledb.erpconnection', # << UNCOMMENT TO ACTIVATE THE GENERIC ERP INTEGRATION
Expand Down
11 changes: 11 additions & 0 deletions doc/release-notes.rst
Expand Up @@ -6,6 +6,17 @@ Release notes

.. rubric:: User interface

- A new get-started wizard is added to generate forecast for a single item.
Fill in a simple form with the item, location, customer and recent sales
history, and we'll populate the data tables and generate the statistical forecast.

- A new get-started wizard is added to generate a production plan for a single
sales order. Fill in the details of the sales order, define the supply path
and we'll populate the data tables and generate the production plan.

- A data loading wizard which is already available on the Enterprise and Cloud
Editions for a long time. It is now also made available on the Community Edition.

- The cockpit is renamed to `home <user-interface/cockpit.html>`_.

6.8.0 (2020/10/03)
Expand Down
104 changes: 88 additions & 16 deletions freppledb/common/static/common/src/webfactory.js
Expand Up @@ -18,15 +18,49 @@

angular.module('frepple.common').factory('WebSvc', webfactory);

webfactory.$inject = ['$rootScope', '$websocket', '$interval'];
webfactory.$inject = ['$rootScope', '$websocket', '$interval', '$http', '$window'];

/*
* This service connects to the frePPLe web service using a web socket.
* The URL of the web socket is retrieved from the global variable "service_url".
* The authentication is retrieved from the global variable "service_token".
*/
function webfactory($rootScope, $websocket, $interval) {
function webfactory($rootScope, $websocket, $interval, $http, $window) {
'use strict';
var debug = true;
var debug = false;
var authenticated = false;
var message='';
var themodal = angular.element(document);

function showerrormodal(msg) {
angular.element("#controller").scope().databaseerrormodal = false;

if (typeof msg === 'string') {
message = '<p>'+msg+'</p>';
} else if (typeof msg === 'object') {
message = '<div style="width: 100%; overflow: auto;" class="webservicerror">'+ msg.description + '</div>';
} else {
message = '<p>Websocket connection is not working.</p><p>Please check that <strong>plan.webservice</strong> parameter is set to <strong>true</strong>,<br>and <strong>execute the plan</strong>.</p>';
}

angular.element("#controller").scope().$applyAsync(function(){
if (typeof msg === 'object') {
if (msg.hasOwnProperty('category') && msg.hasOwnProperty('description')) {
themodal.find('.modal-title span').html('Webservice error');
themodal.find('.modal-body').css({'width':500,'height':350,'overflow':'auto'});
themodal.find('#savechangesparagraph').hide();
themodal.find('#saveAbutton').hide();
themodal.find('.modal-body').append(message);
}
} else {
themodal.find('.modal-title span').html('Websocket connection problem');
themodal.find('.modal-body').html('<div style="width: 100%; overflow: auto;">'+ message + '</div>');
}
});

angular.element(document).find('#popup2').modal('show');
}

var webservice = $websocket(service_url, {
reconnectIfNotNormalClose: true
});
Expand All @@ -37,21 +71,53 @@ function webfactory($rootScope, $websocket, $interval) {

webservice.onMessage(function(message) {
var jsondoc = angular.fromJson(message.data);
if (debug)
console.log(jsondoc);
$rootScope.$broadcast("websocket-" + jsondoc.category, jsondoc);
if (debug) console.log(jsondoc);
if (jsondoc.hasOwnProperty('category') && jsondoc.category === 'error') {
showerrormodal(jsondoc);
} else {
$rootScope.$broadcast("websocket-" + jsondoc.category, jsondoc);
}
});

var alreadyprocessing = false;
webservice.onError(function(message) {
message = '<p>Websocket connection is not working.</p><p>Please check that <strong>plan.webservice</strong> parameter is set to <strong>true</strong>,<br>and <strong>execute the plan</strong>.</p>';
angular.element("#controller").scope().databaseerrormodal = true;
angular.element("#controller").scope().$apply();
angular.element(document)
.find('#popup2 .modal-title span').html('Websocket connection problem');
angular.element(document)
.find('.modal-body').html('<div style="width: 100%; overflow: auto;">'+ message + '</div>');
angular.element(document).find('#popup2').modal('show');
angular.element("#controller").scope().$apply();

if (!alreadyprocessing) {
alreadyprocessing = true;
$http({
method: 'POST',
url: url_prefix + '/execute/api/frepple_start_web_service/'
}).then(function successCallback(response) {
if(response.data.message !== "Successfully launched task") {
showerrormodal();
} else {
const taskid = response.data.taskid;
var answer = {};
const idUrl = url_prefix + '/execute/api/status/?id=' + taskid;
var testsuccess = $interval(function(counter) {
$http({
method: 'POST',
url: idUrl
}).then(function(response) {
showerrormodal('Starting Web Service, please wait a moment.');
angular.element(document).find('#saveAbutton').hide();
answer = response.data[Object.keys(response.data)];
if (answer.message === "Web service active") {
$interval.cancel(testsuccess);
$window.location.reload();
} else if (answer.finished !== "None" && answer.status !== "Web service active") {
$interval.cancel(testsuccess);
showerrormodal();
alreadyprocessing = false;
}
});
}, 1000, 0); //every second
}
}, function errorCallback(response) {
showerrormodal(response.data);
});
}

});

function subscribe(msg, callback) {
Expand All @@ -64,9 +130,14 @@ function webfactory($rootScope, $websocket, $interval) {
function send(data) {
if (webservice.readyState > 1) {
webservice = $websocket(service_url);
authenticated = false;
}
if (!authenticated) {
webservice.send("/authenticate/" + service_token);
authenticated = true;
}
if (debug)
console.log("send:" + data);
console.log("send:" + data);
webservice.send(data);
}

Expand All @@ -75,4 +146,5 @@ function webfactory($rootScope, $websocket, $interval) {
subscribe: subscribe
};
return methods;

}
69 changes: 69 additions & 0 deletions freppledb/common/static/css/frepple.less
Expand Up @@ -817,3 +817,72 @@ h1 small {
color: #777777;
}
}

// Wizard

.fill-primary {
fill: @panel-default-heading-bg;
}

.fill-primary-light {
fill: lighten(@panel-default-heading-bg, 20%);
}

@light-panel-header: lighten(@panel-default-heading-bg, 20%);

.getBackground2Steps(@color1, @color2, @color3) {
@r1: ceil(red(@color1));
@g1: ceil(green(@color1));
@b1: ceil(blue(@color1));
@r2: ceil(red(@color2));
@g2: ceil(green(@color2));
@b2: ceil(blue(@color2));
@r3: ceil(red(@color3));
@g3: ceil(green(@color3));
@b3: ceil(blue(@color3));
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none' width='500' height='10' viewBox='0 0 500 100'><path fill='rgb(@{r1},@{g1},@{b1})' stroke-width='2' stroke='rgb(@{r3},@{g3},@{b3})' d='m0,0 h225 l25,50 l-25,50 h-225 z'/><path fill='rgb(@{r2},@{g2},@{b2})' stroke-width='2' stroke='rgb(@{r3},@{g3},@{b3})' d='m225,0 h275 v100 h-275 l25,-50 z'/></svg>");
background-size: 100% 100%;
background-color: transparent;
}

.getBackground3Steps(@color1, @color2, @color3, @color4) {
@r1: ceil(red(@color1));
@g1: ceil(green(@color1));
@b1: ceil(blue(@color1));
@r2: ceil(red(@color2));
@g2: ceil(green(@color2));
@b2: ceil(blue(@color2));
@r3: ceil(red(@color3));
@g3: ceil(green(@color3));
@b3: ceil(blue(@color3));
@r4: ceil(red(@color4));
@g4: ceil(green(@color4));
@b4: ceil(blue(@color4));
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' preserveAspectRatio='none' width='500' height='10' viewBox='0 0 500 100'><path fill='rgb(@{r1},@{g1},@{b1})' stroke-width='2' stroke='rgb(@{r4},@{g4},@{b4})' d='m0,0 h141 l25,50 l-25,50 h-141 z'/><path fill='rgb(@{r2},@{g2},@{b2})' stroke-width='2' stroke='rgb(@{r4},@{g4},@{b4})' d='m141,0 h166 l25,50 l-25,50 h-166 l25,-50 z'/><path fill='rgb(@{r3},@{g3},@{b3})' stroke-width='2' stroke='rgb(@{r4},@{g4},@{b4})' d='m307,0 h194 v100 h-194 l25,-50 z'/></svg>");
background-size: 100% 100%;
background-color: transparent;
}

.wizard-1-of-2 table, .wizard-2-of-2 table, .wizard-1-of-3 table, .wizard-2-of-3 table, .wizard-3-of-3 table {
background-color: transparent;
}

.wizard-1-of-2 {
.getBackground2Steps(@panel-default-heading-bg, @light-panel-header, @panel-default-heading-bg);
}

.wizard-2-of-2 {
.getBackground2Steps(@light-panel-header, @panel-default-heading-bg, @panel-default-heading-bg);
}

.wizard-1-of-3 {
.getBackground3Steps(@panel-default-heading-bg, @light-panel-header, @light-panel-header, @panel-default-heading-bg);
}

.wizard-2-of-3 {
.getBackground3Steps(@light-panel-header, @panel-default-heading-bg, @light-panel-header, @panel-default-heading-bg);
}

.wizard-3-of-3 {
.getBackground3Steps(@light-panel-header, @light-panel-header, @panel-default-heading-bg, @panel-default-heading-bg);
}
3 changes: 1 addition & 2 deletions freppledb/common/static/js/frepple.js
Expand Up @@ -2319,7 +2319,7 @@ var dashboard = {
});
});

$("#workarea").each( function() {
$("#dashboard").each( function() {
Sortable.create($(this)[ 0 ], {
group: "cockpit",
handle: "h1",
Expand All @@ -2328,7 +2328,6 @@ var dashboard = {
});
});

//stop: dashboard.save
$(".panel-toggle").click(function() {
var icon = $(this);
icon.toggleClass("fa-minus fa-plus");
Expand Down
6 changes: 3 additions & 3 deletions freppledb/common/templates/admin/base_site_grid.html
Expand Up @@ -154,10 +154,10 @@
return true;
},{% endif %}
loadComplete: function(data) {
{% if reportclass.message_when_empty and not filters %}
{% if reportclass.message_when_empty %}
$("#grid_empty_message").remove();
if (data.records == 0)
$("#grid").parent().append(
if (data.records == 0 && $(this).getGridParam("postData").filters === undefined)
$(this).parent().append(
`<div id="grid_empty_message" style="text-align:center; margin-top:5em">
{% include reportclass.message_when_empty %}
</div>`
Expand Down
2 changes: 2 additions & 0 deletions freppledb/common/templates/index.html
Expand Up @@ -27,6 +27,7 @@

{% block content %}
{% getDashboard as dashboard hiddenwidgets %}
<div id="dashboard">
{% for row in dashboard %}
<div class="row" data-cockpit-row="{{ row.rowname }}">
<div class="col-md-10">
Expand Down Expand Up @@ -101,6 +102,7 @@ <h1 class="pull-right">
{% if forloop.last %}</script>{% endif %}
{% endfor %}
{% endfor %}
</div>
{% include "admin/subtemplate_timebuckets.html" %}
<script>
var hiddenwidgets = [
Expand Down
6 changes: 3 additions & 3 deletions freppledb/execute/commands.py
Expand Up @@ -107,9 +107,9 @@ def getWeight(cls, **kwargs):
@classmethod
def DISABLED_debugResource(cls, res, mode):
# if res.name != 'my favorite resource': return
logger.debug("=> Situation on resource %s" % res.name)
print("=> Situation on resource %s" % res.name)
for j in res.loadplans:
logger.debug(
print(
"=> %s %s %s %s %s %s %s"
% (
j.quantity,
Expand All @@ -127,7 +127,7 @@ def DISABLED_debugResource(cls, res, mode):
@classmethod
def DISABLED_debugDemand(cls, dem, mode):
if dem.name == "my favorite demand":
logger.debug("=> Starting to plan demand %s" % dem.name)
print("=> Starting to plan demand %s" % dem.name)
cls.solver.loglevel = 2
else:
cls.solver.loglevel = 0
Expand Down

0 comments on commit 046f37c

Please sign in to comment.