Removing additional js files

This commit is contained in:
Romaric Mourgues
2023-04-20 11:52:18 +02:00
parent c515d5bad7
commit c4cd108a51
44 changed files with 29 additions and 3596 deletions
@@ -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;
}
}
}
@@ -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>
);
}
}
@@ -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>
);
}
}
@@ -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" />;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
@@ -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>
);
}
}