Skip to content

Commit

Permalink
Refactor TagsControl; fix TagsEditorModal animation (#3399)
Browse files Browse the repository at this point in the history
* Refactor TagsControl; fix TagsEditorModal animation

* Update tooltip text

Co-Authored-By: kravets-levko <levko.ne@gmail.com>

* Update tooltip text

Co-Authored-By: kravets-levko <levko.ne@gmail.com>

* CR1
  • Loading branch information
kravets-levko authored and arikfr committed Feb 5, 2019
1 parent 2134113 commit 045c171
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 152 deletions.
2 changes: 1 addition & 1 deletion client/app/components/NoTaggedObjectsFound.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { react2angular } from 'react2angular';
import { BigMessage } from '@/components/BigMessage';
import TagsControl from '@/components/tags-control/TagsControl';
import { TagsControl } from '@/components/tags-control/TagsControl';

export function NoTaggedObjectsFound({ objectType, tags }) {
return (
Expand Down
2 changes: 1 addition & 1 deletion client/app/components/dashboards/AddWidgetDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
ParameterMappingListInput,
editableMappingsToParameterMappings,
} from '@/components/ParameterMappingInput';
import { QueryTagsControl } from '@/components/tags-control/QueryTagsControl';
import { QueryTagsControl } from '@/components/tags-control/TagsControl';

import { toastr } from '@/services/ng';
import { Widget } from '@/services/widget';
Expand Down
12 changes: 0 additions & 12 deletions client/app/components/tags-control/DashboardTagsControl.jsx

This file was deleted.

44 changes: 0 additions & 44 deletions client/app/components/tags-control/ModelTagsControl.jsx

This file was deleted.

12 changes: 0 additions & 12 deletions client/app/components/tags-control/QueryTagsControl.jsx

This file was deleted.

131 changes: 75 additions & 56 deletions client/app/components/tags-control/TagsControl.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { map, trim } from 'lodash';
import React, { Fragment } from 'react';
import { map, trim, extend } from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import { react2angular } from 'react2angular';
import Tooltip from 'antd/lib/tooltip';
import TagsEditorModal from './TagsEditorModal';

export default class TagsControl extends React.Component {
export class TagsControl extends React.Component {
static propTypes = {
tags: PropTypes.arrayOf(PropTypes.string),
canEdit: PropTypes.bool,
getAvailableTags: PropTypes.func,
onEdit: PropTypes.func,
className: PropTypes.string,
children: PropTypes.node,
};

static defaultProps = {
Expand All @@ -18,87 +21,103 @@ export default class TagsControl extends React.Component {
getAvailableTags: () => Promise.resolve([]),
onEdit: () => {},
className: '',
children: null,
};

constructor(props) {
super(props);

this.state = {
showModal: false,
};

// get available tags
this.props.getAvailableTags()
.then((tags) => {
this.availableTags = tags;
});
}

onTagsChanged = (newTags) => {
this.props.onEdit(newTags);
this.closeEditModal();
}
state = {
showModal: false,
};

openEditModal = () => {
this.setState({ showModal: true });
}
};

closeEditModal = () => {
this.setState({ showModal: false });
}

// eslint-disable-next-line class-methods-use-this
renderPrependTags() {
return null;
}

renderTags() {
return map(this.props.tags, tag => (
<span className="label label-tag" key={tag} title={tag}>{tag}</span>
));
}
};

// eslint-disable-next-line class-methods-use-this
renderAppendTags() {
return null;
}
onTagsChanged = (newTags) => {
this.props.onEdit(newTags);
this.closeEditModal();
};

renderEditButton() {
if (!this.props.canEdit) {
return null;
}

const tags = map(this.props.tags, trim);

const buttonLabel = tags.length > 0
? <i className="zmdi zmdi-edit" />
: <Fragment><i className="zmdi zmdi-plus" /> Add tag</Fragment>;
: <React.Fragment><i className="zmdi zmdi-plus m-r-5" />Add tag</React.Fragment>;

return (
<Fragment>
<a className="label label-tag" role="none" onClick={this.openEditModal}>
{buttonLabel}
</a>
<React.Fragment>
<a className="label label-tag" role="none" onClick={this.openEditModal}>{buttonLabel}</a>
{this.state.showModal && (
<TagsEditorModal
tags={tags}
availableTags={this.availableTags}
close={this.onTagsChanged}
dismiss={this.closeEditModal}
getAvailableTags={this.props.getAvailableTags}
onConfirm={this.onTagsChanged}
onCancel={this.closeEditModal}
/>
)}
</Fragment>
</React.Fragment>
);
}

render() {
return (
<div className={'tags-control ' + this.props.className}>
{this.renderPrependTags()}
{this.renderTags()}
{this.renderAppendTags()}
{this.renderEditButton()}
{this.props.children}
{map(this.props.tags, tag => (
<span className="label label-tag" key={tag} title={tag}>{tag}</span>
))}
{this.props.canEdit && this.renderEditButton()}
</div>
);
}
}

function modelTagsControl({ archivedTooltip }) {
// See comment for `propTypes`/`defaultProps`
// eslint-disable-next-line react/prop-types
function ModelTagsControl({ isDraft, isArchived, ...props }) {
return (
<TagsControl {...props}>
{!isArchived && isDraft && (
<span className="label label-tag-unpublished">Unpublished</span>
)}
{isArchived && (
<Tooltip placement="right" title={archivedTooltip}>
<span className="label label-tag-archived">Archived</span>
</Tooltip>
)}
</TagsControl>
);
}

// ANGULAR_REMOVE_ME `extend` needed just for `react2angular`, so remove it when `react2angular` no longer needed
ModelTagsControl.propTypes = extend({
isDraft: PropTypes.bool,
isArchived: PropTypes.bool,
}, TagsControl.propTypes);

ModelTagsControl.defaultProps = extend({
isDraft: false,
isArchived: false,
}, TagsControl.defaultProps);

return ModelTagsControl;
}

export const QueryTagsControl = modelTagsControl({
archivedTooltip: 'This query is archived and can\'t be used in dashboards, or appear in search results.',
});

export const DashboardTagsControl = modelTagsControl({
archivedTooltip: 'This dashboard is archived and won\'t be listed in dashboards nor search results.',
});

export default function init(ngModule) {
ngModule.component('queryTagsControl', react2angular(QueryTagsControl));
ngModule.component('dashboardTagsControl', react2angular(DashboardTagsControl));
}

init.init = true;
65 changes: 41 additions & 24 deletions client/app/components/tags-control/TagsEditorModal.jsx
Original file line number Diff line number Diff line change
@@ -1,61 +1,78 @@
import { map, trim, chain } from 'lodash';
import { map, trim, uniq } from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import Select from 'antd/lib/select';
import Modal from 'antd/lib/modal';

const { Option } = Select;

export default class TagsEditorModal extends React.Component {
static propTypes = {
tags: PropTypes.arrayOf(PropTypes.string),
availableTags: PropTypes.arrayOf(PropTypes.string),
close: PropTypes.func,
dismiss: PropTypes.func,
getAvailableTags: PropTypes.func.isRequired,
onConfirm: PropTypes.func,
onCancel: PropTypes.func,
};

static defaultProps = {
tags: [],
availableTags: [],
close: () => {},
dismiss: () => {},
onConfirm: () => {},
onCancel: () => {},
};

constructor(props) {
super(props);

this.state = {
result: chain(this.props.tags).map(trim).uniq().value(),
isVisible: true,
loading: true,
availableTags: [],
result: uniq(map(this.props.tags, trim)),
onAfterClose: () => {},
};
}

this.selectOptions =
chain(this.props.availableTags)
.map(trim)
.uniq()
.map(tag => <Option key={tag}>{tag}</Option>)
.value();
componentDidMount() {
this.props.getAvailableTags().then((availableTags) => {
this.setState({
loading: false,
availableTags: uniq(map(availableTags, trim)),
});
});
}

render() {
const { close, dismiss } = this.props;
const { result } = this.state;
onConfirm(result) {
this.setState({
isVisible: false,
onAfterClose: () => this.props.onConfirm(result),
});
}

onCancel() {
this.setState({
isVisible: false,
onAfterClose: () => this.props.onCancel(),
});
}

render() {
return (
<Modal
visible
visible={this.state.isVisible}
title="Add/Edit Tags"
onOk={() => close(result)}
onCancel={dismiss}
onOk={() => this.onConfirm(this.state.result)}
onCancel={() => this.onCancel()}
afterClose={() => this.state.onAfterClose()}
>
<Select
mode="tags"
className="w-100"
placeholder="Add some tags..."
defaultValue={result}
defaultValue={this.state.result}
onChange={values => this.setState({ result: map(values, trim) })}
autoFocus
disabled={this.state.loading}
loading={this.state.loading}
>
{this.selectOptions}
{map(this.state.availableTags, tag => <Select.Option key={tag}>{tag}</Select.Option>)}
</Select>
</Modal>
);
Expand Down
2 changes: 1 addition & 1 deletion client/app/pages/dashboards/DashboardList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { react2angular } from 'react2angular';

import { PageHeader } from '@/components/PageHeader';
import { Paginator } from '@/components/Paginator';
import { DashboardTagsControl } from '@/components/tags-control/DashboardTagsControl';
import { DashboardTagsControl } from '@/components/tags-control/TagsControl';

import { wrap as liveItemsList, createResourceFetcher, ControllerType } from '@/components/items-list/LiveItemsList';
import LoadingState from '@/components/items-list/components/LoadingState';
Expand Down
2 changes: 1 addition & 1 deletion client/app/pages/queries-list/QueriesList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { react2angular } from 'react2angular';

import { PageHeader } from '@/components/PageHeader';
import { Paginator } from '@/components/Paginator';
import { QueryTagsControl } from '@/components/tags-control/QueryTagsControl';
import { QueryTagsControl } from '@/components/tags-control/TagsControl';
import { SchedulePhrase } from '@/components/queries/SchedulePhrase';

import { wrap as liveItemsList, createResourceFetcher, ControllerType } from '@/components/items-list/LiveItemsList';
Expand Down

0 comments on commit 045c171

Please sign in to comment.