diff --git a/web/client/components/widgets/builder/wizard/ChartWizard.jsx b/web/client/components/widgets/builder/wizard/ChartWizard.jsx index e3ea282c9c..9dcb3bb1b4 100644 --- a/web/client/components/widgets/builder/wizard/ChartWizard.jsx +++ b/web/client/components/widgets/builder/wizard/ChartWizard.jsx @@ -9,8 +9,11 @@ const React = require('react'); const { wizardHandlers } = require('../../../misc/wizard/enhancers'); const loadingState = require('../../../misc/enhancers/loadingState')(({ loading, data }) => loading || !data, { width: 500, height: 200 }); - -const ChartType = require('./chart/ChartType'); +const noAttribute = require('./common/noAttributesEmptyView'); +const hasNoAttributes = ({ featureTypeProperties = [] }) => featureTypeProperties.filter(({ type =""} = {}) => type.indexOf("gml:") !== 0).length === 0; +const ChartType = noAttribute( + hasNoAttributes +)(require('./chart/ChartType')); const wfsChartOptions = require('./common/wfsChartOptions'); const ChartOptions = wfsChartOptions(require('./common/WPSWidgetOptions')); const WidgetOptions = require('./common/WidgetOptions'); @@ -91,6 +94,7 @@ module.exports = enhanceWizard(({ onChange = () => { }, onFinish = () => { }, se } hideButtons> { onChange("type", i); diff --git a/web/client/components/widgets/builder/wizard/CounterWizard.jsx b/web/client/components/widgets/builder/wizard/CounterWizard.jsx index 9c03771f1d..8d3ce8e3e1 100644 --- a/web/client/components/widgets/builder/wizard/CounterWizard.jsx +++ b/web/client/components/widgets/builder/wizard/CounterWizard.jsx @@ -11,9 +11,10 @@ const { compose, lifecycle } = require('recompose'); const {wizardHandlers} = require('../../../misc/wizard/enhancers'); const loadingState = require('../../../misc/enhancers/loadingState')(({loading, data}) => loading || !data, {width: 500, height: 200}); - const wfsChartOptions = require('./common/wfsChartOptions'); -const CounterOptions = wfsChartOptions(require('./common/WPSWidgetOptions')); +const noAttributes = require('./common/noAttributesEmptyView'); + +const CounterOptions = wfsChartOptions(noAttributes(({options = []}) => options.length === 0)(require('./common/WPSWidgetOptions'))); const WidgetOptions = require('./common/WidgetOptions'); const wpsCounter = require('../../enhancers/wpsCounter'); diff --git a/web/client/components/widgets/builder/wizard/__tests__/CounterWizard-test.jsx b/web/client/components/widgets/builder/wizard/__tests__/CounterWizard-test.jsx index 8dc67db55d..7744ad87ef 100644 --- a/web/client/components/widgets/builder/wizard/__tests__/CounterWizard-test.jsx +++ b/web/client/components/widgets/builder/wizard/__tests__/CounterWizard-test.jsx @@ -8,9 +8,11 @@ const React = require('react'); const ReactDOM = require('react-dom'); - +const {get} = require('lodash'); const expect = require('expect'); const CounterWizard = require('../CounterWizard'); + +const describeStates = require('json-loader!../../../../../test-resources/wfs/describe-states.json'); describe('CounterWizard component', () => { beforeEach((done) => { document.body.innerHTML = '
'; @@ -21,11 +23,20 @@ describe('CounterWizard component', () => { document.body.innerHTML = ''; setTimeout(done); }); - it('CounterWizard rendering with defaults', () => { + it('CounterWizard rendering empty-view', () => { ReactDOM.render(, document.getElementById("container")); const container = document.getElementById('container'); const el = container.querySelector('.ms-wizard'); expect(el).toExist(); + expect(container.querySelector('.chart-options-form')).toNotExist(); + expect(container.querySelector('.empty-state-container')).toExist(); + + }); + it('CounterWizard rendering with base attributes', () => { + ReactDOM.render(, document.getElementById("container")); + const container = document.getElementById('container'); + const el = container.querySelector('.ms-wizard'); + expect(el).toExist(); expect(container.querySelector('.chart-options-form')).toExist(); }); it('CounterWizard rendering widget options', () => { diff --git a/web/client/components/widgets/builder/wizard/common/noAttributesEmptyView.js b/web/client/components/widgets/builder/wizard/common/noAttributesEmptyView.js new file mode 100644 index 0000000000..2ba45caf36 --- /dev/null +++ b/web/client/components/widgets/builder/wizard/common/noAttributesEmptyView.js @@ -0,0 +1,25 @@ +/* + * Copyright 2018, GeoSolutions Sas. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. + */ + +const React = require('react'); +const emptyState = require('../../../../misc/enhancers/emptyState'); +const Message = require('../../../../I18N/Message'); + +/** + * Enhances a component to show the empty view in case of no attributes. + * @param {function} the test to show the empty view + */ +const noAttributes = (func) => emptyState( + func, + { + title: , + description: , + glyph: 'warning-sign' + } +); +module.exports = noAttributes; diff --git a/web/client/components/widgets/builder/wizard/counter/Toolbar.jsx b/web/client/components/widgets/builder/wizard/counter/Toolbar.jsx index 76626e071d..74a2fd9110 100644 --- a/web/client/components/widgets/builder/wizard/counter/Toolbar.jsx +++ b/web/client/components/widgets/builder/wizard/counter/Toolbar.jsx @@ -49,6 +49,13 @@ module.exports = ({openFilterEditor = () => {}, step = 0, stepButtons = [], edit }, ...stepButtons, { visible: step === 0, onClick: openFilterEditor, + /* if no valid attribute is present, filter must be disabled + * (Query panel don't work you can not proceed, so it doesn't make sense to + * create a filter if you can not create the widget) + * TODO: improve checking valid attributes presence instead + * of valid flag. + */ + disabled: !valid, glyph: "filter", tooltipId: "widgets.builder.setupFilter" }, { diff --git a/web/client/components/widgets/builder/wizard/counter/__tests__/Toolbar-test.jsx b/web/client/components/widgets/builder/wizard/counter/__tests__/Toolbar-test.jsx index 7b0fb013f8..fd7a327f50 100644 --- a/web/client/components/widgets/builder/wizard/counter/__tests__/Toolbar-test.jsx +++ b/web/client/components/widgets/builder/wizard/counter/__tests__/Toolbar-test.jsx @@ -35,9 +35,13 @@ describe('CounterWizard Toolbar component', () => { const buttons = container.querySelectorAll('button'); expect(buttons.length).toBe(2); expect(buttons[0].querySelector('.glyphicon-filter')).toExist(); + // filter should not enabled because valid means also that + // there are some attributes + expect(buttons[0].disabled).toBe(true); expect(buttons[1].querySelector('.glyphicon-arrow-right')).toExist(); expect(buttons[1].disabled).toBe(true); ReactDOM.render(, document.getElementById("container")); + expect(container.querySelectorAll('button')[1].disabled).toBe(false); expect(container.querySelectorAll('button')[1].disabled).toBeFalsy(); }); it('step 1', () => { diff --git a/web/client/components/widgets/builder/wizard/table/TableOptions.jsx b/web/client/components/widgets/builder/wizard/table/TableOptions.jsx index bdb20c87ed..a0a3f60701 100644 --- a/web/client/components/widgets/builder/wizard/table/TableOptions.jsx +++ b/web/client/components/widgets/builder/wizard/table/TableOptions.jsx @@ -11,7 +11,7 @@ const { uniq, castArray, includes } = require('lodash'); const { Row, Col, Form, Button } = require('react-bootstrap'); const Message = require('../../../../I18N/Message'); const StepHeader = require('../../../../misc/wizard/StepHeader'); - +const noAttributes = require('../common/noAttributesEmptyView'); const {withProps, withHandlers, compose} = require('recompose'); const updatePropertyName = (arr, name, hide) => { const names = castArray(name); @@ -20,18 +20,20 @@ const updatePropertyName = (arr, name, hide) => { } return uniq([...arr, ...names]); }; -const AttributeSelector = compose(withProps( - ({ attributes = [], options = {}} = {}) => ({ // TODO manage hide condition - attributes: attributes - .filter(a => !isGeometryType(a)) - .map( a => ({ - ...a, - label: a.name, - attribute: a.name, - hide: options.propertyName && (options.propertyName.indexOf( a.name ) < 0) - }) - ) - })), +const AttributeSelector = compose( + withProps( + ({ attributes = [], options = {}} = {}) => ({ // TODO manage hide condition + attributes: attributes + .filter(a => !isGeometryType(a)) + .map( a => ({ + ...a, + label: a.name, + attribute: a.name, + hide: options.propertyName && (options.propertyName.indexOf( a.name ) < 0) + }) + ) + })), + noAttributes(({ attributes = []}) => attributes.length === 0), withHandlers({ onChange: ({ onChange = () => {}, options = {}}) => (name, hide) => onChange("options.propertyName", updatePropertyName(options && options.propertyName || [], name, hide)) }) diff --git a/web/client/components/widgets/builder/wizard/table/Toolbar.jsx b/web/client/components/widgets/builder/wizard/table/Toolbar.jsx index f2e251b476..42fa06311e 100644 --- a/web/client/components/widgets/builder/wizard/table/Toolbar.jsx +++ b/web/client/components/widgets/builder/wizard/table/Toolbar.jsx @@ -23,7 +23,7 @@ const getBackTooltipId = step => { } }; -const getNextTooltipId = (step, valid) => valid ? "widgets.builder.wizard.configureWidgetOptions" : "widget.builder.wizard.errors.checkAtLeastOneAttribute"; +const getNextTooltipId = (step, valid) => valid ? "widgets.builder.wizard.configureWidgetOptions" : "widgets.builder.errors.checkAtLeastOneAttribute"; const getSaveTooltipId = (step, {id} = {}) => { if (id) { @@ -43,6 +43,13 @@ module.exports = ({ openFilterEditor = () => { }, step = 0, stepButtons = [], ed }, ...stepButtons, { visible: step >= 0, onClick: openFilterEditor, + /* if no valid attribute is present, filter must be disabled + * (Query panel don't work you can not proceed, so it doesn't make sense to + * create a filter if you can not create the widget) + * TODO: improve checking valid attributes presence instead + * of valid flag. + */ + disabled: !isValidStep1(editorData), glyph: "filter", tooltipId: "widgets.builder.setupFilter" }, { diff --git a/web/client/components/widgets/builder/wizard/table/__tests__/TableOptions-test.jsx b/web/client/components/widgets/builder/wizard/table/__tests__/TableOptions-test.jsx index 70c5c97461..55bd56b19d 100644 --- a/web/client/components/widgets/builder/wizard/table/__tests__/TableOptions-test.jsx +++ b/web/client/components/widgets/builder/wizard/table/__tests__/TableOptions-test.jsx @@ -31,6 +31,7 @@ describe('TableOptions component', () => { expect(el).toExist(); const resetButton = document.querySelector('.btn'); expect(resetButton).toNotExist(); + expect(document.querySelector('.empty-state-container')).toExist(); }); it('Test TableOptions tools visibility', () => { diff --git a/web/client/localConfig.json b/web/client/localConfig.json index eef6d6a874..2d9237ae60 100644 --- a/web/client/localConfig.json +++ b/web/client/localConfig.json @@ -267,7 +267,6 @@ "name": "TOC", "cfg": { "activateQueryTool": true, - "activateDownloadTool": true, "activateAddLayerButton": true, "spatialOperations": [ {"id": "INTERSECTS", "name": "queryform.spatialfilter.operations.intersects"}, diff --git a/web/client/plugins/widgetbuilder/TableBuilder.jsx b/web/client/plugins/widgetbuilder/TableBuilder.jsx index e76e50d456..ccb4693203 100644 --- a/web/client/plugins/widgetbuilder/TableBuilder.jsx +++ b/web/client/plugins/widgetbuilder/TableBuilder.jsx @@ -96,6 +96,7 @@ module.exports = chooseLayerEnhancer(({ enabled, onClose = () => { }, editorData availableDependencies={availableDependencies} onClose={onClose} /> {get(editorData, "options.propertyName.length") === 0 ? } /> : null} diff --git a/web/client/translations/data.de-DE b/web/client/translations/data.de-DE index 14179ff09c..b6d31f3825 100644 --- a/web/client/translations/data.de-DE +++ b/web/client/translations/data.de-DE @@ -1158,6 +1158,8 @@ "clearConnection": "Verbindung löschen" }, "errors": { + "noAttributesTitle": "Keine Attribute zum Anzeigen", + "noAttributesDescription": "Für die ausgewählten Ebenen sind keine Attribute sichtbar. Bitte gehen Sie zurück und wählen Sie eine andere Ebene, um dieses Widget zu verwenden", "noWidgetsAvailableTitle": "Das Widget für die ausgewählte Ebene kann nicht erstellt werden", "noWidgetsAvailableDescription": "

Bitte wählen Sie eine andere Ebene oder einen anderen Widgets-Typ

Der Server bietet nicht die erforderlichen Dienste für die Ebene und den ausgewählten Widget-Typ

Mögliche Ursachen sind:

  • Der ausgewählte Layer ist ein Raster-Layer
  • Der WFS-Service ist nicht verfügbar
  • Der WPS-Prozess gs:aggregate ist nicht verfügbar

", "checkAtLeastOneAttribute": "Sie müssen mindestens eine Spalte auswählen" diff --git a/web/client/translations/data.en-US b/web/client/translations/data.en-US index 9ed53d1031..386e6216c4 100644 --- a/web/client/translations/data.en-US +++ b/web/client/translations/data.en-US @@ -1159,6 +1159,8 @@ "clearConnection": "Clear connection" }, "errors": { + "noAttributesTitle": "No attributes to show", + "noAttributesDescription": "The selected layers has no attributes to show. Please go back and select another layer to use this widget", "noWidgetsAvailableTitle": "Can not create the widget for the selected layer", "noWidgetsAvailableDescription": "

Please try to select another layer or widget type

The server doesn't provide the needed services for the layer and the widget type selected

Possible causes are:

  • The selected layer is a raster layer
  • WFS service is not available
  • The WPS process gs:aggregate is not available

", "checkAtLeastOneAttribute": "You must select at least one column" diff --git a/web/client/translations/data.es-ES b/web/client/translations/data.es-ES index 30d3cffb26..f946356f55 100644 --- a/web/client/translations/data.es-ES +++ b/web/client/translations/data.es-ES @@ -1158,6 +1158,8 @@ "clearConnection": "Borrar conexión" }, "errors": { + "noAttributesTitle": "No hay atributos para mostrar", + "noAttributesDescription": "Las capas seleccionadas no tienen atributos que mostrar. Vuelva atrás y seleccione otra capa para usar este widget", "noWidgetsAvailableTitle": "No se puede crear el widget para la capa seleccionada", "noWidgetsAvailableDescription": "

Intente seleccionar otra capa o tipo de widget

El servidor no proporciona los servicios necesarios para la capa y el tipo de widget seleccionado

Las posibles causas son:

  • La capa seleccionada es una capa ráster
  • El servicio WFS no está disponible
  • El proceso WPS gs:aggregate no está disponible

", "checkAtLeastOneAttribute": "Debes seleccionar al menos una columna" diff --git a/web/client/translations/data.fr-FR b/web/client/translations/data.fr-FR index 58d6ece771..6b7ccff6ce 100644 --- a/web/client/translations/data.fr-FR +++ b/web/client/translations/data.fr-FR @@ -1159,6 +1159,8 @@ "clearConnection": "Effacer la connexion" }, "errors": { + "noAttributesTitle": "Aucun attribut à afficher", + "noAttributesDescription": "Les couches sélectionnées n'ont aucun attribut à afficher. Veuillez revenir en arrière et sélectionner une autre couche pour utiliser ce widget", "noWidgetsAvailableTitle": "Impossible de créer le widget pour le calque sélectionné", "noWidgetsAvailableDescription": "

Veuillez essayer de sélectionner un autre type de couche ou de widget

Le serveur ne fournit pas les services requis pour la couche et le type de widget sélectionné

Les causes possibles sont:

  • Le calque sélectionné est une couche raster
  • Le service WFS n'est pas disponible
  • Le processus WPS gs:aggregate n'est pas disponible

", "checkAtLeastOneAttribute": "Vous devez sélectionner au moins une colonne" diff --git a/web/client/translations/data.it-IT b/web/client/translations/data.it-IT index 83259e4828..51272bdfd8 100644 --- a/web/client/translations/data.it-IT +++ b/web/client/translations/data.it-IT @@ -1158,6 +1158,8 @@ "clearConnection": "Disconnetti" }, "errors": { + "noAttributesTitle": "Nessun attributo disponibile", + "noAttributesDescription": "Il layer selezionato non ha attributi da mostrare. Tornare indietro e selezionare un'altro livello per utilizzare questo widget", "noWidgetsAvailableTitle": "Impossibile creare il widget per il livello selezionato", "noWidgetsAvailableDescription": "

Prova a selezionare un altro livello o tipo di widget

Il server non fornisce i servizi necessari per il livello e il tipo di widget selezionato

Le possibili cause sono:

  • Il livello selezionato è un livello raster
  • Il servizio WFS non è disponibile
  • Il processo WPS gs:aggregate non è disponibile

", "checkAtLeastOneAttribute": "seleziona almeno un attributo" @@ -1187,7 +1189,7 @@ }, "line": { "title": "Grafico a Linea", - "description": "Crea un grafico a linea da aggiungere alla mapp", + "description": "Crea un grafico a linea da aggiungere alla mappa", "caption": "linea" }, "gauge": {