Use 'tabs' instead Workflow factory

This patch chenges workflow factory to 'tabs' of json-schema-form.
Also fix the use of checkbox and checkboxes.

Change-Id: I5ed0bc5fa1d302a0a0dc1dbc889ccb9e8eaa7dbf
This commit is contained in:
Shu Muto 2016-11-28 20:47:18 +09:00
parent 5f161d21b6
commit 1b529bf087
10 changed files with 241 additions and 395 deletions

View File

@ -26,23 +26,23 @@
createService.$inject = [
'$location',
'horizon.app.core.openstack-service-api.{{cookiecutter.api_module}}',
'horizon.app.core.openstack-service-api.policy',
'horizon.framework.util.actions.action-result.service',
'horizon.framework.util.i18n.gettext',
'horizon.framework.util.q.extensions',
'horizon.framework.widgets.modal.wizard-modal.service',
'horizon.framework.widgets.toast.service',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.events',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.model',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.resourceType',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.workflow'
];
function createService(
$location, policy, actionResult, gettext, $qExtensions, wizardModalService,
toast, events, resourceType, workflow
$location, api, policy, actionResult, gettext, $qExtensions,
toast, events, model, resourceType, workflow
) {
var scope;
var message = {
success: gettext('{{cookiecutter.panel_func}} %s was successfully created.')
};
@ -57,21 +57,19 @@
//////////////
function initScope($scope) {
scope = $scope;
scope.workflow = workflow;
scope.$on('$destroy', function() {
});
function initScope() {
}
function perform(selected) {
// for creation according to selected item
scope.selected = selected;
return wizardModalService.modal({
scope: scope,
workflow: workflow.init('create'),
submit: submit
}).result;
function perform() {
// modal title, buttons
var title, submitText, submitIcon;
title = gettext("Create {{cookiecutter.panel_func}}");
submitText = gettext("Create");
submitIcon = "fa fa-check";
model.init();
var result = workflow.init(title, submitText, submitIcon, model.spec);
return result.then(submit);
}
function allowed() {
@ -80,7 +78,8 @@
}
function submit(){
return workflow.save().then(success);
model.cleanProperties();
return api.create{{cookiecutter.panel_func}}(model.spec).then(success);
}
function success(response) {

View File

@ -26,23 +26,23 @@
updateService.$inject = [
'$location',
'horizon.app.core.openstack-service-api.{{cookiecutter.api_module}}',
'horizon.app.core.openstack-service-api.policy',
'horizon.framework.util.actions.action-result.service',
'horizon.framework.util.i18n.gettext',
'horizon.framework.util.q.extensions',
'horizon.framework.widgets.modal.wizard-modal.service',
'horizon.framework.widgets.toast.service',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.events',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.model',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.resourceType',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.workflow'
];
function updateService(
$location, policy, actionResult, gettext, $qExtensions, wizardModalService,
toast, events, resourceType, workflow
$location, api, policy, actionResult, gettext, $qExtensions,
toast, events, model, resourceType, workflow
) {
var scope;
var message = {
success: gettext('{{cookiecutter.panel_func}} %s was successfully updated.')
};
@ -53,25 +53,42 @@
allowed: allowed
};
var id;
return service;
//////////////
function initScope($scope) {
scope = $scope;
scope.workflow = workflow;
scope.$on('$destroy', function() {
});
function initScope() {
}
function perform(selected) {
// to use selected item for step controllers
scope.selected = selected;
return wizardModalService.modal({
scope: scope,
workflow: workflow.init('update', selected.id),
submit: submit
}).result;
// modal title, buttons
var title, submitText, submitIcon;
title = gettext("Update {{cookiecutter.panel_func}}");
submitText = gettext("Update");
submitIcon = "fa fa-check";
model.init();
// load current data
id = selected.id;
var deferred = api.get{{cookiecutter.panel_func}}(id);
deferred.then(onLoad);
function onLoad(response) {
model.spec.id = response.data.id;
model.spec.name = response.data.name;
model.spec.description = response.data.description;
model.spec.enabled = response.data.enabled;
model.spec.size = response.data.size;
model.spec.temperature = response.data.temperature;
model.spec.base = response.data.base;
model.spec.flavor = response.data.flavor;
model.spec.topping = response.data.topping;
}
var result = workflow.init(title, submitText, submitIcon, model.spec);
return result.then(submit);
}
function allowed() {
@ -80,7 +97,8 @@
}
function submit(){
return workflow.save().then(success);
model.cleanProperties();
return api.update{{cookiecutter.panel_func}}(id, model.spec).then(success);
}
function success(response) {

View File

@ -1,7 +0,0 @@
<div ng-controller="horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.workflow.{{cookiecutter.panel}}InfoController as ctrl">
<form name="schemaForm"
sf-schema="ctrl.schema"
sf-form="ctrl.form"
sf-model="ctrl.model">
</form>
</div>

View File

@ -1,104 +0,0 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
(function() {
'use strict';
/**
* @ngdoc controller
* @name {{cookiecutter.panel}}InfoController
* @ngController
* @description
* Controller for the {{cookiecutter.panel}} info step in create/update workflow
*/
angular
.module('horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s')
.controller(
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.workflow.{{cookiecutter.panel}}InfoController',
{{cookiecutter.panel}}InfoController);
{{cookiecutter.panel}}InfoController.$inject = [
'$q',
'horizon.app.core.openstack-service-api.{{cookiecutter.api_module}}',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.model',
'horizon.framework.util.i18n.gettext'
];
function {{cookiecutter.panel}}InfoController($q, api, model, gettext) {
var ctrl = this;
ctrl.schema = {
type: 'object',
properties: {
name: {
title: gettext('Name'),
type: 'string'
},
description: {
title: gettext('Description'),
type: 'string'
},
enabled: {
title: gettext('Enabled'),
type: 'boolean',
default: true
}
},
required: ['name']
};
ctrl.form = [
{
type: 'section',
htmlClass: 'row',
items: [
{
type: 'section',
htmlClass: 'col-sm-12',
items: [
{
key: 'name',
placeholder: gettext('Name of the {{cookiecutter.panel}} to create.')
},
{
key: 'description',
type: 'textarea'
},
{
key: 'enabled',
type: 'checkbox',
titleMap: [
{value: true, name: ''}
]
}
]
}
]
}
];
ctrl.model = model.spec;
if (model.type === 'update') {
var deferred = api.get{{cookiecutter.panel_func}}(model.spec.id);
deferred.then(onLoad);
function onLoad(response) {
ctrl.model.name = model.spec.name = response.data.name;
ctrl.model.description = model.spec.description = response.data.description;
ctrl.model.enabled = model.spec.enabled = response.data.enabled;
}
}
}
})();

View File

@ -1,7 +0,0 @@
<div ng-controller="horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.workflow.{{cookiecutter.panel}}RecipeController as ctrl">
<form name="schemaForm"
sf-schema="ctrl.schema"
sf-form="ctrl.form"
sf-model="ctrl.model">
</form>
</div>

View File

@ -1,156 +0,0 @@
/**
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
(function() {
'use strict';
/**
* @ngdoc controller
* @name {{cookiecutter.panel}}RecipeController
* @ngController
* @description
* Controller for the {{cookiecutter.panel}} recipe step in create/update workflow
*/
angular
.module('horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s')
.controller(
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.workflow.{{cookiecutter.panel}}RecipeController',
{{cookiecutter.panel}}RecipeController);
{{cookiecutter.panel}}RecipeController.$inject = [
'$q',
'horizon.app.core.openstack-service-api.{{cookiecutter.api_module}}',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.model',
'horizon.framework.util.i18n.gettext'
];
function {{cookiecutter.panel}}RecipeController($q, api, model, gettext) {
var ctrl = this;
ctrl.schema = {
type: 'object',
properties: {
size: {
title: gettext('Size'),
type: 'string',
default: 'M'
},
temperature: {
title: gettext('Temperature'),
type: 'string',
default: 'H'
},
base: {
title: gettext('Base'),
type: 'string'
},
flavor: {
title: gettext('Flavor'),
type: 'string'
},
topping: {
title: gettext('Topping'),
type: 'string'
}
},
required: ['base']
};
ctrl.form = [
{
type: 'section',
htmlClass: 'row',
items: [
{
type: 'section',
htmlClass: 'col-sm-12',
items: [
{
key: 'size',
type: 'radiobuttons',
titleMap: [
// if get options from API, call $scope.$broadcast('schemaFormRedraw')
{value: 'S', name: gettext('Small')},
{value: 'M', name: gettext('Medium')},
{value: 'L', name: gettext('Large')},
{value: 'XL', name: gettext('Extra Large')}
]
},
{
key: 'temperature',
type: 'radiobuttons',
titleMap: [
// if get options from API, call $scope.$broadcast('schemaFormRedraw')
{value: 'H', name: gettext('Hot')},
{value: 'I', name: gettext('Ice')}
]
},
{
key: 'base',
type: 'select',
titleMap: [
// if get options from API, call $scope.$broadcast('schemaFormRedraw')
{value: 'blend', name: gettext('House Blend'), group: gettext('Coffee')},
{value: 'mandheling', name: gettext('Mandheling'), group: gettext('Coffee')},
{value: 'colombia', name: gettext('Colombia'), group: gettext('Coffee')},
{value: 'espresso', name: gettext('Espresso'), group: gettext('Coffee')},
{value: 'earl_gray', name: gettext('Earl Gray'), group: gettext('Tea')},
{value: 'darjeeling', name: gettext('Darjeeling'), group: gettext('Tea')},
{value: 'orange_pekoe', name: gettext('Orange Pekoe'), group: gettext('Tea')}
]
},
{
key: 'flavor',
type: 'select',
titleMap: [
// if get options from API, call $scope.$broadcast('schemaFormRedraw')
{value: 'chocolate', name: gettext('Chocolate')},
{value: 'mocha', name: gettext('Mocha')},
{value: 'strawberry', name: gettext('Strawberry')},
{value: 'blueberry', name: gettext('Blueberry')},
{value: 'raspberry', name: gettext('Raspberry')}
]
},
{
key: 'topping',
type: 'checkboxes',
titleMap: [
// if get options from API, call $scope.$broadcast('schemaFormRedraw')
{value: 'clushed_nuts', name: gettext('Clushed Nuts')},
{value: 'whip_cream', name: gettext('Whip Cream')},
{value: 'mixed_serial', name: gettext('Mixed Serial')}
]
}
]
}
]
}
];
ctrl.model = model.spec;
if (model.type === 'update') {
var deferred = api.get{{cookiecutter.panel_func}}(model.spec.id);
deferred.then(onLoad);
function onLoad(response) {
ctrl.model.size = model.spec.size = response.data.size;
ctrl.model.temperature = model.spec.temperature = response.data.temperature;
ctrl.model.base = model.spec.base = response.data.base;
ctrl.model.flavor = model.spec.flavor = response.data.flavor;
ctrl.model.topping = model.spec.topping = response.data.topping;
}
}
}
})();

View File

@ -25,64 +25,187 @@
.factory('horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.workflow', workflow);
workflow.$inject = [
'horizon.app.core.workflow.factory',
'horizon.dashboard.{{cookiecutter.panel_group}}.basePath',
'horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.model',
'horizon.framework.util.i18n.gettext'
'horizon.framework.util.i18n.gettext',
'horizon.framework.widgets.form.ModalFormService'
];
function workflow(workflowFactory, basePath, model, gettext) {
var workflow = {
// params
type: '',
function workflow(basePath, gettext, modal) {
var workflow = {
init: init
};
// methods
init: init,
save: save
};
function init(title, submitText, submitIcon, model) {
var schema, form;
function init(type, id) {
var title, btnText;
workflow.type = type;
if (type === 'create') {
title = gettext('Create {{cookiecutter.panel_func}}');
btnText = gettext('Create');
model.init('create');
} else if (type === 'update') {
title = gettext('Update {{cookiecutter.panel_func}}');
btnText = gettext('Update');
model.init('update', id);
}
return workflowFactory({
title: title,
steps: [
{
title: gettext('Info'),
templateUrl: basePath + '{{cookiecutter.panel}}s/workflow/info/info.html',
helpUrl: basePath + '{{cookiecutter.panel}}s/workflow/info/info.help.html',
formName: '{{cookiecutter.panel}}InfoForm'
// schema
schema = {
"type": "object",
"properties": {
"name": {
"title": gettext("Name"),
"type": "string"
},
{
title: gettext('Recipe'),
templateUrl: basePath + '{{cookiecutter.panel}}s/workflow/recipe/recipe.html',
helpUrl: basePath + '{{cookiecutter.panel}}s/workflow/recipe/recipe.help.html',
formName: '{{cookiecutter.panel}}RecipeForm'
"description": {
"title": gettext("Description"),
"type": "string"
},
"enabled": {
"title": gettext("Enabled"),
"type": "boolean",
"default": true
},
"size": {
"title": gettext("Size"),
"type": "string",
"default": "M"
},
"temperature": {
"title": gettext("Temperature"),
"type": "string",
"default": "H"
},
"base": {
"title": gettext("Base"),
"type": "string",
"default": ""
},
"flavor": {
"title": gettext("Flavor"),
"type": "string",
"default": ""
},
"topping": {
"title": gettext("Topping")
}
],
btnText: {
finish: btnText
},
btnIcon: {
finish: 'fa fa-check'
}
});
}
};
function save(){
return model.save();
// form
form = [
{
"type": "tabs",
"tabs": [
{
"title": gettext("Info"),
"help": basePath + "{{cookiecutter.panel}}s/workflow/info.help.html",
"items": [
{
"key": "name",
"placeholder": gettext("Name of the {{cookiecutter.panel}}."),
"required": true
},
{
"key": "description",
"type": "textarea"
},
{
"key": "enabled",
"type": "checkbox"
}
]
},
{
"title": gettext("Recipe"),
"help": basePath + "{{cookiecutter.panel}}s/workflow/recipe.help.html",
"items": [
{
"key": "size",
"type": "radiobuttons",
"titleMap": [
{"value": "S", "name": gettext("Small")},
{"value": "M", "name": gettext("Medium")},
{"value": "L", "name": gettext("Large")},
{"value": "XL", "name": gettext("Extra Large")}
]
},
{
"key": "temperature",
"type": "radiobuttons",
"titleMap": [
{"value": "H", "name": gettext("Hot")},
{"value": "I", "name": gettext("Ice")}
]
},
{
"key": "base",
"type": "select",
"titleMap": [
{"value": "", "name": gettext("Choose base.")},
{
"value": "blend",
"name": gettext("House Blend"),
"group": gettext("Coffee")
},
{
"value": "mandheling",
"name": gettext("Mandheling"),
"group": gettext("Coffee")},
{
"value": "colombia",
"name": gettext("Colombia"),
"group": gettext("Coffee")
},
{
"value": "espresso",
"name": gettext("Espresso"),
"group": gettext("Coffee")
},
{
"value": "earl_gray",
"name": gettext("Earl Gray"),
"group": gettext("Tea")
},
{
"value": "darjeeling",
"name": gettext("Darjeeling"),
"group": gettext("Tea")},
{
"value": "orange_pekoe",
"name": gettext("Orange Pekoe"),
"group": gettext("Tea")
}
]
},
{
"key": "flavor",
"type": "select",
"titleMap": [
{"value": "", "name": gettext("Choose flavor.")},
{"value": "chocolate", "name": gettext("Chocolate")},
{"value": "mocha", "name": gettext("Mocha")},
{"value": "strawberry", "name": gettext("Strawberry")},
{"value": "blueberry", "name": gettext("Blueberry")},
{"value": "raspberry", "name": gettext("Raspberry")}
]
},
{
"key": "topping",
"type": "checkboxes",
"titleMap": [
{"value": "clushed_nuts", "name": gettext("Clushed Nuts")},
{"value": "whip_cream", "name": gettext("Whip Cream")},
{"value": "mixed_serial", "name": gettext("Mixed Serial")}
]
}
] // items
} // tab
] // tabs
}
]; // form
var config = {
"title": title,
"submitText": submitText,
"schema": schema,
"form": form,
"model": model
};
return modal.open(config);
}
return workflow;
}
})();

View File

@ -25,59 +25,39 @@
.factory('horizon.dashboard.{{cookiecutter.panel_group}}.{{cookiecutter.panel}}s.model', model);
model.$inject = [
'horizon.app.core.openstack-service-api.{{cookiecutter.api_module}}'
];
function model(api) {
function model() {
var model = {
// params
spec: {},
type: '',
"spec": {},
// methods
init: init,
save: save
"init": init,
"cleanProperties": cleanProperties
};
function init(type, id) {
model.type = type;
// Reset model
function init() {
// initialize model
model.spec = {
id: id,
name: null, // text required
description: null, // textarea
enabled: true, // checkbox
size: 'M', // radio
temperature: 'H', // radio
base: null, // select required
flavor: null, // select
topping: null // checkboxes
"id": "",
"name": "", // text required
"description": "", // textarea
"enabled": true, // checkbox
"size": "M", // radio
"temperature": "H", // radio
"base": "", // select
"flavor": "", // select
"topping": "" // checkboxes
};
}
function save() {
var finalSpec = angular.copy(model.spec);
cleanNullProperties(finalSpec);
var id = finalSpec.id;
delete finalSpec.id;
if (model.type === 'create') {
delete finalSpec.id;
return api.create{{cookiecutter.panel_func}}(finalSpec);
} else {
return api.update{{cookiecutter.panel_func}}(id, finalSpec);
}
}
function cleanNullProperties(finalSpec) {
// Initially clean fields that don't have any value.
for (var key in finalSpec) {
if (finalSpec.hasOwnProperty(key) && finalSpec[key] === null) {
delete finalSpec[key];
}
}
function cleanProperties() {
delete model.spec.id;
delete model.spec.tabs;
}
return model;
}
})();