Skip to content

Commit

Permalink
Add copy of dashboard form
Browse files Browse the repository at this point in the history
  • Loading branch information
rvsia committed Jul 1, 2019
1 parent 783df9f commit f34a048
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 8 deletions.
18 changes: 12 additions & 6 deletions app/controllers/report_controller.rb
Expand Up @@ -48,6 +48,7 @@ def export_field_changed
'saved_report_delete' => :saved_report_delete,
'db_new' => :db_new,
'db_edit' => :db_edit,
'db_copy' => :db_copy,
'db_delete' => :db_delete,
'db_seq_edit' => :db_seq_edit,
'widget_refresh' => :widget_refresh,
Expand Down Expand Up @@ -573,7 +574,7 @@ def set_form_locals
action_url = "widget_edit"
record_id = @edit[:widget_id] ? @edit[:widget_id] : nil
elsif x_active_tree == :db_tree
if @edit[:new][:dashboard_order]
if @edit[:new] && @edit[:new][:dashboard_order]
action_url = "db_seq_edit"
locals[:multi_record] = true
else
Expand Down Expand Up @@ -636,7 +637,7 @@ def open_parent_nodes
# :replace_trees key can be an array of tree symbols to be replaced
def replace_right_cell(options = {})
@explorer = true

action = options[:action]
replace_trees = options[:replace_trees] || []
get_node_info unless @in_a_form
replace_trees = @replace_trees if @replace_trees # get_node_info might set this
Expand Down Expand Up @@ -675,8 +676,9 @@ def replace_right_cell(options = {})
presenter[:osf_node] = x_node # Open, select, and focus on this node

session[:changed] = (@edit[:new] != @edit[:current]) if @edit && @edit[:current] # to get save/reset buttons to highlight when something is changed

if nodetype == 'root' || (nodetype != 'root' && x_active_tree != :roles_tree)
if %w[copy_dashboard].include?(action)
presenter.update(:main_div, r[:partial => action])
elsif nodetype == 'root' || (nodetype != 'root' && x_active_tree != :roles_tree)
presenter.update(:main_div, r[:partial => partial])
case x_active_tree
when :db_tree
Expand Down Expand Up @@ -839,8 +841,12 @@ def replace_right_cell(options = {})
if @pages
presenter.hide(:form_buttons_div, :rpb_div_1)
elsif @in_a_form
presenter.update(:form_buttons_div, r[:partial => 'layouts/x_edit_buttons', :locals => locals])
presenter.remove_paging.hide(:rpb_div_1).show(:form_buttons_div)
if %w[copy_dashboard].include?(action)
presenter.hide(:form_buttons_div).hide(:rpb_div_1).remove_paging
else
presenter.update(:form_buttons_div, r[:partial => 'layouts/x_edit_buttons', :locals => locals])
presenter.remove_paging.hide(:rpb_div_1).show(:form_buttons_div)
end
elsif @sb[:pages]
presenter.update(:paging_div, r[:partial => 'layouts/saved_report_paging_bar', :locals => @sb[:pages]])
presenter.hide(:form_buttons_div).show(:rpb_div_1).remove_paging
Expand Down
55 changes: 55 additions & 0 deletions app/controllers/report_controller/dashboards.rb
Expand Up @@ -51,6 +51,61 @@ def db_new
db_edit
end

def db_copy
case params[:button]
when "cancel"
db_copy_cancel
when "save"
dashboard = find_record_with_rbac(MiqWidgetSet, params[:dashboard_id])
begin
MiqWidgetSet.copy_dashboard(dashboard, params[:name], params[:description], params[:group_id])
render :json => { :name => dashboard.name }, :status => :ok
rescue => bang
render :json => { :error => { :message => _("Error during 'Validate': %{message}") % {:message => bang.to_s} } }, :status => :bad_request
end
else
checked_id = find_checked_items.first || params[:id]
@record = find_record_with_rbac(MiqWidgetSet, checked_id)
@tabactive = false
@in_a_form = true
@edit = {}
@edit[:db_id] = @record.id
session[:changed] = false
@right_cell_text = _("Copy of \"%{dashboard}\" Dashboard") % {:dashboard => @record.name}
replace_right_cell(:action => "copy_dashboard")
end
end

def db_copy_cancel
add_flash(_("Copy of Dashboard was cancelled by the user"))
get_node_info
@edit = session[:edit] = @sb[:action] = nil # clean out the saved info
@dashboard = nil
replace_right_cell
end

def dashboard_get
if params[:name]
dashboard = MiqWidgetSet.where(:name => params[:name]).to_a
render :json => {:length => dashboard.length}
else
dashboard = MiqWidgetSet.select(:name, :description, :owner_id).find_by(:id => params[:id])
render :json => {
:name => dashboard.name,
:description => dashboard.description,
:owner_id => dashboard.owner_id.to_s
}
end
end

def dashboard_render
get_node_info
@edit = session[:edit] = @sb[:action] = nil # clean out the saved info
@dashboard = nil
add_flash(_("Copy of \"%{original_name}\" Dashboard: \"%{name}\" was succesfully saved into \"%{group}\" Group.") % {:original_name => params[:original_name], :name => params[:name], :group => params[:group]})
replace_right_cell(:replace_trees => [:db])
end

def db_edit
case params[:button]
when "cancel"
Expand Down
Expand Up @@ -11,6 +11,13 @@ class ApplicationHelper::Toolbar::MiqWidgetSetCenter < ApplicationHelper::Toolba
'pficon pficon-edit fa-lg',
t = N_('Edit this Dashboard'),
t),
button(
:db_copy,
'pficon pficon-edit fa-lg',
N_('Select a single Dashboard to copy'),
N_('Copy Selected Dashboard'),
:send_checked => true
),
button(
:db_delete,
'pficon pficon-delete fa-lg',
Expand Down
@@ -0,0 +1,79 @@
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Grid } from 'patternfly-react';
import MiqFormRenderer from '../../forms/data-driven-form';
import createSchema from './copy-dashboard-form.schema';
import { http, API } from '../../http_api';
import handleError from '../../helpers/handle-failure';

const CopyDashboardForm = ({ dashboardId }) => {
const [isLoading, setIsLoading] = useState(true);
const [initialValues, setInitialValues] = useState({});
const [schema, setSchema] = useState({});
const [options, setOptions] = useState([]);

const submitValues = (values) => {
miqSparkleOn();
const data = {
...values,
dashboard_id: dashboardId,
};

return http.post(`/report/db_copy/${dashboardId}?button=save`, data, { skipErrors: [400] })
.then(({ name }) =>
miqAjaxButton(
('/report/dashboard_render'),
{ original_name: name, name: values.name, group: options.find(option => option.value === values.group_id).label },
))
.catch((e) => {
handleError(e);
miqSparkleOff();
});
};

const cancelClicked = () => {
miqSparkleOn();
miqAjaxButton(`/report/db_copy/${dashboardId}?button=cancel`);
};

useEffect(() => {
miqSparkleOn();
Promise.all([API.get('/api/groups?expand=resources'),
http.get(`/report/dashboard_get/${dashboardId}`)])
.then(([{ resources }, { name, description, owner_id }]) => {
const options = resources.map(({ id, description }) => ({ value: id, label: description }));
setOptions(options);
setInitialValues({ name, description, group_id: owner_id });
setSchema(createSchema(options, name, dashboardId));
setIsLoading(false);
miqSparkleOff();
})
.catch((e) => {
handleError(e);
miqSparkleOff();
});
}, []);

if (isLoading) return null;
return (
<Grid fluid>
<MiqFormRenderer
initialValues={initialValues}
schema={schema}
onSubmit={submitValues}
onCancel={cancelClicked}
onReset={() => add_flash(__('All changes have been reset'), 'warn')}
canReset
buttonsLabels={{
submitLabel: __('Save'),
}}
/>
</Grid>
);
};

CopyDashboardForm.propTypes = {
dashboardId: PropTypes.string.isRequired,
};

export default CopyDashboardForm;
@@ -0,0 +1,66 @@
import { componentTypes, validatorTypes } from '@data-driven-forms/react-form-renderer';
import debouncePromise from '../../helpers/promise-debounce';
import { http } from '../../http_api';

export const asyncValidator = (value, dashboardId, name) =>
http.get(`/report/dashboard_get/${dashboardId}?name=${value}`)
.then((json) => {
if (value === name) {
return __('Use different name');
}
if (json.length > 0) {
return __('Name has already been taken');
}
if (value === '' || value === undefined) {
return __("Name can't be blank");
}
return undefined;
});

const asyncValidatorDebounced = debouncePromise(asyncValidator);

export default (miqGroups, name, dashboardId) => {
const fields = [
{
component: componentTypes.SUB_FORM,
title: __('Basic Info'),
fields: [
{
component: componentTypes.TEXT_FIELD,
name: 'name',
validate: [
value => asyncValidatorDebounced(value, dashboardId, name),
],
label: __('Name'),
maxLength: 40,
validateOnMount: true,
},
{
component: componentTypes.TEXT_FIELD,
name: 'description',
validate: [{
type: validatorTypes.REQUIRED,
message: __('Required'),
}],
label: __('Description'),
maxLength: 255,
validateOnMount: true,
},
{
component: componentTypes.SELECT_COMPONENT,
name: 'group_id',
options: miqGroups,
label: __('Select Group'),
placeholder: __('Nothing selected'),
isSearchable: true,
validate: [{
type: validatorTypes.REQUIRED,
message: __('Required'),
}],
validateOnMount: true,
},
],
},
];
return { fields };
};
2 changes: 2 additions & 0 deletions app/javascript/packs/component-definitions-common.js
Expand Up @@ -8,6 +8,7 @@ import Breadcrumbs from '../components/breadcrumbs';
import CatalogForm from '../components/catalog-form/catalog-form';
import CloudNetworkForm from '../components/cloud-network-form/cloud-network-form';
import CloudTenantForm from '../components/cloud-tenant-form/cloud-tenant-form';
import CopyDashboardForm from '../components/copy-dashboard-form/copy-dashboard-form';
import FlavorForm from '../components/flavor-form/flavor-form';
import FormButtonsRedux from '../forms/form-buttons-redux';
import GenericGroupWrapper from '../react/generic_group_wrapper';
Expand Down Expand Up @@ -35,6 +36,7 @@ ManageIQ.component.addReact('Breadcrumbs', Breadcrumbs);
ManageIQ.component.addReact('CatalogForm', CatalogForm);
ManageIQ.component.addReact('CloudNetworkForm', CloudNetworkForm);
ManageIQ.component.addReact('CloudTenantForm', CloudTenantForm);
ManageIQ.component.addReact('CopyDashboardForm', CopyDashboardForm);
ManageIQ.component.addReact('FlavorForm', FlavorForm);
ManageIQ.component.addReact('FormButtonsRedux', FormButtonsRedux);
ManageIQ.component.addReact('GenericGroup', GenericGroup);
Expand Down
3 changes: 3 additions & 0 deletions app/views/report/_copy_dashboard.html.haml
@@ -0,0 +1,3 @@
= render :partial => "layouts/flash_msg"
.col-md-12
= react('CopyDashboardForm', { :dashboardId => @edit[:db_id].to_s })
6 changes: 4 additions & 2 deletions app/views/report/_db_show.html.haml
Expand Up @@ -18,12 +18,14 @@
= _('Locked')
.col-md-8
%p.form-control-static
= h(widget.set_data[:locked])
- if widget.set_data && widget.set_data[:locked]
= h(widget.set_data[:locked])
.form-group
%label.control-label.col-md-2
= _('Reset Dashboard upon login')
.col-md-8
%p.form-control-static
= h(widget.set_data[:reset_upon_login])
- if widget.set_data && widget.set_data[:reset_upon_login]
= h(widget.set_data[:reset_upon_login])
%hr
= render :partial => 'db_widgets', :locals => {:widget => widget}
4 changes: 4 additions & 0 deletions config/routes.rb
Expand Up @@ -2710,6 +2710,8 @@

:report => {
:get => %w(
dashboard_get
db_copy
db_widget_dd_done
download_report
explorer
Expand All @@ -2730,6 +2732,8 @@
accordion_select
change_tab
create
dashboard_render
db_copy
db_edit
db_form_field_changed
db_seq_edit
Expand Down

0 comments on commit f34a048

Please sign in to comment.