dashboard: can now change the sidebar

This commit is contained in:
nemunaire 2019-01-19 08:01:29 +01:00
commit a4e0a90adf
7 changed files with 410 additions and 57 deletions

View file

@ -22,8 +22,17 @@ type FICPublicScene struct {
Params map[string]interface{} `json:"params"`
}
func readPublic(path string) ([]FICPublicScene, error) {
var s []FICPublicScene
type FICPublicDisplay struct {
Scenes []FICPublicScene `json:"scenes"`
Side []FICPublicScene `json:"side"`
CustomCountdown map[string]interface{} `json:"customCountdown"`
HideEvents bool `json:"hideEvents"`
HideCountdown bool `json:"hideCountdown"`
HideCarousel bool `json:"hideCarousel"`
}
func readPublic(path string) (FICPublicDisplay, error) {
var s FICPublicDisplay
if fd, err := os.Open(path); err != nil {
return s, err
} else {
@ -38,7 +47,7 @@ func readPublic(path string) ([]FICPublicScene, error) {
}
}
func savePublicTo(path string, s []FICPublicScene) error {
func savePublicTo(path string, s FICPublicDisplay) error {
if fd, err := os.Create(path); err != nil {
return err
} else {
@ -57,20 +66,20 @@ func getPublic(ps httprouter.Params, body []byte) (interface{}, error) {
if _, err := os.Stat(path.Join(DashboardDir, fmt.Sprintf("public%s.json", ps.ByName("sid")))); !os.IsNotExist(err) {
return readPublic(path.Join(DashboardDir, fmt.Sprintf("public%s.json", ps.ByName("sid"))))
} else {
return []FICPublicScene{}, nil
return FICPublicDisplay{Scenes: []FICPublicScene{}, Side: []FICPublicScene{}}, nil
}
}
func deletePublic(ps httprouter.Params, body []byte) (interface{}, error) {
if err := savePublicTo(path.Join(DashboardDir, fmt.Sprintf("public%s.json", ps.ByName("sid"))), []FICPublicScene{}); err != nil {
if err := savePublicTo(path.Join(DashboardDir, fmt.Sprintf("public%s.json", ps.ByName("sid"))), FICPublicDisplay{}); err != nil {
return nil, err
} else {
return []FICPublicScene{}, err
return FICPublicDisplay{Scenes: []FICPublicScene{}, Side: []FICPublicScene{}}, nil
}
}
func savePublic(ps httprouter.Params, body []byte) (interface{}, error) {
var scenes []FICPublicScene
var scenes FICPublicDisplay
if err := json.Unmarshal(body, &scenes); err != nil {
return nil, err
}

View file

@ -165,7 +165,7 @@ angular.module("FICApp")
})
.factory("Scene", function($resource) {
return $resource("/api/public/:screenId", { screenId: '@id' }, {
'update': {method: 'PUT', isArray: true},
'update': {method: 'PUT'},
})
})
.factory("Team", function($resource) {
@ -573,7 +573,7 @@ angular.module("FICApp")
.controller("PublicController", function($scope, $rootScope, $routeParams, $location, Scene, Theme, Teams, Exercice) {
$scope.screens = [0,1,2,3,4,5,6,7,8,9];
$scope.screenid = $routeParams.screenId;
$scope.scenes = Scene.query({ screenId: $routeParams.screenId });
$scope.display = Scene.get({ screenId: $routeParams.screenId });
$scope.themes = Theme.query();
$scope.teams = Teams.get();
@ -594,6 +594,14 @@ angular.module("FICApp")
"table": "Tableau",
"rank": "Classement",
};
$scope.typeside = {
"welcome": "Messages de bienvenue",
"themes": "Présentation des thèmes",
"exercice_follow": "Dernier exercice des événements",
"exercice": "Exercice",
"message": "Message",
"panel": "Boîte",
};
$scope.welcome_types = {
"teams": "Accueil des équipes",
"public": "Accueil du public",
@ -625,12 +633,12 @@ angular.module("FICApp")
$scope.clearScene = function() {
$scope.someUpdt = true;
$scope.scenes = [];
$scope.display.scenes = [];
};
$scope.presetScene = function(scene) {
$scope.someUpdt = true;
if (scene == "registration")
$scope.scenes = [
if (scene == "registration") {
$scope.display.scenes = [
{
type: "welcome",
params: { kind: "teams" },
@ -640,19 +648,29 @@ angular.module("FICApp")
params: { kind: "public", notitle: true },
},
];
else if (scene == "welcome")
$scope.scenes = [
$scope.display.side = [
{
type: "welcome",
params: { kind: "public" },
type: "themes",
params: { },
},
];
}
else if (scene == "welcome") {
$scope.display.scenes = [
{
type: "carousel",
params: { color: "info", kind: "themes", title: "Présentation des entreprises ciblées"},
},
];
else if (scene == "start")
$scope.scenes = [
$scope.display.side = [
{
type: "welcome",
params: { kind: "public" },
},
];
}
else if (scene == "start") {
$scope.display.scenes = [
{
type: "welcome",
params: { kind: "public" },
@ -662,8 +680,15 @@ angular.module("FICApp")
params: { color: "success", end: null, lead: "Go, go, go !", title: "Le challenge forensic va bientôt commencer !" },
},
];
$scope.display.side = [
{
type: "themes",
params: { },
},
];
}
else if (scene == "summary") {
$scope.scenes = [
$scope.display.scenes = [
{
type: "table",
params: { kind: "levels", levels: [1,2,3,4,5], themes: $scope.themes.map(function(z, i) { return z.id; }), total: true },
@ -673,57 +698,107 @@ angular.module("FICApp")
params: { limit: 10, which: "general" },
},
];
}
else if (scene == "happyhour") {
$scope.scenes = [
$scope.display.side = [
{
type: "countdown",
params: { color: "warning", end: new Date(Date.now() + 3602000).toISOString(), lead: "Terminé !", title: "Heure joyeuse : chaque résolution compte double !" },
},
{
type: "rank",
params: { limit: 10, which: "general" },
type: "exercice_follow",
params: { },
},
];
}
else if (scene == "happyhour") {
$scope.display.customCountdown = {
show: true,
shadow: "#E8CF5C",
end: new Date(Date.now() + 1802000).toISOString(),
before: "Heure joyeuse : chaque résolution compte double !",
after: "Heure joyeuse terminée !",
}
}
else if (scene == "freehintquarter") {
$scope.display.customCountdown = {
show: true,
shadow: "#3DD28F",
end: new Date(Date.now() + 902000).toISOString(),
before: "Quart d'heure facile : indices dévoilés !",
after: "Quart d'heure facile terminée !",
}
}
};
$scope.genSceneCountdownDate = function(scene, duration) {
scene.params.end = (new Date(Date.now() + duration)).toISOString();
}
$scope.genCustomCountdownDate = function(duration) {
$scope.display.customCountdown.end = (new Date(Date.now() + duration)).toISOString();
}
$scope.saveScenes = function() {
$scope.someUpdt = false;
var prms = Scene.update({ screenId: $scope.screenid }, $scope.scenes);
var prms = Scene.update({ screenId: $scope.screenid }, $scope.display);
prms.$promise.then(function() {
$rootScope.newBox('success', 'Scene successfully published!');
}, function(response) {
$rootScope.newBox('danger', 'An error occurs when saving scene:', response.data.errmsg);
});
};
$scope.addSide = function() {
$scope.someUpdt = true;
$scope.display.side.push({params: {}});
};
$scope.delSide = function(s) {
$scope.someUpdt = true;
angular.forEach($scope.display.side, function(scene, k) {
if (scene == s)
$scope.display.side.splice(k, 1);
});
};
$scope.upSide = function(s) {
$scope.someUpdt = true;
angular.forEach($scope.display.side, function(scene, k) {
if (scene == s && k > 0) {
$scope.display.side.splice(k, 1);
$scope.display.side.splice(k - 1, 0, scene);
}
});
};
$scope.downSide = function(s) {
$scope.someUpdt = true;
var move = true;
angular.forEach($scope.display.side, function(scene, k) {
if (move && scene == s) {
$scope.display.side.splice(k, 1);
$scope.display.side.splice(k + 1, 0, scene);
move = false;
}
});
};
$scope.addScene = function() {
$scope.someUpdt = true;
$scope.scenes.push({params: {}});
$scope.display.scenes.push({params: {}});
};
$scope.delScene = function(s) {
$scope.someUpdt = true;
angular.forEach($scope.scenes, function(scene, k) {
angular.forEach($scope.display.scenes, function(scene, k) {
if (scene == s)
$scope.scenes.splice(k, 1);
$scope.display.scenes.splice(k, 1);
});
};
$scope.upScene = function(s) {
$scope.someUpdt = true;
angular.forEach($scope.scenes, function(scene, k) {
angular.forEach($scope.display.scenes, function(scene, k) {
if (scene == s && k > 0) {
$scope.scenes.splice(k, 1);
$scope.scenes.splice(k - 1, 0, scene);
$scope.display.scenes.splice(k, 1);
$scope.display.scenes.splice(k - 1, 0, scene);
}
});
};
$scope.downScene = function(s) {
$scope.someUpdt = true;
var move = true;
angular.forEach($scope.scenes, function(scene, k) {
angular.forEach($scope.display.scenes, function(scene, k) {
if (move && scene == s) {
$scope.scenes.splice(k, 1);
$scope.scenes.splice(k + 1, 0, scene);
$scope.display.scenes.splice(k, 1);
$scope.display.scenes.splice(k + 1, 0, scene);
move = false;
}
});

View file

@ -13,21 +13,25 @@
<div class="dropdown-divider"></div>
<a class="dropdown-item" ng-click="presetScene('summary')">Résumé</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" ng-click="presetScene('freehintquarter')">Free Hint Quarter</a>
<a class="dropdown-item" ng-click="presetScene('happyhour')">Happy Hour</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" ng-click="clearScene()">Scène vide</a>
</div>
</div>
<button type="button" ng-click="addScene()" class="float-right btn btn-primary mr-sm-2"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Ajouter un élément</button>
<button type="button" ng-click="addSide()" class="float-right btn btn-primary mr-sm-2"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> élm. côté</button>
<button type="button" ng-click="addScene()" class="float-right btn btn-primary mr-sm-2"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> élm. central</button>
<button type="submit" class="float-right btn mr-sm-2" ng-class="{'btn-success': someUpdt,'btn-secondary': !someUpdt}"><span class="glyphicon glyphicon-save" aria-hidden="true"></span> Publier cette scène</button>
</h2>
<div class="alert alert-info" ng-if="!scenes.length">
<div class="row">
<div class="col-9">
<div class="alert alert-info" ng-if="!display.scenes.length">
<strong ng-if="!someUpdt">Aucun contenu n'est actuellement affiché.</strong>
<strong ng-if="someUpdt">Aucun contenu à afficher.</strong>
</div>
<div class="card mb-2" ng-repeat="scene in scenes" ng-class="{'bg-secondary': !scene.params.hide, 'bg-light': scene.params.hide}">
<div class="card mb-2" ng-repeat="scene in display.scenes" ng-class="{'bg-secondary': !scene.params.hide, 'bg-light': scene.params.hide}">
<div class="card-body">
<div class="form-group row">
@ -44,7 +48,7 @@
</div>
<button type="button" ng-click="upScene(scene)" class="btn btn-sm btn-light mb-2 mr-sm-2 mb-sm-0"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span></button>
<button type="button" ng-click="downScene(scene)" class="btn btn-sm btn-light mb-2 mr-sm-2 mb-sm-0"><span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span></button>
<button type="button" ng-click="delScene(scene)" class="btn btn-sm btn-warning mb-2 mr-sm-2 mb-sm-0"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span> Supprimer</button>
<button type="button" ng-click="delScene(scene)" class="btn btn-sm btn-warning mb-2 mr-sm-2 mb-sm-0"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></button>
</div>
</div>
@ -96,7 +100,19 @@
<div class="form-group row" ng-if="scene.type == 'countdown'">
<label for="cend" class="col-sm-2 col-form-label col-form-label-sm">Date de fin</label>
<div class="col-sm-10">
<input type="text" id="cend" ng-model="scene.params.end" class="form-control form-control-sm">
<div class="input-group mb-3">
<input type="text" id="cend" ng-model="scene.params.end" class="form-control form-control-sm">
<div class="input-group-append">
<button class="btn btn-sm btn-light dropdown-toggle" type="button" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item" ng-click="genSceneCountdownDate(scene, 310000)">5 minutes</a>
<a class="dropdown-item" ng-click="genSceneCountdownDate(scene, 910000)">15 minutes</a>
<a class="dropdown-item" ng-click="genSceneCountdownDate(scene, 1100000)">30 minutes</a>
<a class="dropdown-item" ng-click="genSceneCountdownDate(scene, 3700000)">1 heure</a>
<a class="dropdown-item" ng-click="genSceneCountdownDate(scene, 5500000)">1.5 heure</a>
</div>
</div>
</div>
</div>
</div>
@ -179,4 +195,129 @@
</div>
</div>
</div>
<div class="col-3">
<div class="card mb-2" ng-repeat="scene in display.side" ng-class="{'bg-secondary': !scene.params.hide, 'bg-light': scene.params.hide}">
<div class="card-body">
<div class="text-right mb-2">
<div class="btn-group-toggle" data-toggle="buttons" style="display: inline-block;">
<label class="btn btn-sm btn-secondary" ng-class="{'active':!scene.params.hide}">
<input type="checkbox" ng-model="scene.params.hide" autocomplete="off"><i class="glyphicon" ng-class="{'glyphicon-eye-open':scene.params.hide,'glyphicon-eye-close':!scene.params.hide}"></i>
</label>
</div>
<button type="button" ng-click="upSide(scene)" class="btn btn-sm btn-light mb-2 mr-sm-2 mb-sm-0"><span class="glyphicon glyphicon-chevron-up" aria-hidden="true"></span></button>
<button type="button" ng-click="downSide(scene)" class="btn btn-sm btn-light mb-2 mr-sm-2 mb-sm-0"><span class="glyphicon glyphicon-chevron-down" aria-hidden="true"></span></button>
<button type="button" ng-click="delSide(scene)" class="btn btn-sm btn-warning mb-2 mr-sm-2 mb-sm-0"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></button>
</div>
<div class="form-group">
<select class="custom-select custom-select-sm" id="type" ng-model="scene.type" ng-options="k as v for (k, v) in typeside"></select>
</div>
<div class="form-group row" ng-if="scene.type == 'panel' || scene.type == 'carousel' || scene.type == 'countdown'">
<label for="ptype" class="col-sm-4 col-form-label col-form-label-sm">Couleur</label>
<div class="col-sm-8">
<select class="custom-select custom-select-sm" id="ptype" ng-model="scene.params.color" ng-options="k as v for (k, v) in colors"></select>
</div>
</div>
<div class="form-group row" ng-if="scene.type == 'message' || scene.type == 'panel' || scene.type == 'carousel' || scene.type == 'countdown'">
<label for="mtitle" class="col-sm-4 col-form-label col-form-label-sm">Titre</label>
<div class="col-sm-8">
<input type="text" id="mtitle" ng-model="scene.params.title" class="form-control form-control-sm">
</div>
</div>
<div class="form-group row" ng-if="scene.type == 'message' || scene.type == 'panel' || scene.type == 'countdown'">
<label for="mlead" class="col-sm-4 col-form-label col-form-label-sm" ng-if="scene.type != 'countdown'">Lead</label>
<label for="mlead" class="col-sm-4 col-form-label col-form-label-sm" ng-if="scene.type == 'countdown'">Final</label>
<div class="col-sm-8">
<input type="text" id="mlead" ng-model="scene.params.lead" class="form-control form-control-sm">
</div>
</div>
<div class="form-group row" ng-if="scene.type == 'message' || scene.type == 'panel'">
<label for="mcnt" class="col-sm-4 col-form-label col-form-label-sm">HTML</label>
<div class="col-sm-8">
<textarea class="form-control form-control-sm" id="mcnt" ng-model="scene.params.html"></textarea>
</div>
</div>
<div class="form-group" ng-if="scene.type == 'exercice'">
<select class="custom-select custom-select-sm" id="eex" ng-model="scene.params.exercice" ng-options="ex.id as ex.title group by ex.path.split('/')[0] for ex in exercices"></select>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<label class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" ng-model="display.customCountdown.show">
<span class="custom-control-label">Activer timer secondaire</span>
</label>
</div>
<div class="card-body" ng-if="display.customCountdown && display.customCountdown.show">
<div class="form-group row">
<label for="timertxtbefore" class="col-sm-5 col-form-label col-form-label-sm">Titre avant</label>
<div class="col-sm-7">
<input type="text" id="timertxtbefore" ng-model="display.customCountdown.before" class="form-control form-control-sm">
</div>
</div>
<div class="form-group row">
<label for="timertxtafter" class="col-sm-5 col-form-label col-form-label-sm">Titre après</label>
<div class="col-sm-7">
<input type="text" id="timertxtafter" ng-model="display.customCountdown.after" class="form-control form-control-sm">
</div>
</div>
<div class="form-group row">
<label for="timercolor" class="col-sm-5 col-form-label col-form-label-sm">Couleur</label>
<div class="col-sm-7">
<input type="color" id="timercolor" ng-model="display.customCountdown.shadow" class="form-control form-control-sm">
</div>
</div>
<div class="form-group row">
<label for="timerend" class="col-sm-5 col-form-label col-form-label-sm">Évent</label>
<div class="col-sm-7">
<div class="input-group mb-3">
<input type="text" id="timerend" ng-model="display.customCountdown.end" class="form-control form-control-sm">
<div class="input-group-append">
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown"></button>
<div class="dropdown-menu">
<a class="dropdown-item" ng-click="genCustomCountdownDate(310000)">5 minutes</a>
<a class="dropdown-item" ng-click="genCustomCountdownDate(910000)">15 minutes</a>
<a class="dropdown-item" ng-click="genCustomCountdownDate(1100000)">30 minutes</a>
<a class="dropdown-item" ng-click="genCustomCountdownDate(3700000)">1 heure</a>
<a class="dropdown-item" ng-click="genCustomCountdownDate(5500000)">1.5 heure</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-check">
<label class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" ng-model="display.hideEvents">
<span class="custom-control-label">Cacher les événements</span>
</label>
</div>
<div class="form-check">
<label class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" ng-model="display.hideCountdown">
<span class="custom-control-label">Cacher le timer</span>
</label>
</div>
<div class="form-check">
<label class="custom-control custom-checkbox">
<input class="custom-control-input" type="checkbox" ng-model="display.hideCarousel">
<span class="custom-control-label">Cacher le carousel</span>
</label>
</div>
</div>
</div>
</form>