Merge pull request #2311 from kravets-levko/feature/add-widget-dialog-update

Add Widget Dialog UX Update
This commit is contained in:
Arik Fraimovich 2018-02-14 12:52:12 +02:00 committed by GitHub
commit d6cc7489b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 166 additions and 120 deletions

View File

@ -1,65 +1,65 @@
.modal-header {
padding: 23px 26px;
}
.modal-body {
padding: 0 26px 10px;
}
.modal-content {
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.31);
}
.modal-footer {
padding: 20px 22px;
}
.modal-xl {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
.modal-dialog {
position: fixed;
margin: 0;
width: 100%;
height: 100%;
padding: 0;
}
.modal-content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border: 2px solid #3c7dcf;
border-radius: 0;
box-shadow: none;
}
.modal-header {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 50px;
padding: 10px;
border: 0;
}
.modal-body {
position: absolute;
top: 50px;
bottom: 60px;
width: 100%;
overflow: auto;
}
.modal-footer {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 60px;
padding: 10px;
}
}
.modal-header {
padding: 23px 26px;
}
.modal-body {
padding: 0 26px 10px;
}
.modal-content {
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.31);
}
.modal-footer {
padding: 20px 26px;
}
.modal-xl {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
.modal-dialog {
position: fixed;
margin: 0;
width: 100%;
height: 100%;
padding: 0;
}
.modal-content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
border: 2px solid #3c7dcf;
border-radius: 0;
box-shadow: none;
}
.modal-header {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 50px;
padding: 10px;
border: 0;
}
.modal-body {
position: absolute;
top: 50px;
bottom: 60px;
width: 100%;
overflow: auto;
}
.modal-footer {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 60px;
padding: 10px;
}
}

View File

@ -4,46 +4,70 @@
</div>
<div class="modal-body">
<p class="btn-group">
<button type="button" class="btn btn-default" ng-class="{active: $ctrl.isVisualization()}" ng-click="$ctrl.setType('visualization')">Visualization</button>
<button type="button" class="btn btn-default" ng-class="{active: $ctrl.isTextBox()}" ng-click="$ctrl.setType('textbox')">Text Box</button>
<button type="button" class="btn btn-default" ng-class="{active: $ctrl.isVisualization}" ng-click="$ctrl.setType('visualization')">Visualization</button>
<button type="button" class="btn btn-default" ng-class="{active: $ctrl.isTextBox}" ng-click="$ctrl.setType('textbox')">Text Box</button>
</p>
<div ng-show="$ctrl.isTextBox()">
<div class="form-group">
<textarea class="form-control" ng-model="$ctrl.text" rows="3"></textarea>
</div>
<div ng-show="$ctrl.text">
<strong>Preview:</strong>
<p ng-bind-html="$ctrl.text | markdown"></p>
</div>
<div ng-show="$ctrl.isTextBox">
<div class="form-group">
<textarea class="form-control" ng-model="$ctrl.text" ng-model-options="{ debounce: 200 }" rows="3" autofocus></textarea>
</div>
<div ng-show="$ctrl.text">
<strong>Preview:</strong>
<p ng-bind-html="$ctrl.text | markdown"></p>
</div>
</div>
<div ng-show="$ctrl.isVisualization()">
<div class="form-group">
<ui-select ng-model="$ctrl.query.selected" theme="bootstrap" reset-search-input="false" on-select="$ctrl.onQuerySelect($item, $model)">
<ui-select-match placeholder="Search a query by name">{{$select.selected.name}}</ui-select-match>
<ui-select-choices repeat="q in $ctrl.queries"
refresh="$ctrl.searchQueries($select.search)"
refresh-delay="0">
<div ng-bind-html="$ctrl.trustAsHtml(q.name | highlight: $select.search)"></div>
</ui-select-choices>
</ui-select>
<div ng-show="$ctrl.isVisualization">
<div class="form-group">
<input type="text" placeholder="Search a query by name" class="form-control" autofocus
ng-if="!$ctrl.selectedQuery" ng-model="$ctrl.searchTerm" ng-change="$ctrl.searchQueries($ctrl.searchTerm)">
<div ng-if="$ctrl.selectedQuery" class="p-relative">
<input type="text" class="form-control bg-white"
ng-value="$ctrl.selectedQuery.name" readonly="readonly">
<a href="javascript:void(0)" ng-click="$ctrl.selectQuery(null)"
class="d-flex align-items-center justify-content-center"
style="position: absolute; right: 1px; top: 1px; bottom: 1px; width: 30px; background: #fff; border-radius: 3px;"
><i class="text-muted fa fa-times"></i></a>
</div>
</div>
<div ng-if="!$ctrl.selectedQuery" class="scrollbox" style="max-height: 50vh">
<div ng-if="$ctrl.searchTerm == ''">
<div class="list-group" ng-if="$ctrl.recentQueries.length > 0">
<a class="list-group-item" ng-repeat="query in $ctrl.recentQueries"
ng-click="$ctrl.selectQuery(query.id)">{{query.name}}</a>
</div>
</div>
<div ng-show="$ctrl.selected_query">
<div class="form-group">
<label for="">Choose Visualization</label>
<select ng-model="$ctrl.selectedVis" ng-options="vis as vis.name group by vis.type for vis in $ctrl.selected_query.visualizations" class="form-control"></select>
</div>
<div ng-if="$ctrl.searchTerm != ''">
<div ng-if="$ctrl.searchedQueries.length == 0" class="text-muted">
No results matching search term.
</div>
<div class="list-group" ng-if="$ctrl.searchedQueries.length > 0">
<a class="list-group-item"
ng-repeat="query in $ctrl.searchedQueries" ng-click="$ctrl.selectQuery(query.id)"
ng-bind-html="$ctrl.trustAsHtml(query.name | highlight: $ctrl.searchTerm)"
></a>
</div>
</div>
</div>
<div ng-show="$ctrl.selectedQuery">
<div class="form-group">
<label>Choose Visualization</label>
<select ng-model="$ctrl.selectedVis" class="form-control"
ng-options="vis as vis.name group by vis.type for vis in $ctrl.selectedQuery.visualizations"></select>
</div>
</div>
</div>
<div class="form-group" ng-if="$ctrl.isTextBox()">
<label><input type="checkbox" ng-model="$ctrl.isHidden">&nbsp;Hidden</label>
<div class="form-group" ng-if="$ctrl.isTextBox">
<label><input type="checkbox" ng-model="$ctrl.isHidden">&nbsp;Hidden</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-disabled="$ctrl.saveInProgress" ng-click="$ctrl.dismiss()">Close</button>
<button type="button" class="btn btn-primary" ng-disabled="$ctrl.saveInProgress || !($ctrl.selectedVis || $ctrl.isTextBox())" ng-click="$ctrl.saveWidget()">Add to Dashboard</button>
<button type="button" class="btn btn-primary" ng-disabled="$ctrl.saveInProgress || !($ctrl.selectedVis || $ctrl.isTextBox)" ng-click="$ctrl.saveWidget()">Add to Dashboard</button>
</div>

View File

@ -1,3 +1,4 @@
import { debounce } from 'underscore';
import template from './add-widget-dialog.html';
const AddWidgetDialog = {
@ -12,61 +13,82 @@ const AddWidgetDialog = {
this.dashboard = this.resolve.dashboard;
this.saveInProgress = false;
this.selectedVis = null;
this.query = {};
this.selected_query = undefined;
// Textbox
this.text = '';
this.existing_text = '';
this.new_text = '';
this.isHidden = false;
this.type = 'visualization';
// Visualization
this.selectedQuery = null;
this.searchTerm = '';
this.recentQueries = [];
// Don't show draft (unpublished) queries
Query.recent().$promise.then((items) => {
this.recentQueries = items.filter(item => !item.is_draft);
});
this.searchedQueries = [];
this.selectedVis = null;
this.trustAsHtml = html => $sce.trustAsHtml(html);
this.isVisualization = () => this.type === 'visualization';
this.isTextBox = () => this.type === 'textbox';
this.setType = (type) => {
this.type = type;
this.isVisualization = this.type === 'visualization';
this.isTextBox = this.type === 'textbox';
};
this.setType('visualization');
this.onQuerySelect = () => {
if (!this.query.selected) {
return;
}
this.selectQuery = (queryId) => {
// Clear previously selected query (if any)
this.selectedQuery = null;
this.selectedVis = null;
Query.get({ id: this.query.selected.id }, (query) => {
if (query) {
this.selected_query = query;
if (query.visualizations.length) {
this.selectedVis = query.visualizations[0];
if (queryId) {
Query.get({ id: queryId }, (query) => {
if (query) {
this.selectedQuery = query;
if (query.visualizations.length) {
this.selectedVis = query.visualizations[0];
}
}
}
});
});
}
};
this.searchQueries = (term) => {
// `ng-model-options` does not work with `ng-change`, so do debounce here
this.searchQueries = debounce((term) => {
if (!term || term.length === 0) {
this.queries = [];
this.searchedQueries = [];
return;
}
Query.search({ q: term }, (results) => {
this.queries = results;
// If user will type too quick - it's possible that there will be
// several requests running simultaneously. So we need to check
// which results are matching current search term and ignore
// outdated results.
if (this.searchTerm === term) {
this.searchedQueries = results;
}
});
};
}, 200);
this.saveWidget = () => {
this.saveInProgress = true;
const selectedVis = this.isVisualization ? this.selectedVis : null;
const widget = new Widget({
visualization_id: this.selectedVis && this.selectedVis.id,
visualization_id: selectedVis && selectedVis.id,
dashboard_id: this.dashboard.id,
options: {
isHidden: this.isTextBox() && this.isHidden,
isHidden: this.isTextBox && this.isHidden,
position: {},
},
visualization: this.selectedVis,
text: this.text,
visualization: selectedVis,
text: this.isTextBox ? this.text : '',
});
const position = this.dashboard.calculateNewWidgetPosition(widget);