Removing additional js files
This commit is contained in:
@@ -1,55 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
/* eslint-disable react/jsx-key */
|
||||
import React, { Component } from 'react';
|
||||
import './color-picker.scss';
|
||||
import CheckIcon from '@material-ui/icons/CheckOutlined';
|
||||
|
||||
export default class ColorPicker extends Component {
|
||||
static colors = [
|
||||
'#D50000',
|
||||
'#E67C73',
|
||||
'#F4511E',
|
||||
'#F6BF26',
|
||||
'#33B679',
|
||||
'#0B8043',
|
||||
'#039BE5',
|
||||
'#3F51B5',
|
||||
'#7986CB',
|
||||
'#8E24AA',
|
||||
'#801515',
|
||||
'#616161',
|
||||
];
|
||||
|
||||
/*
|
||||
props = {
|
||||
value : default color
|
||||
onChange : called when a color is selected
|
||||
}
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
this.colors = ColorPicker.colors;
|
||||
}
|
||||
render() {
|
||||
var showed_selected = this.colors.indexOf(this.props.value) >= 0;
|
||||
var colors = this.colors;
|
||||
if (!showed_selected) {
|
||||
colors = this.colors.concat([this.props.value]);
|
||||
}
|
||||
return (
|
||||
<div className="colorPicker" ref={this.props.refDom}>
|
||||
{colors.map(color => {
|
||||
return (
|
||||
<div
|
||||
className="color"
|
||||
style={{ backgroundColor: color }}
|
||||
onClick={() => this.props.onChange(color)}
|
||||
>
|
||||
{this.props.value == color && <CheckIcon className="m-icon-small" />}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
.colorPicker {
|
||||
.color {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: var(--border-radius-large);
|
||||
display: inline-block;
|
||||
margin: 10px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
.m-icon-small {
|
||||
color: #fff;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
-139
@@ -1,139 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
/* eslint-disable react/no-direct-mutation-state */
|
||||
import React, { Component } from 'react';
|
||||
import CloseIcon from '@material-ui/icons/CloseOutlined';
|
||||
import AddIcon from '@material-ui/icons/AddOutlined';
|
||||
import GearIcon from '@material-ui/icons/BuildOutlined';
|
||||
import Input from 'components/inputs/input.jsx';
|
||||
import './connectors-list-manager.scss';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import WorkspacesApps from '@deprecated/workspaces/workspaces_apps.jsx';
|
||||
import { getCompanyApplication as getApplication } from '@features/applications/state/company-applications';
|
||||
|
||||
export default class ConnectorsListManager extends Component {
|
||||
constructor(props) {
|
||||
super();
|
||||
this.props = props;
|
||||
this.state = {
|
||||
connectors_ids: props.current.map(item => item.id || ''),
|
||||
filtered: [],
|
||||
input: '',
|
||||
};
|
||||
}
|
||||
filter(text) {
|
||||
this.state.input = text;
|
||||
var list = this.props.list;
|
||||
var res = list
|
||||
.filter(el => {
|
||||
return el.identity.name.toLocaleLowerCase().indexOf(text.toLocaleLowerCase()) >= 0;
|
||||
})
|
||||
.map(el => el);
|
||||
this.setState({ filtered: res });
|
||||
}
|
||||
componentDidMount() {
|
||||
this.filter('');
|
||||
}
|
||||
|
||||
renderLine(item, added) {
|
||||
var id = item.id || item;
|
||||
|
||||
item = getApplication(id);
|
||||
|
||||
var text = '';
|
||||
var button = '';
|
||||
|
||||
text = (
|
||||
<div className="text" style={{ display: 'flex', alignItems: 'center' }}>
|
||||
{WorkspacesApps.getAppIconComponent(item)}
|
||||
{item.identity.name}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (added) {
|
||||
button = (
|
||||
<div className="more">
|
||||
<GearIcon
|
||||
className="m-icon-small config"
|
||||
onClick={() => {
|
||||
this.props.onConfig(item);
|
||||
}}
|
||||
/>
|
||||
<CloseIcon
|
||||
className="m-icon-small remove"
|
||||
onClick={() => {
|
||||
this.state.connectors_ids = this.state.connectors_ids.filter(id =>
|
||||
typeof item == 'string' ? item != id : item.id != id,
|
||||
);
|
||||
this.setState({});
|
||||
this.props.onChange(this.state.connectors_ids);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
button = (
|
||||
<div className="more">
|
||||
<AddIcon
|
||||
className="m-icon-small add"
|
||||
onClick={() => {
|
||||
this.state.connectors_ids.push(item.id || this.state.input.toLocaleLowerCase());
|
||||
this.setState({ input: '' });
|
||||
this.props.onChange(this.state.connectors_ids);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="menu no-background">
|
||||
{text}
|
||||
{button}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="connectorsListManager">
|
||||
<div className="menu-title no-separator">
|
||||
<div className="text">
|
||||
{Languages.t('scenes.apps.tasks.connectors_menu', [], 'Connecteurs')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.connectors_ids.length == 0 && (
|
||||
<div className="menu-text">
|
||||
{Languages.t('scenes.apps.tasks.no_connector', [], 'Aucun connecteurs.')}
|
||||
</div>
|
||||
)}
|
||||
{this.state.connectors_ids.map(id => {
|
||||
return this.renderLine(id, true);
|
||||
})}
|
||||
<div className="menu-title no-separator">
|
||||
<div className="text">
|
||||
{Languages.t('components.connectorslistmanager.add_connectors')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="menu-buttons" style={{ paddingTop: 2, paddingBottom: 2 }}>
|
||||
<div className="text">
|
||||
<Input
|
||||
type="text"
|
||||
className="small full_width bottom-margin"
|
||||
placeholder={Languages.t('components.listmanager.filter', [], 'Filtrer')}
|
||||
style={{ margin: 0 }}
|
||||
onChange={evt => this.filter(evt.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{this.state.filtered.slice(0, 5).map(item => {
|
||||
if (this.state.connectors_ids.indexOf(item.id) >= 0) {
|
||||
return '';
|
||||
}
|
||||
return this.renderLine(item, false);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
.connectorsListManager {
|
||||
margin: 0px -16px;
|
||||
margin-top: -8px;
|
||||
|
||||
.menu-app-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
display: inline-block;
|
||||
background-position: center;
|
||||
background-size: contain;
|
||||
border-radius: var(--border-radius-base);
|
||||
vertical-align: middle;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.emoji-container {
|
||||
margin-right: 5px;
|
||||
top: 1px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.menu-buttons {
|
||||
padding: 0px 8px;
|
||||
margin: 0px 8px;
|
||||
}
|
||||
|
||||
.more {
|
||||
width: auto !important;
|
||||
margin-right: -5px;
|
||||
|
||||
.m-icon-small {
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.m-icon-small {
|
||||
&.remove:hover {
|
||||
color: var(--red);
|
||||
}
|
||||
&.config:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
&.add {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import InfiniteMessages from './infinite-messages.js';
|
||||
|
||||
export default class InfiniteMessagesTester extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
///////// Simulate messages
|
||||
this.messages = [];
|
||||
this.i = 0;
|
||||
for (this.i; this.i < 10000; this.i++) {
|
||||
this.messages.push({
|
||||
content: 'message ' + this.i,
|
||||
height: 40 + Math.random() * 100,
|
||||
id: this.i,
|
||||
});
|
||||
}
|
||||
setInterval(() => {
|
||||
this.messages.push({
|
||||
content: 'message ' + this.i,
|
||||
height: 40 + Math.random() * 100,
|
||||
id: this.i,
|
||||
});
|
||||
this.i++;
|
||||
this.setState({});
|
||||
}, 1000);
|
||||
///////////
|
||||
|
||||
this.infinieMessages = null;
|
||||
}
|
||||
getMessages(offset, limit, callback) {
|
||||
if (!offset) {
|
||||
setTimeout(() => {
|
||||
callback(this.messages.slice(this.messages.length - limit, this.messages.length));
|
||||
}, 10);
|
||||
} else {
|
||||
var offsetPos = 0;
|
||||
this.messages.every(m => {
|
||||
if (m.id >= offset) {
|
||||
return false;
|
||||
}
|
||||
offsetPos++;
|
||||
return true;
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
if (limit > 0) {
|
||||
callback(this.messages.slice(offsetPos - limit, offsetPos));
|
||||
} else {
|
||||
callback(this.messages.slice(offsetPos + 1, offsetPos - limit));
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="infinite_messages_tester">
|
||||
<InfiniteMessages
|
||||
ref={node => (this.infinieMessages = node)}
|
||||
getMessages={(offset, limit, callback) => this.getMessages(offset, limit, callback)}
|
||||
messages={this.messages}
|
||||
offsetKey={'id'}
|
||||
top={''}
|
||||
renderMessage={(message, oldmessage, measure) => (
|
||||
<div className="message" style={{ height: message.height }}>
|
||||
{message.content}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,472 +0,0 @@
|
||||
/* eslint-disable react/no-direct-mutation-state */
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import Button from 'components/buttons/button.jsx';
|
||||
import './infinite-messages.scss';
|
||||
|
||||
export default class InfiniteMessages extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
window.test = this;
|
||||
|
||||
this.init(props);
|
||||
|
||||
this.onScroll = this.onScroll.bind(this);
|
||||
this.onUpdate = this.onUpdate.bind(this);
|
||||
}
|
||||
|
||||
init(props) {
|
||||
props = props || this.props;
|
||||
|
||||
this.on_load_min = {};
|
||||
if (props.messages.length > 60) {
|
||||
this.on_load_min = props.messages.slice(props.messages.length - 60, props.messages.length)[0];
|
||||
} else {
|
||||
this.on_load_min = props.messages[0] || {};
|
||||
}
|
||||
|
||||
this.state = {
|
||||
messages: props.messages.filter(m => this.compare(m, this.on_load_min) >= 0),
|
||||
};
|
||||
this.shouldAutoScroll = true;
|
||||
this.messages_min = this.state.messages[0] || {};
|
||||
this.messages_med = this.state.messages[this.state.messages.length - 1] || {};
|
||||
this.messages_max = this.state.messages[this.state.messages.length - 1] || {};
|
||||
this.bloc_top_height = 0;
|
||||
|
||||
this.did_update_messages_data = {};
|
||||
|
||||
this.dom_messages = {};
|
||||
|
||||
this.max_known = this.messages_max;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.did_update_messages = true;
|
||||
this.did_update_messages_data = {
|
||||
direction: 'bottom_auto_add',
|
||||
bloc_top_height: this.dom_visualized_messages_top.clientHeight,
|
||||
bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight,
|
||||
scroll_top: this.dom_infinite_messages.scrollTop,
|
||||
scroll_height: this.dom_infinite_messages.scrollHeight,
|
||||
};
|
||||
|
||||
// this.dom_infinite_messages.addEventListener("scroll", this.onScroll);
|
||||
window.addEventListener('resize', this.onUpdate);
|
||||
|
||||
this.onUpdate();
|
||||
}
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.onUpdate);
|
||||
// this.dom_infinite_messages.removeEventListener("scroll", this.onScroll);
|
||||
}
|
||||
UNSAFE_componentWillUpdate(nextProps, nextState) {
|
||||
this.scroll_distance_from_bottom =
|
||||
this.dom_infinite_messages.scrollHeight -
|
||||
this.dom_infinite_messages.clientHeight -
|
||||
this.dom_infinite_messages.scrollTop;
|
||||
|
||||
if (nextProps.messages.length) {
|
||||
if (nextProps.messages[nextProps.messages.length - 1].id) {
|
||||
if (this.messages_med.id == this.max_known.id) {
|
||||
this.messages_med = nextProps.messages[nextProps.messages.length - 1];
|
||||
this.messages_max = nextProps.messages[nextProps.messages.length - 1];
|
||||
}
|
||||
this.max_known = nextProps.messages[nextProps.messages.length - 1];
|
||||
}
|
||||
}
|
||||
if (this.max_known.id == this.messages_med.id) {
|
||||
nextState.messages = nextProps.messages.filter(m => {
|
||||
return !m.id || this.compare(m, this.on_load_min) >= 0;
|
||||
});
|
||||
this.did_update_messages = true;
|
||||
this.did_update_messages_data = {
|
||||
direction: 'bottom_auto_add',
|
||||
bloc_top_height: this.dom_visualized_messages_top.clientHeight,
|
||||
bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight,
|
||||
scroll_top: this.dom_infinite_messages.scrollTop,
|
||||
scroll_height: this.dom_infinite_messages.scrollHeight,
|
||||
};
|
||||
}
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.onUpdate();
|
||||
}
|
||||
|
||||
onUpdate() {
|
||||
this.did_auto_scroll = new Date();
|
||||
|
||||
this.scrollToBottom();
|
||||
var dom_fake_separator_top_visible = Math.max(
|
||||
0,
|
||||
this.dom_infinite_messages.clientHeight - this.dom_visualized_messages_top.clientHeight,
|
||||
);
|
||||
if (dom_fake_separator_top_visible == 0) {
|
||||
this.dom_fake_separator_top.style.display = 'none';
|
||||
} else {
|
||||
this.dom_fake_separator_top.style.display = 'block';
|
||||
}
|
||||
|
||||
if (this.did_update_messages) {
|
||||
this.did_update_messages = false;
|
||||
this.bloc_top_height = this.dom_visualized_messages_top.clientHeight;
|
||||
this.bloc_bottom_height = this.dom_visualized_messages_bottom.clientHeight;
|
||||
|
||||
if (this.did_update_messages_data.direction == 'bottom') {
|
||||
this.scrollToPosition(
|
||||
this.dom_anything_on_top.clientHeight +
|
||||
(this.did_update_messages_data.bloc_bottom_height -
|
||||
(this.did_update_messages_data.scroll_height -
|
||||
this.did_update_messages_data.scroll_top)),
|
||||
);
|
||||
} else if (this.did_update_messages_data.direction == 'bottom_auto_add') {
|
||||
//Nothing
|
||||
} else {
|
||||
this.scrollToPosition(this.bloc_top_height + this.did_update_messages_data.scroll_top);
|
||||
}
|
||||
|
||||
this.getVisibleMessages();
|
||||
}
|
||||
}
|
||||
|
||||
onScroll(evt) {
|
||||
if (new Date() - this.did_auto_scroll < 100) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.dom_infinite_messages.scrollHeight != this.last_scrollHeight &&
|
||||
this.shouldAutoScroll
|
||||
) {
|
||||
this.last_scrollHeight = this.dom_infinite_messages.scrollHeight;
|
||||
this.scrollToBottom();
|
||||
} else {
|
||||
var shouldAutoScroll = this.shouldAutoScroll;
|
||||
this.shouldAutoScroll = false;
|
||||
if (this.props.onAutoScrollChange && shouldAutoScroll) this.props.onAutoScrollChange(false);
|
||||
}
|
||||
|
||||
if (this.dom_infinite_messages.scrollTop <= this.dom_infinite_messages.scrollHeight / 8) {
|
||||
this.onScrollTop();
|
||||
}
|
||||
var dist_from_bottom =
|
||||
this.dom_infinite_messages.scrollHeight -
|
||||
this.dom_infinite_messages.scrollTop -
|
||||
this.dom_infinite_messages.clientHeight;
|
||||
if (dist_from_bottom <= Math.max(10, this.dom_infinite_messages.scrollHeight / 8)) {
|
||||
if (
|
||||
dist_from_bottom <= 10 &&
|
||||
(this.shouldAutoScroll ||
|
||||
this.max_known.id == this.state.messages[this.state.messages.length - 1].id)
|
||||
) {
|
||||
// eslint-disable-next-line no-redeclare
|
||||
var shouldAutoScroll = this.shouldAutoScroll;
|
||||
this.shouldAutoScroll = true;
|
||||
if (this.props.onAutoScrollChange && !shouldAutoScroll) this.props.onAutoScrollChange(true);
|
||||
} else if (dist_from_bottom <= 10 || this.max_known.id != this.messages_med.id) {
|
||||
this.onScrollBottom();
|
||||
}
|
||||
}
|
||||
|
||||
this.getVisibleMessages();
|
||||
}
|
||||
|
||||
getVisibleMessages() {
|
||||
if (
|
||||
this.last_get &&
|
||||
Math.abs(this.last_get.scroll_top - this.dom_infinite_messages.scrollTop) < 40
|
||||
) {
|
||||
return [this.last_get.first];
|
||||
}
|
||||
|
||||
var first = null;
|
||||
|
||||
var frame = window.getBoundingClientRect(this.dom_infinite_messages);
|
||||
frame.x = frame.x || frame.left;
|
||||
frame.y = frame.y || frame.top;
|
||||
frame.scrollTop = this.dom_infinite_messages.scrollTop;
|
||||
|
||||
Object.keys(this.dom_messages).every(i => {
|
||||
var item = this.dom_messages[i];
|
||||
if (item.node && item.scrollTop === undefined) {
|
||||
item.scrollTop = window.getBoundingClientRect(item.node).top + frame.scrollTop - frame.y;
|
||||
}
|
||||
if (item.node) {
|
||||
if (!first && item.scrollTop > frame.scrollTop) {
|
||||
first = item.message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
var first_date = new Date((first || {}).creation_date * 1000).setHours(0, 0, 0, 0);
|
||||
|
||||
if (first_date != (this.last_get || {}).first_date) {
|
||||
if (this.props.onFirstDateChange) this.props.onFirstDateChange(first_date);
|
||||
}
|
||||
|
||||
this.last_get = {
|
||||
scroll_top: frame.scrollTop,
|
||||
first: first,
|
||||
first_date: first_date,
|
||||
};
|
||||
|
||||
return [this.last_get.first];
|
||||
}
|
||||
|
||||
scrollToBottom(force) {
|
||||
if (this.shouldAutoScroll || force) {
|
||||
//Make sure we display the last bloc !
|
||||
if (
|
||||
this.messages_med.id != this.messages_min.id &&
|
||||
this.messages_med.id != this.messages_max.id
|
||||
) {
|
||||
this.init();
|
||||
this.did_update_messages = true;
|
||||
this.did_update_messages_data = {
|
||||
direction: 'bottom_auto_add',
|
||||
bloc_top_height: this.dom_visualized_messages_top.clientHeight,
|
||||
bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight,
|
||||
scroll_top: this.dom_infinite_messages.scrollTop,
|
||||
scroll_height: this.dom_infinite_messages.scrollHeight,
|
||||
};
|
||||
|
||||
this.onUpdate();
|
||||
}
|
||||
|
||||
var old_position = this.dom_infinite_messages.scrollTop;
|
||||
this.dom_infinite_messages.scrollTop = this.dom_infinite_messages.scrollHeight;
|
||||
if (old_position != this.dom_infinite_messages.scrollTop) {
|
||||
this.did_auto_scroll = new Date();
|
||||
}
|
||||
|
||||
var shouldAutoScroll = this.shouldAutoScroll;
|
||||
this.shouldAutoScroll = true;
|
||||
if (this.props.onAutoScrollChange && !shouldAutoScroll) this.props.onAutoScrollChange(true);
|
||||
}
|
||||
}
|
||||
scrollToPosition(scrollTop) {
|
||||
var old_position = this.dom_infinite_messages.scrollTop;
|
||||
this.dom_infinite_messages.scrollTop = scrollTop;
|
||||
this.did_auto_scroll = new Date();
|
||||
}
|
||||
|
||||
onScrollTop() {
|
||||
if (this.is_getting_top_messages) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.no_more_before && this.messages_min.id == this.no_more_before.id) {
|
||||
return;
|
||||
}
|
||||
this.number_of_messages_to_load = 2 * (this.dom_infinite_messages.clientHeight / 20);
|
||||
this.is_getting_top_messages = true;
|
||||
|
||||
this.props.getMessages(this.messages_min.id, parseInt(this.number_of_messages_to_load), res => {
|
||||
if (res.length == 0) {
|
||||
this.is_getting_top_messages = false;
|
||||
this.no_more_before = this.messages_min;
|
||||
return;
|
||||
}
|
||||
|
||||
var top_list = this.state.messages.filter(
|
||||
m => this.compare(m, this.messages_min) >= 0 && this.compare(m, this.messages_med) <= 0,
|
||||
);
|
||||
top_list = res.concat(top_list);
|
||||
|
||||
this.messages_med = res[res.length - 1];
|
||||
this.messages_min = res[0];
|
||||
this.messages_max = top_list[top_list.length - 1];
|
||||
|
||||
this.did_update_messages = true;
|
||||
this.did_update_messages_data = {
|
||||
direction: 'top',
|
||||
bloc_top_height: this.dom_visualized_messages_top.clientHeight,
|
||||
bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight,
|
||||
scroll_top: this.dom_infinite_messages.scrollTop,
|
||||
scroll_height: this.dom_infinite_messages.scrollHeight,
|
||||
};
|
||||
|
||||
this.dom_messages = {};
|
||||
|
||||
this.setState({ messages: top_list });
|
||||
|
||||
this.is_getting_top_messages = false;
|
||||
});
|
||||
}
|
||||
|
||||
onScrollBottom() {
|
||||
if (this.is_getting_bottom_messages) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.number_of_messages_to_load = 2 * (this.dom_infinite_messages.clientHeight / 20);
|
||||
this.is_getting_bottom_messages = true;
|
||||
|
||||
this.props.getMessages(
|
||||
this.messages_max.id,
|
||||
-parseInt(this.number_of_messages_to_load),
|
||||
res => {
|
||||
if (res.length == 0) {
|
||||
this.is_getting_bottom_messages = false;
|
||||
var shouldAutoScroll = this.shouldAutoScroll;
|
||||
this.shouldAutoScroll = true;
|
||||
if (this.props.onAutoScrollChange && !shouldAutoScroll)
|
||||
this.props.onAutoScrollChange(true);
|
||||
|
||||
this.max_known = this.state.messages[this.state.messages.length - 1];
|
||||
this.messages_min = this.state.messages[0];
|
||||
this.messages_max = this.state.messages[this.state.messages.length - 1];
|
||||
this.messages_med = this.messages_max;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.compare(res[res.length - 1], this.on_load_min) >= 0) {
|
||||
var top_list = this.state.messages.filter(m => this.compare(m, res[res.length - 1]) >= 0);
|
||||
top_list = top_list.concat(res);
|
||||
|
||||
this.state.messages = this.props.messages.filter(
|
||||
m => this.compare(m, this.on_load_min) > 0,
|
||||
);
|
||||
|
||||
this.max_known = this.state.messages[this.state.messages.length - 1];
|
||||
this.messages_min = this.state.messages[0];
|
||||
this.messages_max = this.state.messages[this.state.messages.length - 1];
|
||||
this.messages_med = this.messages_max;
|
||||
|
||||
this.did_update_messages = true;
|
||||
this.did_update_messages_data = {
|
||||
direction: 'bottom_auto_add',
|
||||
bloc_top_height: this.dom_visualized_messages_top.clientHeight,
|
||||
bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight,
|
||||
scroll_top: this.dom_infinite_messages.scrollTop,
|
||||
scroll_height: this.dom_infinite_messages.scrollHeight,
|
||||
};
|
||||
|
||||
this.dom_messages = {};
|
||||
|
||||
this.setState({ messages: this.state.messages });
|
||||
} else {
|
||||
// eslint-disable-next-line no-redeclare
|
||||
var top_list = this.state.messages.filter(
|
||||
m => this.compare(m, this.messages_med) > 0 && this.compare(m, this.messages_max) <= 0,
|
||||
);
|
||||
top_list = top_list.concat(res);
|
||||
|
||||
this.messages_min = top_list[0];
|
||||
this.messages_med = this.messages_max;
|
||||
this.messages_max = top_list[top_list.length - 1];
|
||||
|
||||
this.did_update_messages = true;
|
||||
this.did_update_messages_data = {
|
||||
direction: 'bottom',
|
||||
bloc_top_height: this.dom_visualized_messages_top.clientHeight,
|
||||
bloc_bottom_height: this.dom_visualized_messages_bottom.clientHeight,
|
||||
scroll_top: this.dom_infinite_messages.scrollTop,
|
||||
scroll_height: this.dom_infinite_messages.scrollHeight,
|
||||
};
|
||||
|
||||
this.dom_messages = {};
|
||||
|
||||
this.setState({ messages: top_list });
|
||||
}
|
||||
|
||||
this.is_getting_bottom_messages = false;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
measure(message) {
|
||||
if (this.dom_infinite_messages) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
//Returns a-b as int
|
||||
compare(a, b) {
|
||||
if (this.props.compare) {
|
||||
return this.props.compare(a, b);
|
||||
}
|
||||
return a.id - b.id;
|
||||
}
|
||||
|
||||
render() {
|
||||
var previous_message = null;
|
||||
|
||||
return (
|
||||
<div className="infinite_messages" ref={node => (this.dom_infinite_messages = node)}>
|
||||
<div ref={node => (this.dom_anything_on_top = node)}>
|
||||
{this.props.top || ''}
|
||||
{!this.no_more_before && (
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Button
|
||||
className="small primary"
|
||||
onClick={() => {
|
||||
this.onScrollTop();
|
||||
}}
|
||||
>
|
||||
Load more messages
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="fake_separator_top" ref={node => (this.dom_fake_separator_top = node)} />
|
||||
<div
|
||||
className="visualized_messages top"
|
||||
ref={node => (this.dom_visualized_messages_top = node)}
|
||||
>
|
||||
{this.state.messages.map((message, _i) => {
|
||||
if (this.compare(message, this.messages_med) <= 0) {
|
||||
var tmp = previous_message;
|
||||
previous_message = message;
|
||||
var i = _i;
|
||||
return (
|
||||
<div
|
||||
key={message.id}
|
||||
ref={node =>
|
||||
(this.dom_messages[i] = {
|
||||
node: node,
|
||||
message: message,
|
||||
scrollTop: (this.dom_messages[i] || {}).scrollTop,
|
||||
})
|
||||
}
|
||||
>
|
||||
{this.props.renderMessage(message, tmp, () => this.measure(message))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
<div
|
||||
className="visualized_messages"
|
||||
ref={node => (this.dom_visualized_messages_bottom = node)}
|
||||
>
|
||||
{this.state.messages.map((message, _i) => {
|
||||
if (this.compare(message, this.messages_med) > 0) {
|
||||
var tmp = previous_message;
|
||||
previous_message = message;
|
||||
var i = _i;
|
||||
return (
|
||||
<div
|
||||
key={message.id}
|
||||
ref={node =>
|
||||
(this.dom_messages[i] = {
|
||||
node: node,
|
||||
message: message,
|
||||
scrollTop: (this.dom_messages[i] || {}).scrollTop,
|
||||
})
|
||||
}
|
||||
>
|
||||
{this.props.renderMessage(message, tmp, () => this.measure(message))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
.infinite_messages {
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.message {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.fake_separator_top {
|
||||
background: transparent;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.infinite_messages_tester {
|
||||
height: 90vh;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
.message {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #f00;
|
||||
border-bottom: 5px solid #0f0;
|
||||
}
|
||||
.visualized_messages.top {
|
||||
.message {
|
||||
background: #fee;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import './inline-tag-picker.scss';
|
||||
|
||||
export default class InlineTagPicker extends Component {
|
||||
render() {
|
||||
return this.props.available.map(item => {
|
||||
return (
|
||||
<div
|
||||
key={item}
|
||||
className={
|
||||
'inline-tag small-top-margin ' + (this.props.value.includes(item) ? 'selected' : '')
|
||||
}
|
||||
onClick={() => {
|
||||
let array = (this.props.value || []).map(a => a);
|
||||
if (this.props.value.includes(item)) {
|
||||
array = this.props.value.filter(val => item !== val);
|
||||
} else {
|
||||
array.push(item);
|
||||
}
|
||||
this.props.onChange(array);
|
||||
}}
|
||||
>
|
||||
{item}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
.inline-tag {
|
||||
cursor: pointer;
|
||||
background: var(--grey-light);
|
||||
border-radius: var(--border-radius-base);
|
||||
height: 20px;
|
||||
color: var(--grey-dark);
|
||||
font-size: 12px;
|
||||
padding: 0 5px;
|
||||
line-height: 18px;
|
||||
box-sizing: border-box;
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
margin-right: 6px;
|
||||
font-weight: normal;
|
||||
&.selected {
|
||||
background: var(--green);
|
||||
color: var(--white);
|
||||
}
|
||||
&:hover {
|
||||
transition: 0.3s;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import Tooltip from 'components/tooltip/tooltip.jsx';
|
||||
import InputWithButton from 'components/inputs/input-with-button.jsx';
|
||||
|
||||
export default class InputWithClipBoard extends Component {
|
||||
/*
|
||||
props = {
|
||||
value : "",
|
||||
disabled : true|false
|
||||
}
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.props = props;
|
||||
|
||||
this.state = {
|
||||
i18n: Languages,
|
||||
};
|
||||
|
||||
Languages.addListener(this);
|
||||
this.inputElement = false;
|
||||
}
|
||||
componentWillUnmount() {
|
||||
Languages.removeListener(this);
|
||||
}
|
||||
selectAll() {
|
||||
this.inputElement.focus();
|
||||
this.inputElement.select();
|
||||
}
|
||||
copy() {
|
||||
this.inputElement.disabled = false;
|
||||
this.inputElement.focus();
|
||||
this.inputElement.select();
|
||||
document.execCommand('copy');
|
||||
this.inputElement.disabled = this.props.disabled;
|
||||
this.tooltip.openWithTimeOut(2);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Tooltip
|
||||
ref={obj => (this.tooltip = obj)}
|
||||
overable={false}
|
||||
tooltip={Languages.t('components.input.copied', [], 'Copié')}
|
||||
>
|
||||
<InputWithButton
|
||||
refInput={obj => (this.inputElement = obj)}
|
||||
btnAction={() => this.copy()}
|
||||
icon="copy"
|
||||
hideBtn={this.props.hideBtn}
|
||||
value={this.props.value}
|
||||
disabled={this.props.disabled}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import './inputs.scss';
|
||||
import CheckIcon from '@material-ui/icons/CheckOutlined';
|
||||
|
||||
export default class Checkbox extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
renderSwitch() {
|
||||
var className = this.props.className || '';
|
||||
|
||||
if (this.props.big) {
|
||||
className += ' big ';
|
||||
}
|
||||
if (this.props.medium) {
|
||||
className += ' medium ';
|
||||
}
|
||||
if (this.props.small) {
|
||||
className += ' small ';
|
||||
}
|
||||
|
||||
if (
|
||||
className.indexOf('medium') === className.indexOf('small') &&
|
||||
className.indexOf('big') === className.indexOf('small') &&
|
||||
className.indexOf('big') < 0
|
||||
) {
|
||||
className += ' medium';
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
' flex justify-center items-center w-6 h-6 border-2 rounded-full text-white ' +
|
||||
(this.props.value
|
||||
? 'border-blue-500 bg-blue-500 hover:border-blue-600 hover:bg-blue-600'
|
||||
: 'border-zinc-300 hover:border-blue-300') +
|
||||
' ' +
|
||||
(this.props.disabled ? 'opacity-50' : 'cursor-pointer') +
|
||||
' ' +
|
||||
(className || '')
|
||||
}
|
||||
onClick={() => {
|
||||
if (!this.props.label && !this.props.disabled) {
|
||||
this.props.onChange(!this.props.value);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="state">
|
||||
<CheckIcon className="m-icon-small" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
var parentClassName = '';
|
||||
|
||||
if (this.props.big) {
|
||||
parentClassName += ' big ';
|
||||
}
|
||||
if (this.props.medium) {
|
||||
parentClassName += ' medium ';
|
||||
}
|
||||
if (this.props.small) {
|
||||
parentClassName += ' small ';
|
||||
}
|
||||
|
||||
if (
|
||||
parentClassName.indexOf('medium') === parentClassName.indexOf('small') &&
|
||||
parentClassName.indexOf('big') === parentClassName.indexOf('small') &&
|
||||
parentClassName.indexOf('big') < 0
|
||||
) {
|
||||
parentClassName += ' medium';
|
||||
}
|
||||
|
||||
if (this.props.label) {
|
||||
return (
|
||||
<div
|
||||
className={'checkbox_with_label ' + (this.props.value ? 'on ' : 'off ') + parentClassName}
|
||||
onClick={() => {
|
||||
if (!this.props.disabled) {
|
||||
this.props.onChange(!this.props.value);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{this.renderSwitch()}
|
||||
<div className="label">{this.props.label}</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return this.renderSwitch();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import MenusManager from '@components/menus/menus-manager.jsx';
|
||||
import ColorPicker from 'components/color-picker/color-picker.jsx';
|
||||
import Input from 'components/inputs/input.jsx';
|
||||
import './inputs.scss';
|
||||
|
||||
export default class InputWithColor extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
outsideMenuListener() {
|
||||
this.closeColorPicker();
|
||||
}
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('click', this.outsideClickListener);
|
||||
}
|
||||
componentDidMount() {
|
||||
if (this.props.focusOnDidMount && this.input) {
|
||||
this.input.focus();
|
||||
}
|
||||
this.outsideClickListener = event => {
|
||||
if (
|
||||
this.colorPickerIsOpen &&
|
||||
this.colorpicker_dom &&
|
||||
!this.colorpicker_dom.contains(event.target) &&
|
||||
document.contains(event.target)
|
||||
) {
|
||||
this.outsideMenuListener();
|
||||
}
|
||||
};
|
||||
this.outsideClickListener = this.outsideClickListener.bind(this);
|
||||
document.addEventListener('click', this.outsideClickListener);
|
||||
}
|
||||
closeColorPicker() {
|
||||
if (!this.colorPickerIsOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.props.menu_level !== undefined) {
|
||||
MenusManager.closeSubMenu(this.props.menu_level);
|
||||
} else {
|
||||
MenusManager.closeMenu();
|
||||
}
|
||||
|
||||
this.colorPickerIsOpen = false;
|
||||
}
|
||||
openColorPicker() {
|
||||
if (this.colorPickerIsOpen) {
|
||||
return;
|
||||
}
|
||||
|
||||
var menu = [
|
||||
{
|
||||
type: 'react-element',
|
||||
reactElement: () => {
|
||||
return (
|
||||
<ColorPicker
|
||||
refDom={node => (this.colorpicker_dom = node)}
|
||||
value={this.props.value[0]}
|
||||
onChange={color => this.selectColor(color)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
var elementRect = window.getBoundingClientRect(this.color_dom);
|
||||
elementRect.x = elementRect.x || elementRect.left;
|
||||
elementRect.y = elementRect.y || elementRect.top;
|
||||
if (this.props.menu_level !== undefined) {
|
||||
MenusManager.openSubMenu(menu, elementRect, this.props.menu_level, 'bottom');
|
||||
} else {
|
||||
MenusManager.openMenu(menu, elementRect, 'bottom');
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.colorPickerIsOpen = true;
|
||||
}, 200);
|
||||
}
|
||||
selectColor(color) {
|
||||
this.closeColorPicker();
|
||||
var value = [color, this.props.value[1]];
|
||||
this.onChange(value);
|
||||
}
|
||||
onChange(value) {
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(value);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
if (!this.props.value[0]) {
|
||||
this.onChange([
|
||||
ColorPicker.colors[parseInt(Math.random() * ColorPicker.colors.length)],
|
||||
this.props.value[1],
|
||||
]);
|
||||
}
|
||||
return (
|
||||
<div className={'input_with_color ' + this.props.className}>
|
||||
<div
|
||||
className="color"
|
||||
ref={node => (this.color_dom = node)}
|
||||
onClick={() => {
|
||||
this.openColorPicker();
|
||||
}}
|
||||
>
|
||||
<div className="acolor" style={{ backgroundColor: this.props.value[0] }} />
|
||||
</div>
|
||||
<div className="right_input">
|
||||
<Input
|
||||
className="full_width medium"
|
||||
refInput={obj => (this.input = obj)}
|
||||
type="text"
|
||||
placeholder={this.props.placeholder}
|
||||
value={this.props.value[1]}
|
||||
onKeyDown={e => {
|
||||
if (e.keyCode == 13 && this.props.onEnter) {
|
||||
this.props.onEnter();
|
||||
}
|
||||
}}
|
||||
onChange={evt => {
|
||||
if (this.onChange) this.onChange([this.props.value[0], evt.target.value]);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import PlusIcon from '@material-ui/icons/AddOutlined';
|
||||
|
||||
export default class Rounded extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
style={this.props.style}
|
||||
className={'rounded-btn ' + this.props.className}
|
||||
onClick={this.props.onClick}
|
||||
>
|
||||
{this.props.text ? this.props.text + ' ' : ''}
|
||||
<PlusIcon className="m-icon-small" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import './interactive-login-background.scss';
|
||||
|
||||
export default class InteractiveLoginBackground extends React.Component {
|
||||
constructor(props) {
|
||||
super();
|
||||
|
||||
this.lFollowX = 0;
|
||||
this.lFollowY = 0;
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.friction = 1 / 30;
|
||||
|
||||
this.objects = [];
|
||||
}
|
||||
addObject() {
|
||||
var div = document.createElement('div');
|
||||
|
||||
var size = Math.pow(0.1 + Math.random(), 2) * 10;
|
||||
var left = Math.random() * 100 + 'vw';
|
||||
|
||||
div.style.width = size + 'px';
|
||||
div.style.height = size + 'px';
|
||||
|
||||
var duration = 30 + Math.random() * 15;
|
||||
var time_class = 'a';
|
||||
if (duration > 40) {
|
||||
time_class = 'b';
|
||||
} else if (duration >= 35) {
|
||||
time_class = 'c';
|
||||
}
|
||||
|
||||
div.style.animationDelay = '-' + Math.random() * 45 + 's';
|
||||
div.style.animationDuration = duration + 's';
|
||||
|
||||
div.style.left = left;
|
||||
|
||||
div.classList.add('animated_shape');
|
||||
if (Math.random() > 0.5) {
|
||||
div.classList.add('circle');
|
||||
}
|
||||
div.classList.add('speed-' + time_class);
|
||||
|
||||
this.background.appendChild(div);
|
||||
|
||||
this.objects.push(div);
|
||||
}
|
||||
mousemove(evt) {
|
||||
this.lFollowX = evt.clientX / window.innerWidth;
|
||||
this.lFollowY = evt.clientY / window.innerHeight;
|
||||
}
|
||||
moveBackground() {
|
||||
if (!this.mounted) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.x += (this.lFollowX - this.x) * this.friction;
|
||||
this.y += (this.lFollowY - this.y) * this.friction;
|
||||
|
||||
this.objects.forEach(div => {
|
||||
var fa, fb;
|
||||
if (div.classList.contains('speed-a')) {
|
||||
fa = 50;
|
||||
fb = 15;
|
||||
}
|
||||
if (div.classList.contains('speed-b')) {
|
||||
fa = 40;
|
||||
fb = 10;
|
||||
}
|
||||
if (div.classList.contains('speed-c')) {
|
||||
fa = 30;
|
||||
fb = 5;
|
||||
}
|
||||
div.style.marginLeft = (this.x - 0.5) * fa;
|
||||
div.style.marginTop = (this.y - 0.5) * fb;
|
||||
});
|
||||
|
||||
window.requestAnimationFrame(this.moveBackground);
|
||||
}
|
||||
componentDidMount() {
|
||||
for (var i = 0; i < 50; i++) {
|
||||
this.addObject();
|
||||
}
|
||||
|
||||
this.mousemove = this.mousemove.bind(this);
|
||||
this.moveBackground = this.moveBackground.bind(this);
|
||||
|
||||
this.mounted = true;
|
||||
this.moveBackground();
|
||||
document.addEventListener('mousemove', this.mousemove);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
document.removeEventListener('mousemove', this.mousemove);
|
||||
}
|
||||
render() {
|
||||
return <div ref={node => (this.background = node)} className="animated_background" />;
|
||||
}
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
.animated_background {
|
||||
width: 100%;
|
||||
height: 60vh;
|
||||
position: relative;
|
||||
background: var(--primary);
|
||||
|
||||
.animated_shape {
|
||||
background: #fff;
|
||||
top: calc(100% + 50px);
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: linear;
|
||||
animation-name: animated_background_shape_animation;
|
||||
position: absolute;
|
||||
border-radius: var(--border-radius-base);
|
||||
}
|
||||
.animated_shape.circle {
|
||||
border-radius: 100%;
|
||||
animation-name: animated_background_shape_animation_circle;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animated_background_shape_animation {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
opacity: 0.7;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-100vh) rotate(600deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes animated_background_shape_animation_circle {
|
||||
0% {
|
||||
transform: translateY(0);
|
||||
opacity: 0.7;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-100vh);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
.locked-history-banner {
|
||||
.title-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
margin: 16px 0 8px 0px;
|
||||
|
||||
.title {
|
||||
line-height: 16px;
|
||||
margin: 0;
|
||||
margin-left: 8px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Typography, Button } from 'antd';
|
||||
import Banner from '@components/banner/banner';
|
||||
import Emojione from '@components/emojione/emojione';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import './locked-history-banner.scss';
|
||||
import consoleService from '@features/console/services/console-service';
|
||||
import useRouterCompany from '@features/router/hooks/use-router-company';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
const LockedHistoryBanner = (): JSX.Element => {
|
||||
const companyId = useRouterCompany();
|
||||
|
||||
const onClickBtn = () =>
|
||||
window.open(consoleService.getCompanySubscriptionUrl(companyId), 'blank');
|
||||
|
||||
return (
|
||||
<Banner
|
||||
type="ghost"
|
||||
height={135}
|
||||
className="locked-history-banner"
|
||||
contentColumnStyle={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
height: '100%',
|
||||
width: '380px',
|
||||
}}
|
||||
>
|
||||
<div className="title-container">
|
||||
<Emojione type=":rocket:" s64 />
|
||||
<Title level={5} className="title">
|
||||
{Languages.t('components.locked_features.locked_history_banner.title')}
|
||||
</Title>
|
||||
</div>
|
||||
<Text type="secondary" className="description">
|
||||
{Languages.t('components.locked_features.locked_history_banner.description')}
|
||||
</Text>
|
||||
<Button type="primary" size="middle" onClick={onClickBtn} style={{ margin: '16px 0 16px 0' }}>
|
||||
{Languages.t('components.locked_features.locked_history_banner.button')}
|
||||
</Button>
|
||||
</Banner>
|
||||
);
|
||||
};
|
||||
|
||||
export default LockedHistoryBanner;
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
import React from 'react';
|
||||
import ObjectModal from '@components/object-modal/object-modal';
|
||||
import { Button, Row, Typography } from 'antd';
|
||||
import ModalManager from '@components/modal/modal-manager';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import consoleService from '@features/console/services/console-service';
|
||||
import useRouterCompany from '@features/router/hooks/use-router-company';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
export default () => {
|
||||
const companyId = useRouterCompany();
|
||||
return (
|
||||
<ObjectModal
|
||||
titleCenter
|
||||
titleLevel={2}
|
||||
title={Languages.t('components.locked_features.locked_workspace_popup.title')}
|
||||
titleTypographyStyle={{ textAlign: 'center', marginBottom: 32 }}
|
||||
style={{ padding: 32 }}
|
||||
contentStyle={{ display: 'flex', flexDirection: 'column', justifyContent: 'center' }}
|
||||
footer={
|
||||
<div
|
||||
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: 32 }}
|
||||
>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
style={{ marginTop: 8 }}
|
||||
onClick={() =>
|
||||
window.open(consoleService.getCompanySubscriptionUrl(companyId), 'blank')
|
||||
}
|
||||
>
|
||||
{Languages.t('components.locked_features.locked_guests_popup.learn_more_button')}
|
||||
</Button>
|
||||
<Text style={{ margin: '16px 0 ' }} strong>
|
||||
{Languages.t('components.locked_features.locked_guests_popup.or')}
|
||||
</Text>
|
||||
<Button
|
||||
type="ghost"
|
||||
style={{ height: 36, width: 163 }}
|
||||
onClick={() => ModalManager.closeAll()}
|
||||
>
|
||||
{Languages.t('components.locked_features.locked_guests_popup.skip_for_now_button')}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
hideFooterDivider
|
||||
footerAlign="center"
|
||||
footerStyle={{ marginBottom: 16 }}
|
||||
>
|
||||
<Row justify="center" align="middle" className="bottom-margin">
|
||||
<Title
|
||||
level={3}
|
||||
children={Languages.t('components.locked_features.locked_workspace_popup.subtitle')}
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
margin: 0,
|
||||
}}
|
||||
/>
|
||||
</Row>
|
||||
|
||||
<Row justify="center">
|
||||
<Text
|
||||
style={{
|
||||
textAlign: 'center',
|
||||
width: '404px',
|
||||
}}
|
||||
children={Languages.t('components.locked_features.locked_workspace_popup.text')}
|
||||
/>
|
||||
</Row>
|
||||
</ObjectModal>
|
||||
);
|
||||
};
|
||||
@@ -1,118 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import Icon from '@components/icon/icon.jsx';
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
import Tabs from 'components/tabs/tabs.jsx';
|
||||
import './deprecated-object-modal.scss';
|
||||
import { Divider } from 'antd';
|
||||
|
||||
export class ObjectModalTitle extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className={'modal_title ' + this.props.className} style={this.props.style}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
//ObjectModalSeparator
|
||||
export class ObjectModalSeparator extends Component {
|
||||
render() {
|
||||
return <div className="separator"></div>;
|
||||
}
|
||||
}
|
||||
//ObjectModalSectionTitle
|
||||
export class ObjectModalSectionTitle extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: this.props.smallMargin ? '16px' : '',
|
||||
}}
|
||||
>
|
||||
<b>{this.props.title || this.props.children}</b>
|
||||
<div>{this.props.action}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ObjectModalFormTitle
|
||||
export class ObjectModalFormTitle extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className={'section_title ' + this.props.className} style={this.props.style}>
|
||||
{this.props.icon && <Icon type={this.props.icon} className="m-icon-small" />}
|
||||
<span>{this.props.name}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ObjectModal extends Component {
|
||||
constructor(props) {
|
||||
super();
|
||||
this.state = {};
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className={'object_modal ' + this.props.className}>
|
||||
<div className="top_right_buttons">
|
||||
{this.props.onEdit && (
|
||||
<div className="square_button" onClick={this.props.onEdit}>
|
||||
<Icon type="edit-alt" className="m-icon-small" />
|
||||
</div>
|
||||
)}
|
||||
{this.props.onClose && (
|
||||
<div className="square_button" onClick={this.props.onClose}>
|
||||
<Icon type="times" className="m-icon-small" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={!this.props.noCloseButton ? 'title' : ''}>{this.props.title}</div>
|
||||
|
||||
{this.props.tabs && (
|
||||
<Tabs
|
||||
tabs={this.props.tabs.map(item => {
|
||||
return {
|
||||
title: item.title || '',
|
||||
render: (
|
||||
<div className="body">
|
||||
<PerfectScrollbar options={{ suppressScrollX: true }} component="div">
|
||||
{item.render}
|
||||
</PerfectScrollbar>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!this.props.tabs && (
|
||||
<div className="body">
|
||||
{!!this.props.noScrollBar && (
|
||||
<div className="child-with-margin">{this.props.children}</div>
|
||||
)}
|
||||
{!this.props.noScrollBar && (
|
||||
<PerfectScrollbar options={{ suppressScrollX: true }} component="div">
|
||||
{this.props.children}
|
||||
</PerfectScrollbar>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{this.props.footer && <div className="separator" style={{ marginTop: 0 }} />}
|
||||
{this.props.footer && (
|
||||
<div className="footer bottom-margin">
|
||||
<Divider />
|
||||
<div className="x-margin">{this.props.footer}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
.object_modal {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 24px;
|
||||
|
||||
& > .title {
|
||||
padding-right: 56px;
|
||||
margin: 16px 0 11px 16px;
|
||||
}
|
||||
|
||||
& > .top_right_buttons {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
text-align: right;
|
||||
|
||||
.square_button {
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
border-radius: var(--border-radius-base);
|
||||
margin-left: 8px;
|
||||
background: var(--grey-background);
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: var(--primary-background);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > .body {
|
||||
margin: 0 0;
|
||||
.scrollbar-container,
|
||||
.child-with-margin {
|
||||
padding: 16px;
|
||||
max-height: calc(80vh - 200px);
|
||||
}
|
||||
}
|
||||
|
||||
.modal_title {
|
||||
font-size: 24px;
|
||||
color: var(--black);
|
||||
}
|
||||
}
|
||||
|
||||
.section_title {
|
||||
color: var(--grey-dark);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 24px;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
&:before {
|
||||
margin-left: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
/* eslint-disable react/no-direct-mutation-state */
|
||||
import React, { Component } from 'react';
|
||||
import Button from 'components/buttons/button.jsx';
|
||||
import Input from 'components/inputs/input.jsx';
|
||||
import Icon from '@components/icon/icon.jsx';
|
||||
import Select from 'components/select/select.jsx';
|
||||
import './reminder-selector.scss';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
|
||||
export default class ReminderSelector extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
reminders: [],
|
||||
};
|
||||
|
||||
this.old_value = JSON.stringify(props.reminders || []);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateFromProps(this.props);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
if (this.old_value != JSON.stringify(nextProps.reminders)) {
|
||||
this.old_value = JSON.stringify(nextProps.reminders);
|
||||
this.updateFromProps(nextProps);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
remove(i) {
|
||||
delete this.state.reminders[i];
|
||||
this.update();
|
||||
}
|
||||
|
||||
add() {
|
||||
this.state.reminders.push({
|
||||
mode: 'push',
|
||||
delay_unit: 'minutes',
|
||||
delay_value: '30',
|
||||
});
|
||||
this.update();
|
||||
}
|
||||
|
||||
update() {
|
||||
var ret = [];
|
||||
this.state.reminders.forEach(item => {
|
||||
if (item.delay_unit == 'minutes' && item.delay_value > 59) {
|
||||
item.delay_value = 30;
|
||||
}
|
||||
if (item.delay_unit == 'hours' && item.delay_value > 23) {
|
||||
item.delay_value = 1;
|
||||
}
|
||||
if (item.delay_unit == 'days' && item.delay_value > 13) {
|
||||
item.delay_value = 1;
|
||||
}
|
||||
if (item.delay_unit == 'weeks' && item.delay_value < 2) {
|
||||
item.delay_value = 2;
|
||||
}
|
||||
|
||||
ret.push({
|
||||
mode: item.mode,
|
||||
delay:
|
||||
parseInt(item.delay_value) *
|
||||
60 *
|
||||
(item.delay_unit == 'hours' ? 60 : 1) *
|
||||
(item.delay_unit == 'days' ? 60 * 24 : 1) *
|
||||
(item.delay_unit == 'weeks' ? 60 * 24 * 7 : 1),
|
||||
});
|
||||
});
|
||||
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange(ret);
|
||||
}
|
||||
|
||||
this.setState({});
|
||||
}
|
||||
|
||||
updateFromProps(nextProps) {
|
||||
var props = nextProps || this.props;
|
||||
|
||||
var reminders = [];
|
||||
|
||||
(props.reminders || []).forEach(item => {
|
||||
var delay_value = parseInt(item.delay / 60);
|
||||
var delay_unit = 'minutes';
|
||||
if (item.delay > 59 * 60) {
|
||||
delay_value = parseInt(item.delay / (60 * 60));
|
||||
delay_unit = 'hours';
|
||||
}
|
||||
if (item.delay > 23 * 60 * 60) {
|
||||
delay_value = parseInt(item.delay / (60 * 60 * 24));
|
||||
delay_unit = 'days';
|
||||
}
|
||||
if (item.delay > 13 * 24 * 60 * 60) {
|
||||
delay_value = parseInt(item.delay / (60 * 60 * 24 * 7));
|
||||
delay_unit = 'weeks';
|
||||
}
|
||||
reminders.push({
|
||||
mode: item.mode,
|
||||
delay_value: delay_value,
|
||||
delay_unit: delay_unit,
|
||||
});
|
||||
});
|
||||
|
||||
this.setState({ reminders: reminders });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="reminderSelector">
|
||||
{this.state.reminders.map((reminder, i) => {
|
||||
return (
|
||||
<div className="bottom-margin" key={`reminder-${i}`}>
|
||||
<Select
|
||||
className="small small-right-margin"
|
||||
value={reminder['mode'] || 'push'}
|
||||
style={{ width: 'auto' }}
|
||||
onChange={value => {
|
||||
this.state.reminders[i].mode = value;
|
||||
this.update();
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
text: Languages.t('components.reminder.notification', [], 'Notification'),
|
||||
value: 'push',
|
||||
},
|
||||
{
|
||||
text: Languages.t('components.reminder.by_email', [], 'E-Mail'),
|
||||
value: 'mail',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Input
|
||||
className="small small-right-margin"
|
||||
type="number"
|
||||
min="0"
|
||||
max="60"
|
||||
step="1"
|
||||
value={reminder['delay_value'] || '0'}
|
||||
onChange={evt => {
|
||||
this.state.reminders[i].delay_value = evt.target.value;
|
||||
if (!evt.target.value) {
|
||||
return;
|
||||
}
|
||||
this.update();
|
||||
}}
|
||||
style={{ width: 60 }}
|
||||
/>
|
||||
|
||||
<Select
|
||||
className="small small-right-margin"
|
||||
value={reminder['delay_unit'] || 'minutes'}
|
||||
style={{ width: 'auto', marginLeft: 10 }}
|
||||
onChange={value => {
|
||||
this.state.reminders[i].delay_unit = value;
|
||||
this.update();
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
text: Languages.t('components.reminder.minutes_bef', [], 'minutes avant'),
|
||||
value: 'minutes',
|
||||
},
|
||||
{
|
||||
text: Languages.t('components.reminder.hours_bef', [], 'heures avant'),
|
||||
value: 'hours',
|
||||
},
|
||||
{
|
||||
text: Languages.t('components.reminder.days_bef', [], 'jours avant'),
|
||||
value: 'days',
|
||||
},
|
||||
{
|
||||
text: Languages.t('components.reminder.weeks_bef', [], 'semaines avant'),
|
||||
value: 'weeks',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Icon
|
||||
type="trash"
|
||||
className="remove_icon"
|
||||
style={{ verticalAlign: 'middle' }}
|
||||
onClick={() => this.remove(i)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
<Button small className="button secondary-text" onClick={() => this.add()}>
|
||||
<Icon type="plus" className="m-icon-small" />{' '}
|
||||
{Languages.t('scenes.apps.calendar.modals.reminder_add', [], 'Ajouter un rappel')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
.reminderSelector {
|
||||
.remove_icon {
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: var(--red);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/* eslint-disable react/jsx-key */
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import PerfectScrollbar from 'react-perfect-scrollbar';
|
||||
import './tabs.scss';
|
||||
|
||||
export default class Tabs extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
i18n: Languages,
|
||||
tab: props.selected,
|
||||
};
|
||||
Languages.addListener(this);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
Languages.removeListener(this);
|
||||
}
|
||||
select(i) {
|
||||
this.setState({ tab: i });
|
||||
this.props.onChange && this.props.onChange(i);
|
||||
}
|
||||
UNSAFE_componentWillUpdate(nextProps, nextState) {
|
||||
if (nextProps.selected && JSON.stringify(nextProps.selected) != this.oldSelected) {
|
||||
nextState.tab = nextProps.selected;
|
||||
this.oldSelected = JSON.stringify(nextProps.selected);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
var selected = this.state.tab || Object.keys(this.props.tabs || {})[0];
|
||||
if (!this.props.tabs[selected]) {
|
||||
selected = Object.keys(this.props.tabs || {})[0];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'component_tabs ' + (this.props.fullBody ? 'full-body ' : '')}>
|
||||
<PerfectScrollbar
|
||||
options={{ suppressScrollY: true }}
|
||||
component="div"
|
||||
className="component_tabs_tabs"
|
||||
>
|
||||
{Object.keys(this.props.tabs || {}).map(i => {
|
||||
var item = this.props.tabs[i];
|
||||
return (
|
||||
<div
|
||||
style={item.titleStyle || {}}
|
||||
className={
|
||||
'component_tabs_tab ' +
|
||||
(i == selected ? 'selected ' : '') +
|
||||
(item.titleClassName || '') +
|
||||
' '
|
||||
}
|
||||
onClick={() => this.select(i)}
|
||||
>
|
||||
{typeof item.title == 'function' ? item.title() : item.title}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</PerfectScrollbar>
|
||||
<div className="body ">
|
||||
{typeof this.props.tabs[selected].render == 'function'
|
||||
? this.props.tabs[selected].render()
|
||||
: this.props.tabs[selected].render}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
.component_tabs {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: relative;
|
||||
right: 0px;
|
||||
left: auto;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
width: 50px;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(to right, #ffffff00 0%, #ffffffff 100%);
|
||||
}
|
||||
|
||||
& > .component_tabs_tabs {
|
||||
border-bottom: 1px solid var(--grey-background);
|
||||
padding: 0 16px;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.component_tabs_tab {
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0;
|
||||
display: inline-block;
|
||||
padding: 8px 16px;
|
||||
font-weight: 500;
|
||||
color: var(--grey-dark);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background: transparent;
|
||||
border-bottom: 4px solid var(--primary);
|
||||
color: var(--black);
|
||||
}
|
||||
}
|
||||
}
|
||||
& > .body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
&.full-body {
|
||||
& > .body,
|
||||
& > .component_tabs_tabs {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
/* eslint-disable react/jsx-key */
|
||||
/* eslint-disable react/no-direct-mutation-state */
|
||||
import React, { Component } from 'react';
|
||||
import Icon from '@components/icon/icon.jsx';
|
||||
import Button from 'components/buttons/button.jsx';
|
||||
import './tag-picker.scss';
|
||||
import MenusManager from '@components/menus/menus-manager.jsx';
|
||||
import TagSelector from './tag-selector.jsx';
|
||||
import Workspaces from '@deprecated/workspaces/workspaces.jsx';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections.js';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
|
||||
export default class TagPicker extends React.Component {
|
||||
constructor(props) {
|
||||
super();
|
||||
this.props = props;
|
||||
this.state = {
|
||||
currentSelected: [],
|
||||
inputValue: '',
|
||||
currentList: [],
|
||||
selected: [],
|
||||
value: this.props.value || [],
|
||||
list: props.data || [
|
||||
{ id: 1, name: Languages.t('scenes.apps.tasks.task_status.todo', [], 'To do') },
|
||||
{ id: 2, name: Languages.t('scenes.apps.tasks.task_status.current', [], 'Doing') },
|
||||
{ id: 3, name: Languages.t('scenes.apps.tasks.task_status.done', [], 'Done') },
|
||||
],
|
||||
};
|
||||
}
|
||||
UNSAFE_componentWillUpdate(nextProps, nextState) {
|
||||
if (JSON.stringify(nextProps.value) != JSON.stringify(this.props.value)) {
|
||||
this.state.value = nextProps.value;
|
||||
}
|
||||
}
|
||||
UNSAFE_componentWillMount() {
|
||||
if (!this.props.data) {
|
||||
Collections.get('tags').addListener(this);
|
||||
Collections.get('tags').addSource(
|
||||
{
|
||||
http_base_url: 'globalsearch/tags',
|
||||
http_options: {
|
||||
workspace_id: Workspaces.currentWorkspaceId,
|
||||
},
|
||||
websockets: [{ uri: 'tags/' + Workspaces.currentWorkspaceId, options: { type: 'tags' } }],
|
||||
},
|
||||
Workspaces.currentWorkspaceId,
|
||||
);
|
||||
}
|
||||
}
|
||||
componentWillUnmount() {
|
||||
if (!this.props.data) {
|
||||
Collections.get('tags').removeListener(this);
|
||||
}
|
||||
}
|
||||
addTags(evt) {
|
||||
var menu = [
|
||||
{
|
||||
type: 'react-element',
|
||||
reactElement: level => {
|
||||
return (
|
||||
<TagSelector
|
||||
level={level}
|
||||
data={
|
||||
this.props.data
|
||||
? this.props.data.map(a => {
|
||||
if (typeof a == 'string') {
|
||||
return { name: a, id: a, color: '#888' };
|
||||
} else {
|
||||
return a;
|
||||
}
|
||||
})
|
||||
: false
|
||||
}
|
||||
canCreate={this.props.canCreate}
|
||||
disabledTags={
|
||||
this.state.value.map(item => {
|
||||
return typeof item == 'string' ? item : item.id;
|
||||
}) || []
|
||||
}
|
||||
onChange={value => {
|
||||
value.forEach(tag => {
|
||||
if (
|
||||
this.state.value
|
||||
.map(item => {
|
||||
return typeof item == 'string' ? item : item.id;
|
||||
})
|
||||
.indexOf(tag.id || tag.name || tag) < 0
|
||||
) {
|
||||
this.state.value.push(tag.id || tag.name || tag);
|
||||
}
|
||||
});
|
||||
if (!this.props.saveButton) this.props.onChange(this.state.value);
|
||||
this.setState({});
|
||||
if (this.props.menu_level !== undefined) {
|
||||
MenusManager.closeSubMenu(this.props.menu_level);
|
||||
} else {
|
||||
MenusManager.closeMenu();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
if (this.props.menu_level !== undefined) {
|
||||
MenusManager.openSubMenu(
|
||||
menu,
|
||||
{ x: evt.clientX, y: evt.clientY },
|
||||
this.props.menu_level,
|
||||
'right',
|
||||
);
|
||||
} else {
|
||||
MenusManager.openMenu(menu, { x: evt.clientX, y: evt.clientY }, 'right');
|
||||
}
|
||||
}
|
||||
render() {
|
||||
var value = this.state.value || [];
|
||||
|
||||
var tag_list = value.map(tag_id => {
|
||||
var tag = false;
|
||||
if (this.props.data) {
|
||||
if (typeof tag_id == 'string') {
|
||||
tag = { name: tag_id, id: tag_id, color: '#888' };
|
||||
} else {
|
||||
tag = tag_id;
|
||||
tag.id = tag.id || tag.name;
|
||||
tag.color = tag.color || '#888';
|
||||
}
|
||||
} else {
|
||||
tag = Collections.get('tags').find(tag_id);
|
||||
}
|
||||
if (!tag) {
|
||||
return '';
|
||||
}
|
||||
var name = tag.name;
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'tag ' + (this.props.inline ? 'inline-tag ' + (this.props.className || '') : '')
|
||||
}
|
||||
style={{ backgroundColor: tag.color }}
|
||||
>
|
||||
{name}{' '}
|
||||
{!this.props.readOnly && (
|
||||
<Icon
|
||||
className="remove"
|
||||
type="times"
|
||||
onClick={() => {
|
||||
this.state.value.splice(this.state.value.indexOf(tag.id), 1);
|
||||
if (!this.props.saveButton) this.props.onChange(this.state.value);
|
||||
this.setState({});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
if (this.props.inline) {
|
||||
return tag_list;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'tagPicker ' + (this.props.className || '')}>
|
||||
{!this.props.readOnly && value.length == 0 && (
|
||||
<div className="tag notag">{Languages.t('components.tagpicker.notag', [], 'No tag')}</div>
|
||||
)}
|
||||
|
||||
{tag_list}
|
||||
|
||||
{!this.props.readOnly && (
|
||||
<Button
|
||||
className="small secondary-text"
|
||||
onClick={evt => {
|
||||
this.addTags(evt);
|
||||
}}
|
||||
>
|
||||
<Icon type="plus" className="m-icon-small" /> {Languages.t('general.add', [], 'Add')}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{this.props.saveButton && (
|
||||
<div className="full_width" style={{ textAlign: 'right' }}>
|
||||
<Button
|
||||
className="small primary"
|
||||
value={Languages.t('general.save')}
|
||||
onClick={() => {
|
||||
this.props.onChange(this.state.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
.tagPicker .tag,
|
||||
.inline-tag {
|
||||
height: 22px;
|
||||
border-radius: var(--border-radius-base);
|
||||
background: var(--grey-dark);
|
||||
color: #fff;
|
||||
line-height: 22px;
|
||||
vertical-align: top;
|
||||
margin-bottom: 8px;
|
||||
margin-right: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding: 0 4px;
|
||||
padding-left: 6px;
|
||||
|
||||
&.notag {
|
||||
background: var(--grey-background);
|
||||
color: var(--grey-dark);
|
||||
}
|
||||
|
||||
.remove {
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.remove:before {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.tagPicker {
|
||||
.tag_selectable {
|
||||
display: flex;
|
||||
.tag_part {
|
||||
flex: 1;
|
||||
}
|
||||
.edit {
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-text {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.pickerInput {
|
||||
padding-left: 5px;
|
||||
|
||||
&.readOnly {
|
||||
padding-left: 0px;
|
||||
}
|
||||
}
|
||||
.itemSelected {
|
||||
display: inline-block;
|
||||
.close {
|
||||
font-size: 8px;
|
||||
margin-left: 5px;
|
||||
opacity: 0.4;
|
||||
display: inline-block;
|
||||
margin-right: -1px;
|
||||
bottom: 0px;
|
||||
position: relative;
|
||||
}
|
||||
.close:hover {
|
||||
opacity: 0.8;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.itemContoured {
|
||||
padding: 1px 6px;
|
||||
display: inline-block;
|
||||
background-color: var(--primary);
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
border-radius: var(--border-radius-base);
|
||||
margin: 5px 0px;
|
||||
margin-right: 5px;
|
||||
height: 18px;
|
||||
line-height: 16px;
|
||||
font-size: 12px;
|
||||
}
|
||||
.menu {
|
||||
.itemContoured {
|
||||
margin: 3px 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.inline-tag {
|
||||
display: inline-block;
|
||||
margin-bottom: 0px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
/* eslint-disable react/no-direct-mutation-state */
|
||||
import React, { Component } from 'react';
|
||||
import Picker from 'components/picker/picker.jsx';
|
||||
import Button from 'components/buttons/button.jsx';
|
||||
import Workspaces from '@deprecated/workspaces/workspaces.jsx';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections.js';
|
||||
import Icon from '@components/icon/icon.jsx';
|
||||
import ColorPicker from 'components/color-picker/color-picker.jsx';
|
||||
import Strings from '@features/global/utils/strings';
|
||||
import InputWithColor from 'components/inputs/input-with-color.jsx';
|
||||
import AlertManager from '@features/global/services/alert-manager-service';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import MenusManager from '@components/menus/menus-manager.jsx';
|
||||
|
||||
class TagEditor extends React.Component {
|
||||
constructor(props) {
|
||||
super();
|
||||
this.props = props;
|
||||
this.state = {
|
||||
edited_tag_name: '',
|
||||
edited_tag_color: '',
|
||||
};
|
||||
}
|
||||
UNSAFE_componentWillMount() {
|
||||
var tag = this.props.tag;
|
||||
this.state.edited_tag_color = tag.color;
|
||||
this.state.edited_tag_name = tag.name;
|
||||
}
|
||||
saveTag(tag) {
|
||||
tag.color = this.state.edited_tag_color || tag.color;
|
||||
tag.name = this.state.edited_tag_name || tag.name;
|
||||
Collections.get('tags').save(tag, Workspaces.currentWorkspaceId);
|
||||
MenusManager.closeSubMenu(this.props.level - 1);
|
||||
}
|
||||
render() {
|
||||
var tag = this.props.tag;
|
||||
return (
|
||||
<div>
|
||||
<InputWithColor
|
||||
menu_level={this.props.level}
|
||||
className="medium bottom-margin full_width"
|
||||
focusOnDidMount
|
||||
placeholder={Languages.t('components.tagpicker.tag_name', [], 'Tag name')}
|
||||
value={[this.state.edited_tag_color, this.state.edited_tag_name]}
|
||||
onEnter={() => {
|
||||
this.saveTag(tag);
|
||||
}}
|
||||
onChange={value => {
|
||||
this.setState({ edited_tag_color: value[0], edited_tag_name: value[1] });
|
||||
}}
|
||||
/>
|
||||
<div style={{ textAlign: 'right' }}>
|
||||
<Button
|
||||
className="small"
|
||||
onClick={() => {
|
||||
this.saveTag(tag);
|
||||
}}
|
||||
value={Languages.t('general.save')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default class TagSelector extends React.Component {
|
||||
constructor(props) {
|
||||
super();
|
||||
this.props = props;
|
||||
this.state = {
|
||||
edited_tag_name: '',
|
||||
edited_tag_color: '',
|
||||
};
|
||||
|
||||
this.colors_random_list = ColorPicker.colors.map(a => a).sort(() => Math.random() - 0.5);
|
||||
this.next_new_color = 0;
|
||||
}
|
||||
onUpdate(item) {}
|
||||
onCreate(text, cb) {
|
||||
var color = this.colors_random_list[this.next_new_color];
|
||||
this.next_new_color = (this.next_new_color + 1) % this.colors_random_list.length;
|
||||
|
||||
var new_tag = Collections.get('tags').edit();
|
||||
new_tag.name = text;
|
||||
new_tag.color = color;
|
||||
new_tag.workspace_id = Workspaces.currentWorkspaceId;
|
||||
Collections.get('tags').save(new_tag, Workspaces.currentWorkspaceId, tag => {
|
||||
cb(new_tag);
|
||||
});
|
||||
|
||||
return new_tag;
|
||||
}
|
||||
onRemove(item, ev) {}
|
||||
renderItemChoosen(item) {
|
||||
return '';
|
||||
}
|
||||
editTag(evt, id) {
|
||||
var tag = Collections.get('tags').find(id);
|
||||
if (!tag) {
|
||||
return;
|
||||
}
|
||||
var menu = [
|
||||
{ type: 'title', text: Languages.t('general.edit') },
|
||||
{
|
||||
type: 'react-element',
|
||||
reactElement: level => {
|
||||
return <TagEditor tag={tag} parent={this} level={level} />;
|
||||
},
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
text: Languages.t('general.remove'),
|
||||
className: 'error',
|
||||
icon: 'trash',
|
||||
onClick: ev => {
|
||||
var tag = Collections.get('tags').find(id);
|
||||
if (tag) {
|
||||
AlertManager.confirm(() => {
|
||||
MenusManager.closeSubMenu(this.props.level - 1);
|
||||
Collections.get('tags').remove(tag, Workspaces.currentWorkspaceId);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
];
|
||||
MenusManager.openSubMenu(menu, { x: evt.clientX, y: evt.clientY }, this.props.level, 'right');
|
||||
}
|
||||
renderItem(item) {
|
||||
var add_option = false;
|
||||
if (typeof item == 'string') {
|
||||
add_option = true;
|
||||
item = { name: item, color: this.colors_random_list[this.next_new_color] };
|
||||
}
|
||||
var tag = (
|
||||
<div
|
||||
className={
|
||||
'tag ' + (this.props.disabledTags.indexOf(item.id || item.name) >= 0 ? 'disabled' : '')
|
||||
}
|
||||
style={{ backgroundColor: item.color, margin: '5px 0' }}
|
||||
>
|
||||
{item.name}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (add_option) {
|
||||
return tag;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="tag_selectable">
|
||||
<div className="tag_part">{tag}</div>
|
||||
{!add_option && !this.props.data && (
|
||||
<div
|
||||
className="edit"
|
||||
onClick={ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.editTag(ev, item.id);
|
||||
}}
|
||||
>
|
||||
<Icon type="ellipsis-h" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
search(text, cb) {
|
||||
var res = Collections.get('tags').findBy({ workspace_id: Workspaces.currentWorkspaceId });
|
||||
if (this.props.data) {
|
||||
res = this.props.data;
|
||||
}
|
||||
|
||||
res = res
|
||||
.filter(function (item) {
|
||||
if (
|
||||
Strings.removeAccents(item.name.toLowerCase().replace(/ +/, '')).indexOf(
|
||||
Strings.removeAccents(text.toLowerCase().replace(/ +/, '')),
|
||||
) !== -1
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
return this.props.disabledTags.indexOf(a.id) >= 0 ? -1 : 1;
|
||||
});
|
||||
cb(res);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Picker
|
||||
className={'tagPicker ' + (this.props.disabled ? 'disabled ' : '')}
|
||||
ref={picker => {
|
||||
this.picker = picker;
|
||||
}}
|
||||
title={false}
|
||||
search={(text, cb) => {
|
||||
this.search(text, cb);
|
||||
}}
|
||||
renderItem={item => {
|
||||
return this.renderItem(item);
|
||||
}}
|
||||
renderItemChoosen={item => {
|
||||
return this.renderItemChoosen(item);
|
||||
}}
|
||||
renderItemSimply={item => {
|
||||
return item.name;
|
||||
}}
|
||||
canCreate={this.props.canCreate !== false}
|
||||
onCreate={(text, cb) => this.onCreate(text, cb)}
|
||||
onSelect={item => this.onSelect(item)}
|
||||
onChange={this.props.onChange}
|
||||
value={this.props.value}
|
||||
readOnly={this.props.readOnly}
|
||||
inline={this.props.inline}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
/* eslint-disable react/jsx-key */
|
||||
import React, { Component } from 'react';
|
||||
import Workspaces from '@deprecated/workspaces/workspaces.jsx';
|
||||
import Button from 'components/buttons/button.jsx';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections.js';
|
||||
import Emojione from 'components/emojione/emojione';
|
||||
import Loader from 'components/loader/loader.jsx';
|
||||
import TasksService from '@deprecated/Apps/Tasks/Tasks.js';
|
||||
import LeftIcon from '@material-ui/icons/KeyboardArrowLeftOutlined';
|
||||
|
||||
import './task-picker.scss';
|
||||
|
||||
export default class TaskPicker extends Component {
|
||||
/*
|
||||
props : {
|
||||
mode : "select_board" / "select_task"
|
||||
}
|
||||
*/
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.tasks_collection_key = 'tasks_picker_' + Workspaces.currentWorkspaceId;
|
||||
this.collection_key = [];
|
||||
|
||||
this.state = {
|
||||
taskRepository: Collections.get('task'),
|
||||
currentBoard: null,
|
||||
currentList: null,
|
||||
taskSelected: null,
|
||||
boardRepository: Collections.get('boards'),
|
||||
};
|
||||
Languages.addListener(this);
|
||||
Collections.get('boards').addListener(this);
|
||||
Collections.get('lists').addListener(this);
|
||||
Collections.get('tasks').addListener(this);
|
||||
Collections.get('boards').addSource(
|
||||
{
|
||||
http_base_url: 'tasks/board',
|
||||
http_options: {
|
||||
workspace_id: Workspaces.currentWorkspaceId,
|
||||
},
|
||||
websockets: [
|
||||
{ uri: 'boards/' + Workspaces.currentWorkspaceId, options: { type: 'board' } },
|
||||
],
|
||||
},
|
||||
this.tasks_collection_key,
|
||||
);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
Languages.removeListener(this);
|
||||
Collections.get('boards').removeSource(this.tasks_collection_key);
|
||||
Collections.get('lists').removeSource(this.tasks_collection_key);
|
||||
Collections.get('tasks').removeSource(this.tasks_collection_key);
|
||||
Collections.get('boards').removeListener();
|
||||
Collections.get('lists').removeListener();
|
||||
Collections.get('tasks').removeListener();
|
||||
}
|
||||
selectBoard(board) {
|
||||
if (this.collection_key.indexOf(this.tasks_collection_key + '_' + board.id) < 0) {
|
||||
this.collection_key.push(this.tasks_collection_key + '_' + board.id);
|
||||
Collections.get('lists').addSource(
|
||||
{
|
||||
http_base_url: 'tasks/list',
|
||||
http_options: {
|
||||
board_id: board.id,
|
||||
},
|
||||
websockets: [{ uri: 'board_lists/' + board.id, options: { type: 'list' } }],
|
||||
},
|
||||
this.tasks_collection_key + '_' + board.id,
|
||||
);
|
||||
Collections.get('tasks').addSource(
|
||||
{
|
||||
http_base_url: 'tasks/task',
|
||||
http_options: {
|
||||
board_id: board.id,
|
||||
},
|
||||
websockets: [{ uri: 'board_tasks/' + board.id, options: { type: 'task' } }],
|
||||
},
|
||||
this.tasks_collection_key + '_' + board.id + '_tasks',
|
||||
);
|
||||
}
|
||||
this.setState({ currentBoard: board });
|
||||
}
|
||||
selectList(list) {
|
||||
this.setState({ currentList: list });
|
||||
}
|
||||
selectTask(task) {
|
||||
this.setState({ taskSelected: task });
|
||||
}
|
||||
submit() {
|
||||
if (this.props.mode === 'select_task' && this.state.taskSelected) {
|
||||
if (this.props.onChoose) {
|
||||
this.props.onChoose(this.state.taskSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
renderBoardPicker() {
|
||||
var boards = Collections.get('boards').findBy({ workspace_id: Workspaces.currentWorkspaceId });
|
||||
var loading =
|
||||
!Collections.get('boards').did_load_first_time[this.tasks_collection_key] &&
|
||||
boards.length === 0;
|
||||
return (
|
||||
<div className="boardPicker">
|
||||
{loading && (
|
||||
<div className="loading">
|
||||
<Loader color="#CCC" className="app_loader" />
|
||||
</div>
|
||||
)}
|
||||
{!loading &&
|
||||
boards.map(board => {
|
||||
return (
|
||||
<div className="picker_item" onClick={() => this.selectBoard(board)}>
|
||||
<div className="board_name_picker">
|
||||
{board.emoji && (
|
||||
<Emojione type={board.emoji} s16 className="board_emoji_picker" />
|
||||
)}
|
||||
<div className="text">{board.title}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
renderListPicker() {
|
||||
var loading =
|
||||
!Collections.get('lists').did_load_first_time[
|
||||
this.tasks_collection_key + '_' + this.state.currentBoard.id
|
||||
];
|
||||
var lists = Collections.get('lists').findBy({ board_id: this.state.currentBoard.id });
|
||||
return (
|
||||
<div className="">
|
||||
{loading && (
|
||||
<div className="loading">
|
||||
<Loader color="#CCC" className="app_loader" />
|
||||
</div>
|
||||
)}
|
||||
{!loading &&
|
||||
lists
|
||||
.sort(
|
||||
(a, b) =>
|
||||
TasksService.getElementIndex(a, 'lists_' + a.board_id) -
|
||||
TasksService.getElementIndex(b, 'lists_' + b.board_id),
|
||||
)
|
||||
.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
className="picker_item"
|
||||
onClick={() => {
|
||||
this.selectList(item);
|
||||
}}
|
||||
>
|
||||
<div className="colorBloc" style={{ backgroundColor: item.color }} />
|
||||
<div className="text">{item.title}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
renderTaskPicker() {
|
||||
var loading =
|
||||
!Collections.get('tasks').did_load_first_time[
|
||||
this.tasks_collection_key + '_' + this.state.currentBoard.id + '_tasks'
|
||||
];
|
||||
var tasks = Collections.get('tasks').findBy({
|
||||
board_id: this.state.currentBoard.id,
|
||||
list_id: this.state.currentList.id,
|
||||
archived: false,
|
||||
});
|
||||
return (
|
||||
<div className="item">
|
||||
{loading && (
|
||||
<div className="loading">
|
||||
<Loader color="#CCC" className="app_loader" />
|
||||
</div>
|
||||
)}
|
||||
{!loading &&
|
||||
(tasks || [])
|
||||
.sort(
|
||||
(a, b) =>
|
||||
TasksService.getElementIndex(a, 'tasks_' + a.list_id) -
|
||||
TasksService.getElementIndex(b, 'tasks_' + b.list_id),
|
||||
)
|
||||
.map((item, index) => (
|
||||
<div
|
||||
className={
|
||||
'picker_item ' +
|
||||
(this.state.taskSelected &&
|
||||
this.props.mode === 'select_task' &&
|
||||
this.state.taskSelected.id === item.id
|
||||
? 'is_selected'
|
||||
: '')
|
||||
}
|
||||
onClick={() => {
|
||||
this.selectTask(item);
|
||||
}}
|
||||
>
|
||||
<div className="text">{item.title}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="taskPicker">
|
||||
{!this.state.currentBoard && (
|
||||
<div className="title">{Languages.t('scenes.apps.tasks.task')}</div>
|
||||
)}
|
||||
{this.state.currentBoard && !this.state.currentList && (
|
||||
<div className="title">
|
||||
<LeftIcon
|
||||
className="m-icon-small getback"
|
||||
onClick={() => {
|
||||
Collections.get('lists').removeListener();
|
||||
this.setState({ currentBoard: null });
|
||||
}}
|
||||
/>
|
||||
{this.state.currentBoard.title}
|
||||
</div>
|
||||
)}
|
||||
{this.state.currentBoard && this.state.currentList && (
|
||||
<div className="title">
|
||||
<LeftIcon
|
||||
className="m-icon-small getback"
|
||||
onClick={() => {
|
||||
Collections.get('tasks').removeListener();
|
||||
this.setState({ currentList: null });
|
||||
}}
|
||||
/>
|
||||
{this.state.currentBoard.title} - {this.state.currentList.title}
|
||||
</div>
|
||||
)}
|
||||
<div className="list">
|
||||
{!this.state.currentBoard && this.renderBoardPicker()}
|
||||
{this.state.currentBoard && !this.state.currentList && this.renderListPicker()}
|
||||
{this.state.currentBoard && this.state.currentList && this.renderTaskPicker()}
|
||||
</div>
|
||||
<div className="menu-buttons">
|
||||
{this.props.mode === 'select_task' &&
|
||||
this.state.taskSelected &&
|
||||
this.state.taskSelected.id && (
|
||||
<Button
|
||||
className="small"
|
||||
value={Languages.t('scenes.app.taskpicker.select', [], 'Sélectionner')}
|
||||
onClick={() => this.submit()}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
.taskPicker {
|
||||
position: relative;
|
||||
.title {
|
||||
background: #ffffff;
|
||||
margin-bottom: 0px;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
line-height: 20px;
|
||||
padding-bottom: 8px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
.getback {
|
||||
background: var(--grey-background);
|
||||
border-radius: var(--border-radius-base);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: top;
|
||||
margin-right: 5px;
|
||||
margin-left: 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.list {
|
||||
height: 150px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
.loading {
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
.picker_item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
bottom: 0px;
|
||||
color: var(--black);
|
||||
height: 40px;
|
||||
font-weight: 500;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border-top: 1px solid var(--grey-background);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
.text {
|
||||
display: inline-block;
|
||||
line-height: 40px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.board_emoji_picker {
|
||||
vertical-align: top;
|
||||
line-height: 40px;
|
||||
}
|
||||
.colorBloc {
|
||||
height: 30px;
|
||||
width: 4px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
.picker_item:hover {
|
||||
background: var(--primary-background);
|
||||
border-color: #fff;
|
||||
}
|
||||
.is_selected {
|
||||
background: var(--primary);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import './elements.scss';
|
||||
|
||||
export default class UserConnectionDot extends React.Component {
|
||||
render() {
|
||||
if (this.props.connected && !this.props.notificationsDisabled) {
|
||||
return <div className="connexion_dot green" />;
|
||||
} else if (!this.props.connected && !this.props.notificationsDisabled) {
|
||||
return <div className="connexion_dot grey" />;
|
||||
} else {
|
||||
return <div className="connexion_dot red" />;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import Picker from 'components/picker/picker.jsx';
|
||||
import Icon from '@components/icon/icon.jsx';
|
||||
import './user-picker.scss';
|
||||
import User from 'components/ui/user.jsx';
|
||||
import UsersService from '@features/users/services/current-user-service';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
|
||||
export default class UserPicker extends React.Component {
|
||||
/*
|
||||
hello
|
||||
*/
|
||||
constructor(props) {
|
||||
super();
|
||||
this.props = props;
|
||||
this.state = {
|
||||
currentSelected: [],
|
||||
inputValue: '',
|
||||
currentList: [],
|
||||
selected: [],
|
||||
};
|
||||
}
|
||||
componentWillUnmount() {}
|
||||
onUpdate(item) {}
|
||||
onRemove(item, ev) {}
|
||||
renderItem(item, withEditor) {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
'itemContoured ' + (withEditor ? 'itemSelected ' : '') + (this.props.mini ? 'mini ' : '')
|
||||
}
|
||||
>
|
||||
<User data={item} mini={this.props.mini} />
|
||||
|
||||
{!this.props.readOnly && withEditor && (
|
||||
<div
|
||||
className="close"
|
||||
onClick={ev => {
|
||||
this.picker.onRemove(item);
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
}}
|
||||
>
|
||||
<Icon type="close" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
search(text, cb) {
|
||||
UsersService.search(text, { scope: this.props.scope || 'all' }, res => {
|
||||
cb(res);
|
||||
});
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<Picker
|
||||
className="userPicker"
|
||||
ref={picker => {
|
||||
this.picker = picker;
|
||||
}}
|
||||
title={
|
||||
this.props.title || Languages.t('components.drive.modify_uslist', [], 'Modify user list')
|
||||
}
|
||||
search={(text, cb) => {
|
||||
this.search(text, cb);
|
||||
}}
|
||||
renderItem={item => {
|
||||
return this.renderItem(item, false);
|
||||
}}
|
||||
renderItemChoosen={item => {
|
||||
return this.renderItem(item, true);
|
||||
}}
|
||||
renderItemSimply={item => {
|
||||
item = item || {};
|
||||
return item.username;
|
||||
}}
|
||||
max={10}
|
||||
onSelect={item => this.onSelect(item)}
|
||||
onChange={this.props.onChange}
|
||||
value={this.props.value}
|
||||
readOnly={this.props.readOnly}
|
||||
inline={this.props.inline}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
.userPicker {
|
||||
.itemSelected {
|
||||
display: inline-flex;
|
||||
max-width: 100%;
|
||||
|
||||
.user_bloc {
|
||||
flex: 1;
|
||||
}
|
||||
.close {
|
||||
font-size: 8px;
|
||||
margin-left: 5px;
|
||||
opacity: 0.4;
|
||||
display: inline-block;
|
||||
margin-right: -1px;
|
||||
bottom: 0px;
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.close:hover {
|
||||
opacity: 0.8;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.itemContoured {
|
||||
display: inline-flex;
|
||||
box-sizing: border-box;
|
||||
color: #000;
|
||||
margin: 5px;
|
||||
height: 18px;
|
||||
line-height: 16px;
|
||||
font-size: 12px;
|
||||
text-transform: capitalize;
|
||||
border-radius: 9px;
|
||||
padding-right: 6px;
|
||||
|
||||
&.mini {
|
||||
padding-right: 0px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
.pickerInput:not(.readOnly) {
|
||||
.itemContoured:hover {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
.menu .itemContoured {
|
||||
margin: 3px;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import UserService from '@features/users/services/current-user-service';
|
||||
import NotificationParameters from '@deprecated/user/notification_parameters.js';
|
||||
import ListenUsers from '@features/users/services/listen-users-service';
|
||||
import UserOnlineStatus from '../online-user-status/online-user-status';
|
||||
|
||||
@@ -21,9 +20,6 @@ export default class User extends Component {
|
||||
render() {
|
||||
var user = this.props.user;
|
||||
var notifications_disabled = false;
|
||||
if (user && NotificationParameters.hasNotificationsDisabled(user.notifications_preferences)) {
|
||||
notifications_disabled = true;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import Observable from '@deprecated/CollectionsV1/observable.js';
|
||||
|
||||
import Globals from '@features/global/services/globals-tdrive-app-service';
|
||||
|
||||
class SelectionsManager extends Observable {
|
||||
constructor() {
|
||||
super();
|
||||
this.setObservableName('selections_manager');
|
||||
|
||||
this.type = '';
|
||||
this.selected_per_type = {};
|
||||
this.last_change = {};
|
||||
|
||||
Globals.window.selected_drive = this;
|
||||
}
|
||||
|
||||
toggle(id) {
|
||||
if (this.selected_per_type[this.type][id]) {
|
||||
this.unselect(id);
|
||||
} else {
|
||||
this.select(id);
|
||||
}
|
||||
}
|
||||
|
||||
select(id) {
|
||||
this.selected_per_type[this.type][id] = true;
|
||||
this.last_change[id] = new Date();
|
||||
this.notify();
|
||||
}
|
||||
|
||||
unselect(id) {
|
||||
delete this.selected_per_type[this.type][id];
|
||||
this.last_change[id] = new Date();
|
||||
this.notify();
|
||||
}
|
||||
|
||||
unselectAll() {
|
||||
if (Object.keys(this.selected_per_type[this.type] || {}).length === 0) {
|
||||
return;
|
||||
}
|
||||
Object.keys(this.selected_per_type[this.type] || {}).forEach(id => {
|
||||
this.last_change[id] = new Date();
|
||||
});
|
||||
this.selected_per_type[this.type] = {};
|
||||
this.notify();
|
||||
}
|
||||
|
||||
setType(type) {
|
||||
if (type !== this.type) {
|
||||
this.type = type;
|
||||
if (!this.selected_per_type[this.type]) {
|
||||
this.selected_per_type[this.type] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Observable improvement, a listener can listen only for modifications on some objects to prevent massive notify and state updates
|
||||
listenOnly(listener, object_front_ids) {
|
||||
if (!listener._observable) {
|
||||
listener._observable = {};
|
||||
}
|
||||
if (!listener._observable[this.observableName]) {
|
||||
listener._observable[this.observableName] = {};
|
||||
}
|
||||
listener._observable[this.observableName].listen_only = object_front_ids;
|
||||
}
|
||||
shouldNotify(node) {
|
||||
if (!this._last_modified) {
|
||||
this._last_modified = {};
|
||||
}
|
||||
var update = true;
|
||||
if (
|
||||
node._observable &&
|
||||
node._observable[this.observableName] &&
|
||||
node._observable[this.observableName].listen_only
|
||||
) {
|
||||
update = false;
|
||||
// eslint-disable-next-line array-callback-return
|
||||
node._observable[this.observableName].listen_only.map(item => {
|
||||
if (!this._last_modified[item] || this.last_change[item] > this._last_modified[item]) {
|
||||
this._last_modified[item] = this.last_change[item];
|
||||
update = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
return update;
|
||||
}
|
||||
}
|
||||
|
||||
const service = new SelectionsManager();
|
||||
export default service;
|
||||
@@ -1,213 +0,0 @@
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import Observable from '@deprecated/CollectionsV1/observable.js';
|
||||
import ws from '@deprecated/websocket/websocket.js';
|
||||
import Api from '@features/global/framework/api-service';
|
||||
import Login from '@features/auth/login-service';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections.js';
|
||||
import AlertManager from '@features/global/services/alert-manager-service';
|
||||
|
||||
import Globals from '@features/global/services/globals-tdrive-app-service';
|
||||
|
||||
/**
|
||||
* FIXME: This service seems still used by some components but we now have ./NotificationPreferences one which seems to overlap...
|
||||
*/
|
||||
class NotificationParameters extends Observable {
|
||||
constructor() {
|
||||
super();
|
||||
this.setObservableName('notifications_parameters');
|
||||
|
||||
Globals.window.notificationsParametersServices = this;
|
||||
|
||||
this.preferences = {};
|
||||
this.loading = true;
|
||||
}
|
||||
|
||||
initFirstTime() {
|
||||
//Save default 'do not disturb' with correct timezone
|
||||
this.init();
|
||||
}
|
||||
|
||||
init(callback) {
|
||||
this.loading = true;
|
||||
this.notify();
|
||||
var that = this;
|
||||
Api.post('/ajax/users/account/get_notifications', {}, function (res) {
|
||||
that.preferences = res.data;
|
||||
that.original_preferences = JSON.parse(JSON.stringify(that.preferences));
|
||||
|
||||
if (that.preferences['dont_disturb_between'] == null) {
|
||||
var l = that.transform_period(22, 8.5, new Date().getTimezoneOffset() / 60);
|
||||
that.preferences['dont_disturb_between'] = l[0];
|
||||
that.preferences['dont_disturb_and'] = l[1];
|
||||
that.save(['dont_disturb_and', 'dont_disturb_between']);
|
||||
}
|
||||
|
||||
that.loading = false;
|
||||
that.notify();
|
||||
|
||||
if (callback) callback();
|
||||
});
|
||||
}
|
||||
|
||||
save(keys, no_notif) {
|
||||
if (!keys) {
|
||||
keys = [];
|
||||
}
|
||||
|
||||
if (!this.preferences) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!keys || keys.length === 0) {
|
||||
this.original_preferences = JSON.parse(JSON.stringify(this.preferences));
|
||||
}
|
||||
|
||||
this.notify();
|
||||
var data = {
|
||||
preferences: JSON.parse(JSON.stringify(this.original_preferences)),
|
||||
};
|
||||
|
||||
keys.forEach(key => {
|
||||
data.preferences[key] = this.preferences[key];
|
||||
});
|
||||
this.original_preferences = data.preferences;
|
||||
|
||||
this.saveElements(data.preferences, no_notif);
|
||||
}
|
||||
|
||||
saveElements(pref, no_notif) {
|
||||
var data = {
|
||||
preferences: JSON.parse(JSON.stringify(pref)),
|
||||
};
|
||||
var user = Collections.get('users').find(Login.currentUserId);
|
||||
if (!user.notifications_preferences) {
|
||||
user.notifications_preferences = {};
|
||||
}
|
||||
Object.keys(pref).forEach(key => {
|
||||
user.notifications_preferences[key] = pref[key];
|
||||
});
|
||||
Collections.get('users').updateObject(user);
|
||||
|
||||
this.loading = true;
|
||||
var that = this;
|
||||
Api.post('/ajax/users/account/set_notifications', data, function (res) {
|
||||
that.loading = false;
|
||||
ws.publish('users/' + Login.currentUserId, {
|
||||
user: {
|
||||
notifications_preferences: Collections.get('users').find(Login.currentUserId)
|
||||
.notifications_preferences,
|
||||
},
|
||||
});
|
||||
that.notify();
|
||||
|
||||
if (!no_notif) {
|
||||
AlertManager.alert(() => {}, {
|
||||
text: Languages.t(
|
||||
'services.user.notification_parameters_update_alert',
|
||||
[],
|
||||
'Les paramètres de notification ont été mis à jour.',
|
||||
),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
is_in_period(a, b) {
|
||||
var currentDate = new Date().getHours() + Math.floor(new Date().getMinutes() / 30) / 2;
|
||||
if (a != null && b != null) {
|
||||
if (a < b && currentDate >= a && currentDate < b) {
|
||||
return true;
|
||||
}
|
||||
if (a > b && (currentDate >= a || currentDate < b)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
hasNotificationsDisabled(preferences) {
|
||||
if (!preferences) {
|
||||
return false;
|
||||
}
|
||||
var l = this.transform_period(
|
||||
preferences.dont_disturb_between,
|
||||
preferences.dont_disturb_and,
|
||||
-new Date().getTimezoneOffset() / 60,
|
||||
);
|
||||
if (this.is_in_period(l[0], l[1])) {
|
||||
return true;
|
||||
}
|
||||
if (preferences.disable_until > new Date().getTime() / 1000) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getNotificationsStatus(user) {
|
||||
this.dont_disturb = this.transform_period(
|
||||
(user.notifications_preferences || {}).dont_disturb_between,
|
||||
(user.notifications_preferences || {}).dont_disturb_and,
|
||||
-new Date().getTimezoneOffset() / 60,
|
||||
);
|
||||
var notifications_state = 'on';
|
||||
if (
|
||||
(user.notifications_preferences || {}).disable_until < new Date().getTime() / 1000 &&
|
||||
!this.is_in_period(this.dont_disturb[0], this.dont_disturb[1])
|
||||
) {
|
||||
notifications_state = 'on';
|
||||
} else if (
|
||||
(user.notifications_preferences || {}).disable_until <
|
||||
new Date().getTime() / 1000 + 60 * 60 * 24 ||
|
||||
this.is_in_period(this.dont_disturb[0], this.dont_disturb[1])
|
||||
) {
|
||||
notifications_state = 'paused';
|
||||
} else {
|
||||
notifications_state = 'off';
|
||||
}
|
||||
return notifications_state;
|
||||
}
|
||||
|
||||
transform_period(a, b, offset) {
|
||||
a = parseFloat(a);
|
||||
b = parseFloat(b);
|
||||
|
||||
if (offset > 0) {
|
||||
offset += -24;
|
||||
}
|
||||
|
||||
a += offset;
|
||||
b += offset;
|
||||
|
||||
if (a < 0 || b < 0) {
|
||||
a += 24;
|
||||
b += 24;
|
||||
|
||||
if (b >= 24) {
|
||||
if (a < b) {
|
||||
b += -24;
|
||||
} else {
|
||||
b += -24;
|
||||
var c = b;
|
||||
b = a;
|
||||
a = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (a >= 24) {
|
||||
if (b < a) {
|
||||
a += -24;
|
||||
} else {
|
||||
a += -24;
|
||||
// eslint-disable-next-line no-redeclare
|
||||
var c = a;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [a, b];
|
||||
}
|
||||
}
|
||||
|
||||
export default new NotificationParameters();
|
||||
@@ -1,46 +0,0 @@
|
||||
import ws from '@deprecated/websocket/websocket.js';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections.js';
|
||||
|
||||
class ListenWorkspace {
|
||||
constructor() {
|
||||
this.workspaces_repository = Collections.get('workspaces');
|
||||
this.listenerCount = {};
|
||||
}
|
||||
|
||||
listenWorkspace(idWorkspace) {
|
||||
if (!idWorkspace) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.listenerCount[idWorkspace]) {
|
||||
this.listenerCount[idWorkspace] = 0;
|
||||
}
|
||||
this.listenerCount[idWorkspace] += 1;
|
||||
|
||||
var that = this;
|
||||
if (this.listenerCount[idWorkspace] === 1) {
|
||||
ws.subscribe('workspace/' + idWorkspace, function (uri, data) {
|
||||
if (data.workspace) {
|
||||
data.workspace.id = idWorkspace;
|
||||
that.workspaces_repository.updateObject(data.workspace);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cancelListenWorkspace(idWorkspace) {
|
||||
if (!idWorkspace) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.listenerCount[idWorkspace]) {
|
||||
this.listenerCount[idWorkspace] += -1;
|
||||
}
|
||||
if (!this.listenerCount[idWorkspace] || this.listenerCount[idWorkspace] === 0) {
|
||||
ws.unsubscribe('workspace/' + idWorkspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const service = new ListenWorkspace();
|
||||
export default service;
|
||||
@@ -1,9 +1,8 @@
|
||||
import FileUploadService from '@features/files/services/file-upload-service';
|
||||
import RouterServices from '@features/router/services/router-service';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { PendingFilesListState } from '../state/atoms/pending-files-list';
|
||||
import { CurrentTaskSelector } from '../state/selectors/current-task';
|
||||
import RouterServices from '@features/router/services/router-service';
|
||||
import { AttachedFileType } from '@features/files/types/file';
|
||||
|
||||
export const useUpload = () => {
|
||||
const { companyId } = RouterServices.getStateFromRoute();
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import { v1 as uuid } from 'uuid';
|
||||
|
||||
import { FileType, PendingFileType } from '@features/files/types/file';
|
||||
import JWTStorage from '@features/auth/jwt-storage-service';
|
||||
import RouterServices from '@features/router/services/router-service';
|
||||
import { FileType, PendingFileType } from '@features/files/types/file';
|
||||
import Resumable from '@features/files/utils/resumable';
|
||||
import Logger from '@features/global/framework/logger-service';
|
||||
import RouterServices from '@features/router/services/router-service';
|
||||
import _ from 'lodash';
|
||||
import FileUploadAPIClient from '../api/file-upload-api-client';
|
||||
import { isPendingFileStatusPending } from '../utils/pending-files';
|
||||
import Logger from '@features/global/framework/logger-service';
|
||||
import _ from 'lodash';
|
||||
import { AttachedFileType } from '@features/files/types/file';
|
||||
|
||||
export enum Events {
|
||||
ON_CHANGE = 'notify',
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
import Observable from '@deprecated/CollectionsV1/observable.js';
|
||||
|
||||
class Autocomplete extends Observable {
|
||||
constructor() {
|
||||
super();
|
||||
this.observableName = 'autocompleteService';
|
||||
this.isOpen = false;
|
||||
}
|
||||
|
||||
open() {
|
||||
this.isOpen = true;
|
||||
this.notify();
|
||||
}
|
||||
|
||||
close() {
|
||||
this.isOpen = false;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
const autocompleteService = new Autocomplete();
|
||||
export default autocompleteService;
|
||||
@@ -1,13 +1,13 @@
|
||||
import { delayRequest } from '@features/global/utils/managedSearchRequest';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { SearchInputState } from '../state/search-input';
|
||||
import { DriveApiClient } from '@features/drive/api-client/api-client';
|
||||
import { LoadingState } from '@features/global/state/atoms/Loading';
|
||||
import { SearchDriveItemsResultsState } from '../state/search-drive-items-result';
|
||||
import { RecentDriveItemsState } from '../state/recent-drive-items';
|
||||
import _ from 'lodash';
|
||||
import { useGlobalEffect } from '@features/global/hooks/use-global-effect';
|
||||
import { LoadingState } from '@features/global/state/atoms/Loading';
|
||||
import { delayRequest } from '@features/global/utils/managedSearchRequest';
|
||||
import useRouterCompany from '@features/router/hooks/use-router-company';
|
||||
import _ from 'lodash';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { RecentDriveItemsState } from '../state/recent-drive-items';
|
||||
import { SearchDriveItemsResultsState } from '../state/search-drive-items-result';
|
||||
import { SearchInputState } from '../state/search-input';
|
||||
import { useSearchModal } from './use-search';
|
||||
|
||||
export const useSearchDriveItemsLoading = () => {
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import * as Text from '@atoms/text';
|
||||
import { ToasterService as Toaster } from '@features/global/services/toaster-service';
|
||||
import UserAPIClient from '@features/users/api/user-api-client';
|
||||
import { useCurrentUser } from '@features/users/hooks/use-current-user';
|
||||
import Radio from 'components/inputs/radio.jsx';
|
||||
|
||||
export type preferencesType = Record<string, unknown>;
|
||||
export type AssistantPreferencesType = {
|
||||
user_id: string;
|
||||
company_id: string;
|
||||
workspace_id: string;
|
||||
preferences: preferencesType;
|
||||
};
|
||||
|
||||
let locked = false;
|
||||
|
||||
export default () => {
|
||||
const { user, refresh } = useCurrentUser();
|
||||
|
||||
const setPreferences = async (value: 'all' | 'nothing' | 'metadata') => {
|
||||
if (locked) return;
|
||||
locked = true;
|
||||
try {
|
||||
await UserAPIClient.setUserPreferences({
|
||||
knowledge_graph: value,
|
||||
});
|
||||
await refresh();
|
||||
Toaster.success(Languages.t('scenes.apps.account.assistant.success'));
|
||||
} catch (err) {
|
||||
Toaster.error('' + err);
|
||||
}
|
||||
locked = false;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="title">{Languages.t('scenes.apps.account.assistant.title')}</div>
|
||||
|
||||
<Text.Info>{Languages.t('scenes.apps.account.assistant.description')}</Text.Info>
|
||||
|
||||
<div className="parameters_form" style={{ maxWidth: 'none', paddingTop: 10 }}>
|
||||
<Radio
|
||||
small
|
||||
label={Languages.t('scenes.apps.account.assistant.share.nothing')}
|
||||
value={user?.preferences?.knowledge_graph === 'nothing'}
|
||||
onChange={() => {
|
||||
setPreferences('nothing');
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
|
||||
<Radio
|
||||
small
|
||||
label={Languages.t('scenes.apps.account.assistant.share.metadata')}
|
||||
value={
|
||||
!user?.preferences?.knowledge_graph || user?.preferences?.knowledge_graph === 'metadata'
|
||||
}
|
||||
onChange={() => {
|
||||
setPreferences('metadata');
|
||||
}}
|
||||
/>
|
||||
<br />
|
||||
|
||||
<Radio
|
||||
small
|
||||
label={Languages.t('scenes.apps.account.assistant.share.all')}
|
||||
value={user?.preferences?.knowledge_graph === 'all'}
|
||||
onChange={() => {
|
||||
setPreferences('all');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,26 +1,24 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
/* eslint-disable react/jsx-key */
|
||||
import React, { Component } from 'react';
|
||||
import { Component } from 'react';
|
||||
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections.js';
|
||||
import LoginService from '@features/auth/login-service';
|
||||
import popupManager from '@deprecated/popupManager/popupManager.js';
|
||||
import userService from '@features/users/services/current-user-service';
|
||||
import currentUserService from '@deprecated/user/CurrentUser';
|
||||
import uploadService from '@deprecated/uploadManager/upload-manager.js';
|
||||
import ButtonWithTimeout from 'components/buttons/button-with-timeout.jsx';
|
||||
import Attribute from 'components/parameters/attribute.jsx';
|
||||
import Assistant from './Pages/Assistant';
|
||||
import MenuList from 'components/menus/menu-component.jsx';
|
||||
import './UserParameter.scss';
|
||||
import Input from 'components/inputs/input.jsx';
|
||||
import { Button } from '../../../../atoms/button/button';
|
||||
import { ExternalLinkIcon } from '@heroicons/react/outline';
|
||||
import InitService from '@features/global/services/init-service';
|
||||
import * as Text from '../../../../atoms/text';
|
||||
import workspaceService from '@deprecated/workspaces/workspaces.jsx';
|
||||
import { getFilesTree } from '@components/uploads/file-tree-utils';
|
||||
import Collections from '@deprecated/CollectionsV1/Collections/Collections.js';
|
||||
import popupManager from '@deprecated/popupManager/popupManager.js';
|
||||
import currentUserService from '@deprecated/user/CurrentUser';
|
||||
import workspaceService from '@deprecated/workspaces/workspaces.jsx';
|
||||
import LoginService from '@features/auth/login-service';
|
||||
import InitService from '@features/global/services/init-service';
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import userService from '@features/users/services/current-user-service';
|
||||
import { ExternalLinkIcon } from '@heroicons/react/outline';
|
||||
import ButtonWithTimeout from 'components/buttons/button-with-timeout.jsx';
|
||||
import Input from 'components/inputs/input.jsx';
|
||||
import MenuList from 'components/menus/menu-component.jsx';
|
||||
import Attribute from 'components/parameters/attribute.jsx';
|
||||
import { Button } from '../../../../atoms/button/button';
|
||||
import * as Text from '../../../../atoms/text';
|
||||
import './UserParameter.scss';
|
||||
|
||||
export default class UserParameter extends Component {
|
||||
constructor(props) {
|
||||
@@ -605,9 +603,6 @@ export default class UserParameter extends Component {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (this.state.page === 4) {
|
||||
return <Assistant />;
|
||||
}
|
||||
}
|
||||
|
||||
setPage(page) {
|
||||
@@ -630,18 +625,6 @@ export default class UserParameter extends Component {
|
||||
this.setPage(1);
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'menu',
|
||||
text: this.state.i18n.t('scenes.apps.account.assistant.title'),
|
||||
emoji: ':robot:',
|
||||
hide:
|
||||
document.location.origin === 'https://web.tdrive.app' &&
|
||||
workspaceService.currentGroupId !== '56393af2-e5fe-11e9-b894-0242ac120004',
|
||||
selected: this.state.page === 4 ? 'selected' : '',
|
||||
onClick: () => {
|
||||
this.setPage(4);
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,6 @@ import Icon from '@components/icon/icon.jsx';
|
||||
|
||||
import LoginView from './login-view/login-view';
|
||||
import Signin from './signin/signin.jsx';
|
||||
import VerifyMail from './verify-mail/verify-mail.jsx';
|
||||
import ForgotPassword from './forgot-password/index.jsx';
|
||||
import Error from './error';
|
||||
|
||||
@@ -45,7 +44,6 @@ export default () => {
|
||||
{LoginService.state === 'error' && <Error />}
|
||||
{LoginService.state === 'logged_out' && <LoginView />}
|
||||
{LoginService.state === 'signin' && <Signin />}
|
||||
{LoginService.state === 'verify_mail' && <VerifyMail />}
|
||||
{LoginService.state === 'forgot_password' && <ForgotPassword />}
|
||||
|
||||
<div className={'app_version_footer '}>
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import Languages from '@features/global/services/languages-service';
|
||||
import LoginService from '@features/auth/login-service';
|
||||
import AccountService from '@deprecated/login/account';
|
||||
import Emojione from 'components/emojione/emojione';
|
||||
import WindowState from '@features/global/utils/window';
|
||||
|
||||
export default class VerifyMail extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
login: LoginService,
|
||||
i18n: Languages,
|
||||
status: 'pending',
|
||||
};
|
||||
LoginService.addListener(this);
|
||||
Languages.addListener(this);
|
||||
}
|
||||
componentDidMount() {
|
||||
AccountService.doVerifyMail(
|
||||
WindowState.findGetParameter('m'),
|
||||
WindowState.findGetParameter('c'),
|
||||
WindowState.findGetParameter('token'),
|
||||
() => {
|
||||
this.setState({ status: 'success' });
|
||||
document.location.replace('/');
|
||||
LoginService.init();
|
||||
},
|
||||
() => {
|
||||
this.setState({ status: 'error' });
|
||||
},
|
||||
);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
LoginService.removeListener(this);
|
||||
Languages.removeListener(this);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div className="verify_mail">
|
||||
<div className="center_box_container login_view fade_in">
|
||||
<div className="center_box white_box_with_shadow" style={{ width: '400px' }}>
|
||||
<div className="title">
|
||||
{Languages.t('scenes.login.verifymail.alert', [], 'Nous vérifions votre e-mail !')}
|
||||
</div>
|
||||
|
||||
{this.state.status === 'pending' && (
|
||||
<div className="subtitle">
|
||||
<Emojione type=":hourglass:" />{' '}
|
||||
{Languages.t(
|
||||
'scenes.login.verifymail.verification_waiting',
|
||||
[],
|
||||
'En attente de vérification...',
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{this.state.status === 'success' && [
|
||||
<div className="subtitle" key='scenes.login.verifymail.success'>
|
||||
<Emojione type=":white_check_mark:" />{' '}
|
||||
{Languages.t(
|
||||
'scenes.login.verifymail.success',
|
||||
[],
|
||||
'Votre e-mail a été vérifié avec succès!',
|
||||
)}
|
||||
</div>,
|
||||
// eslint-disable-next-line jsx-a11y/anchor-is-valid
|
||||
<a href="#" onClick={() => (document.location = '/')} className="blue_link" key="scenes.login.verifymail.signin_button">
|
||||
{Languages.t('scenes.login.verifymail.signin_button', [], 'Se connecter')}
|
||||
</a>,
|
||||
]}
|
||||
|
||||
{this.state.status === 'error' && [
|
||||
<div className="subtitle" key="scenes.login.verifymail.error_message">
|
||||
<Emojione type=":confused:" />{' '}
|
||||
{Languages.t(
|
||||
'scenes.login.verifymail.error_message',
|
||||
[],
|
||||
"Une erreur s'est produite",
|
||||
)}
|
||||
</div>,
|
||||
// eslint-disable-next-line jsx-a11y/anchor-is-valid
|
||||
<a
|
||||
key="scenes.login.home.create_account"
|
||||
onClick={() => {
|
||||
LoginService.changeState('signin');
|
||||
document.location.replace('/');
|
||||
}}
|
||||
className="blue_link"
|
||||
>
|
||||
{this.state.i18n.t('scenes.login.home.create_account')}
|
||||
</a>,
|
||||
]}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user