1
0
Fork 0
mirror of https://github.com/anyproto/anytype-ts.git synced 2025-06-09 09:35:02 +09:00
This commit is contained in:
Andrew Simachev 2024-12-06 19:54:19 +01:00
commit ce4bacb8ed
No known key found for this signature in database
GPG key ID: 1DFE44B21443F0EF
23 changed files with 446 additions and 593 deletions

View file

@ -623,7 +623,9 @@ onClick = ({ x, y }) => {
onSelect = ({ x, y, selectRelated }) => {
const d = getNodeByCoords(x, y);
let related = [];
let related = [];
if (d) {
if (selectRelated) {
related = edgeMap.get(d.id);
@ -637,6 +639,7 @@ onSetRootId = ({ x, y }) => {
const d = getNodeByCoords(x, y);
if (d) {
this.setRootId({ rootId: d.id });
send('setRootId', { node: d.id });
};
};

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "anytype",
"version": "0.43.26-alpha",
"version": "0.43.27-alpha",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "anytype",
"version": "0.43.26-alpha",
"version": "0.43.27-alpha",
"hasInstallScript": true,
"license": "SEE LICENSE IN LICENSE.md",
"dependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "anytype",
"version": "0.43.26-alpha",
"version": "0.43.27-alpha",
"description": "Anytype",
"main": "electron.js",
"scripts": {

View file

@ -115,7 +115,7 @@ const BlockChat = observer(class BlockChat extends React.Component<I.BlockCompon
rootId={rootId}
blockId={blockId}
subId={subId}
scrollToBottom={this.scrollToBottom}
scrollToBottom={this.scrollToBottomCheck}
scrollToMessage={this.scrollToMessage}
getMessages={this.getMessages}
getReplyContent={this.getReplyContent}
@ -600,6 +600,7 @@ const BlockChat = observer(class BlockChat extends React.Component<I.BlockCompon
onReplyEdit (e: React.MouseEvent, message: any) {
this.refForm.onReply(message);
this.scrollToBottomCheck();
};
onReplyClick (e: React.MouseEvent, message: any) {

View file

@ -743,6 +743,7 @@ const ChatForm = observer(class ChatForm extends React.Component<Props, State> {
onReplyClear () {
this.replyingId = '';
this.forceUpdate();
this.props.scrollToBottom();
};
onDelete (id: string) {

View file

@ -57,7 +57,7 @@ const BlockFeatured = observer(class BlockFeatured extends React.Component<Props
return (
<div
ref={node => this.node = node}
className={[ 'wrap', 'focusable', 'c' + block.id ].join(' ')}
className={[ 'wrap', 'focusable', `c${block.id}` ].join(' ')}
tabIndex={0}
onKeyDown={this.onKeyDown}
onKeyUp={this.onKeyUp}

View file

@ -1,4 +1,4 @@
import * as React from 'react';
import React, { FC, useRef } from 'react';
import { U } from 'Lib';
interface Props {
@ -6,61 +6,29 @@ interface Props {
onDragEnd(oldIndex: number, newIndex: number): void;
};
class DragBox extends React.Component<Props> {
_isMounted = false;
node: any = null;
cache: any = {};
ox = 0;
oy = 0;
oldIndex = -1;
newIndex = -1;
constructor (props: Props) {
super(props);
const DragBox: FC<Props> = ({ children: initialChildren, onDragEnd }) => {
this.onDragStart = this.onDragStart.bind(this);
};
render () {
const children = React.Children.map(this.props.children, (child: any) => {
return React.cloneElement(child, {
onDragStart: this.onDragStart
});
});
const nodeRef = useRef(null);
const cache = useRef({});
const ox = useRef(0);
const oy = useRef(0);
const oldIndex = useRef(-1);
const newIndex = useRef(-1);
return (
<span
ref={node => this.node = node}
className="dragbox"
>
{children}
</span>
);
};
componentDidMount () {
this._isMounted = true;
};
componentWillUnmount () {
this._isMounted = false;
};
onDragStart (e: any) {
const onDragStart = (e: any) => {
e.preventDefault();
e.stopPropagation();
if (!this._isMounted) {
if (!nodeRef.current) {
return;
};
const win = $(window);
const node = $(this.node);
const node = $(nodeRef.current);
const items = node.find('.isDraggable');
const element = $(e.currentTarget);
const clone = element.clone();
const offset = node.offset();
const { left, top } = node.offset();
items.each((i: number, item: any) => {
item = $(item);
@ -71,7 +39,7 @@ class DragBox extends React.Component<Props> {
};
const p = item.position();
this.cache[id] = {
cache.current[id] = {
x: p.left,
y: p.top,
width: item.outerWidth(),
@ -79,58 +47,57 @@ class DragBox extends React.Component<Props> {
};
});
this.ox = offset.left;
this.oy = offset.top;
this.oldIndex = element.data('index');
ox.current = left;
oy.current = top;
oldIndex.current = element.data('index');
node.append(clone);
clone.addClass('isClone');
element.addClass('isDragging');
win.off('mousemove.dragbox mouseup.dragbox');
win.on('mousemove.dragbox', e => this.onDragMove(e));
win.on('mouseup.dragbox', e => this.onDragEnd(e));
win.on('mousemove.dragbox', e => onDragMove(e));
win.on('mouseup.dragbox', e => onDragEndHandler(e));
};
onDragMove (e: any) {
if (!this._isMounted) {
const onDragMove = (e: any) => {
if (!nodeRef.current) {
return;
};
const node = $(this.node);
const node = $(nodeRef.current);
const items = node.find('.isDraggable');
const clone = node.find('.isDraggable.isClone');
const width = clone.outerWidth();
const height = clone.outerHeight();
const x = e.pageX - this.ox - width / 2;
const y = e.pageY - this.oy - height / 2;
const x = e.pageX - ox.current - width / 2;
const y = e.pageY - oy.current - height / 2;
const center = x + width / 2;
this.newIndex = -1;
newIndex.current = -1;
node.find('.isDraggable.isOver').removeClass('isOver left right');
clone.css({ transform: `translate3d(${x}px,${y}px,0px)` });
for (let i = 0; i < items.length; ++i) {
const el = $(items.get(i));
const rect = this.cache[el.data('id')];
const rect = cache.current[el.data('id')];
if (rect && U.Common.rectsCollide({ x: center, y, width: 2, height }, rect)) {
const isLeft = center <= rect.x + rect.width / 2;
this.newIndex = i;
newIndex.current = i;
el.addClass('isOver ' + (isLeft ? 'left' : 'right'));
break;
};
};
};
onDragEnd (e: any) {
if (!this._isMounted) {
const onDragEndHandler = (e: any) => {
if (!nodeRef.current) {
return;
};
const node = $(this.node);
const { onDragEnd } = this.props;
const node = $(nodeRef.current);
node.find('.isDraggable.isClone').remove();
node.find('.isDraggable.isDragging').removeClass('isDragging');
@ -138,15 +105,25 @@ class DragBox extends React.Component<Props> {
$(window).off('mousemove.dragbox mouseup.dragbox');
if (this.newIndex >= 0) {
onDragEnd(this.oldIndex, this.newIndex);
if (newIndex.current >= 0) {
onDragEnd(oldIndex.current, newIndex.current);
};
this.cache = {};
this.oldIndex = -1;
this.newIndex = -1;
cache.current = {};
oldIndex.current = -1;
newIndex.current = -1;
};
const children = React.Children.map(initialChildren, (child: any) => React.cloneElement(child, { onDragStart }));
return (
<span
ref={nodeRef}
className="dragbox"
>
{children}
</span>
);
};
export default DragBox;

View file

@ -1,93 +1,22 @@
import * as React from 'react';
import React, { forwardRef, useRef, useImperativeHandle } from 'react';
import * as ReactDOM from 'react-dom';
import $ from 'jquery';
import { observer } from 'mobx-react';
import { I, M, S, U, J, keyboard } from 'Lib';
interface State {
rootId: string;
type: I.DropType;
width: number;
ids: string[];
};
const DragLayer = observer(forwardRef((_, ref: any) => {
const nodeRef = useRef(null);
class DragLayer extends React.Component<object, State> {
_isMounted = false;
node: any = null;
state = {
rootId: '',
type: I.DropType.None,
width: 0,
ids: [] as string[],
};
constructor (props: any) {
super(props);
this.show = this.show.bind(this);
this.hide = this.hide.bind(this);
};
render () {
const { width } = this.state;
return (
<div
ref={node => this.node = node}
id="dragLayer"
className="dragLayer"
style={{ width }}
>
<div id="inner" className="inner" />
</div>
);
};
componentDidMount () {
this._isMounted = true;
};
componentDidUpdate () {
if (!this._isMounted) {
return;
};
const node = $(this.node);
node.find('.block').attr({ id: '' });
node.find('.selectionTarget').attr({ id: '' });
this.renderContent();
};
componentWillUnmount () {
this._isMounted = false;
};
show (rootId: string, type: I.DropType, ids: string[], component: any, x: number, y: number) {
if (!this._isMounted) {
return;
};
const show = (rootId: string, type: I.DropType, ids: string[], component: any) => {
const comp = $(ReactDOM.findDOMNode(component));
const rect = (comp.get(0) as Element).getBoundingClientRect();
this.setState({ rootId, type, width: rect.width - J.Size.blockMenu, ids });
};
hide () {
if (this._isMounted) {
this.setState({ rootId: '', type: I.DropType.None, ids: [], width: 0 });
};
};
renderContent () {
const { rootId, type, ids } = this.state;
const node = $(this.node);
const width = rect.width - J.Size.blockMenu;
const node = $(nodeRef.current);
const inner = node.find('#inner').html('');
const container = U.Common.getPageContainer(keyboard.isPopup());
const wrap = $('<div></div>');
switch (type) {
case I.DropType.Block: {
wrap.addClass('blocks');
@ -157,8 +86,31 @@ class DragLayer extends React.Component<object, State> {
};
inner.append(wrap);
node.css({ width });
node.find('.block').attr({ id: '' });
node.find('.selectionTarget').attr({ id: '' });
};
};
const hide = () => {
$(nodeRef.current).find('#inner').html('')
};
useImperativeHandle(ref, () => ({
show,
hide,
}));
return (
<div
ref={nodeRef}
id="dragLayer"
className="dragLayer"
>
<div id="inner" className="inner" />
</div>
);
}));
export default DragLayer;

View file

@ -218,6 +218,7 @@ const DragProvider = observer(class DragProvider extends React.Component<Props>
this.initData();
this.unbind();
console.log('SET LAYER');
e.dataTransfer.setDragImage(layer.get(0), 0, 0);
e.dataTransfer.setData('text/plain', JSON.stringify(dataTransfer));
e.dataTransfer.setData('data-' + JSON.stringify(dataTransfer), '1');

View file

@ -343,6 +343,10 @@ const Graph = observer(forwardRef<GraphRefProps, Props>(({
break;
};
case 'setRootId': {
$(window).trigger('updateGraphRoot', { id: data.node });
};
};
};

View file

@ -1,6 +1,6 @@
import * as React from 'react';
import React, { forwardRef, useRef, useEffect, useImperativeHandle } from 'react';
import { I, S, U, J, Renderer, keyboard, sidebar, Preview, translate } from 'Lib';
import { Icon } from 'Component';
import { Icon, Sync } from 'Component';
import HeaderAuthIndex from './auth';
import HeaderMainObject from './main/object';
@ -25,80 +25,51 @@ const Components = {
mainEmpty: HeaderMainEmpty,
};
class Header extends React.Component<Props> {
const Header = forwardRef<{}, Props>((props, ref) => {
refChild: any = null;
const {
component,
className = '',
withBanner = false,
rootId = '',
tab = '',
tabs = [],
layout = I.ObjectLayout.Page,
isPopup = false,
onTab,
} = props;
constructor (props: Props) {
super(props);
const childRef = useRef(null);
const Component = Components[component] || null;
const cn = [ 'header', component, className ];
this.menuOpen = this.menuOpen.bind(this);
this.renderLeftIcons = this.renderLeftIcons.bind(this);
this.renderTabs = this.renderTabs.bind(this);
this.onSearch = this.onSearch.bind(this);
this.onTooltipShow = this.onTooltipShow.bind(this);
this.onTooltipHide = this.onTooltipHide.bind(this);
this.onDoubleClick = this.onDoubleClick.bind(this);
this.onExpand = this.onExpand.bind(this);
this.onRelation = this.onRelation.bind(this);
if (![ 'authIndex' ].includes(component)) {
cn.push('isCommon');
};
render () {
const { component, className, withBanner } = this.props;
const Component = Components[component] || null;
const cn = [ 'header', component, className ];
if (![ 'authIndex' ].includes(component)) {
cn.push('isCommon');
};
if (withBanner) {
cn.push('withBanner');
};
if (withBanner) {
cn.push('withBanner');
};
const renderLeftIcons = (onOpen?: () => void) => {
const object = S.Detail.get(rootId, rootId, J.Relation.template);
const isTypeOrRelation = U.Object.isTypeOrRelationLayout(object.layout);
const showMenu = !isTypeOrRelation;
const canSync = showMenu && !object.templateIsBundled && !U.Object.isParticipantLayout(object.layout);
return (
<div id="header" className={cn.join(' ')} onDoubleClick={this.onDoubleClick}>
{Component ? (
<Component
ref={ref => this.refChild = ref}
{...this.props}
onSearch={this.onSearch}
onTooltipShow={this.onTooltipShow}
onTooltipHide={this.onTooltipHide}
menuOpen={this.menuOpen}
renderLeftIcons={this.renderLeftIcons}
renderTabs={this.renderTabs}
onRelation={this.onRelation}
/>
) : ''}
</div>
);
};
componentDidMount () {
sidebar.resizePage(null, null, false);
};
componentDidUpdate () {
sidebar.resizePage(null, null, false);
this.refChild?.forceUpdate();
};
renderLeftIcons (onOpen?: () => void) {
return (
<React.Fragment>
<>
<Icon
className="expand withBackground"
tooltip={translate('commonOpenObject')}
onClick={onOpen || this.onExpand}
onClick={onOpen || onExpand}
/>
</React.Fragment>
{canSync ? <Sync id="button-header-sync" onClick={onSync} /> : ''}
</>
);
};
renderTabs () {
const { tab, tabs, onTab } = this.props;
const renderTabs = () => {
return (
<div id="tabs" className="tabs">
{tabs.map((item: any, i: number) => (
@ -106,8 +77,8 @@ class Header extends React.Component<Props> {
key={i}
className={[ 'tab', (item.id == tab ? 'active' : '') ].join(' ')}
onClick={() => onTab(item.id)}
onMouseOver={e => this.onTooltipShow(e, item.tooltip, item.tooltipCaption)}
onMouseOut={this.onTooltipHide}
onMouseOver={e => onTooltipShow(e, item.tooltip, item.tooltipCaption)}
onMouseOut={onTooltipHide}
>
{item.name}
</div>
@ -116,37 +87,34 @@ class Header extends React.Component<Props> {
);
};
onExpand () {
const { rootId, layout } = this.props;
const onExpand = () => {
S.Popup.closeAll(null, () => U.Object.openRoute({ id: rootId, layout }));
};
onSearch () {
const onSearch = () => {
keyboard.onSearchPopup('Header');
};
onTooltipShow (e: any, text: string, caption?: string) {
const onTooltipShow = (e: any, text: string, caption?: string) => {
const t = Preview.tooltipCaption(text, caption);
if (t) {
Preview.tooltipShow({ text: t, element: $(e.currentTarget), typeY: I.MenuDirection.Bottom });
};
};
onTooltipHide () {
const onTooltipHide = () => {
Preview.tooltipHide(false);
};
onDoubleClick () {
const onDoubleClick = () => {
if (U.Common.isPlatformMac()) {
Renderer.send('winCommand', 'maximize');
};
};
menuOpen (id: string, elementId: string, param: Partial<I.MenuParam>) {
const { isPopup } = this.props;
const menuOpen = (id: string, elementId: string, param: Partial<I.MenuParam>) => {
const st = $(window).scrollTop();
const element = $(`${this.getContainer()} ${elementId}`);
const element = $(`${getContainer()} ${elementId}`);
const menuParam: any = Object.assign({
element,
offsetY: 4,
@ -160,18 +128,17 @@ class Header extends React.Component<Props> {
S.Menu.closeAllForced(null, () => S.Menu.open(id, menuParam));
};
onRelation (param?: Partial<I.MenuParam>, data?: any) {
const onRelation = (param?: Partial<I.MenuParam>, data?: any) => {
param = param || {};
data = data || {};
const { isPopup, rootId } = this.props;
const cnw = [ 'fixed' ];
if (!isPopup) {
cnw.push('fromHeader');
};
this.menuOpen('blockRelationView', '#button-header-relation', {
menuOpen('blockRelationView', '#button-header-relation', {
noFlipX: true,
noFlipY: true,
horizontal: I.MenuDirection.Right,
@ -186,10 +153,65 @@ class Header extends React.Component<Props> {
});
};
getContainer () {
return (this.props.isPopup ? '.popup' : '') + ' .header';
const onSync = () => {
menuOpen('syncStatus', '#button-header-sync', {
subIds: [ 'syncStatusInfo' ],
data: {
rootId,
}
});
};
};
const getContainer = () => {
return (isPopup ? '.popup' : '') + ' .header';
};
useEffect(() => {
sidebar.resizePage(null, null, false);
});
useImperativeHandle(ref, () => ({
setRootId: (rootId: string) => {
if (childRef.current && childRef.current.setRootId) {
childRef.current.setRootId(rootId);
};
},
setVersion: (version: string) => {
if (childRef.current && childRef.current.setVersion) {
childRef.current.setVersion(version);
};
},
forceUpdate: () => {
if (childRef.current && childRef.current.forceUpdate) {
childRef.current.forceUpdate();
};
},
}));
return (
<div
id="header"
className={cn.join(' ')}
onDoubleClick={onDoubleClick}
>
{Component ? (
<Component
ref={childRef}
{...props}
onSearch={onSearch}
onTooltipShow={onTooltipShow}
onTooltipHide={onTooltipHide}
menuOpen={menuOpen}
renderLeftIcons={renderLeftIcons}
renderTabs={renderTabs}
onRelation={onRelation}
/>
) : ''}
</div>
);
});
export default Header;

View file

@ -1,60 +1,25 @@
import * as React from 'react';
import React, { forwardRef } from 'react';
import { observer } from 'mobx-react';
import { Sync } from 'Component';
import { I, S, U, J, keyboard } from 'Lib';
import { I, S, U, keyboard } from 'Lib';
interface State {
templatesCnt: number;
};
const HeaderMainChat = observer(class HeaderMainChat extends React.Component<I.HeaderComponent, State> {
state = {
templatesCnt: 0
};
constructor (props: I.HeaderComponent) {
super(props);
this.onSync = this.onSync.bind(this);
this.onOpen = this.onOpen.bind(this);
};
render () {
const { rootId, renderLeftIcons } = this.props;
return (
<React.Fragment>
<div className="side left">
{renderLeftIcons(this.onOpen)}
<Sync id="button-header-sync" onClick={this.onSync} />
</div>
<div className="side center" />
<div className="side right" />
</React.Fragment>
);
};
onOpen () {
const { rootId } = this.props;
const HeaderMainChat = observer(forwardRef<{}, I.HeaderComponent>((props, ref) => {
const { rootId, renderLeftIcons } = props;
const onOpen = () => {
const object = S.Detail.get(rootId, rootId, []);
keyboard.disableClose(true);
S.Popup.closeAll(null, () => U.Object.openRoute(object));
};
onSync () {
const { rootId, menuOpen } = this.props;
return (
<>
<div className="side left">{renderLeftIcons(onOpen)}</div>
<div className="side center" />
<div className="side right" />
</>
);
menuOpen('syncStatus', '#button-header-sync', {
subIds: [ 'syncStatusInfo' ],
data: {
rootId,
}
});
};
});
}));
export default HeaderMainChat;

View file

@ -1,17 +1,17 @@
import * as React from 'react';
import React, { FC } from 'react';
import { I } from 'Lib';
class HeaderMainEmpty extends React.Component<I.HeaderComponent> {
const HeaderMainEmpty: FC<I.HeaderComponent> = (props) => {
const { renderLeftIcons } = props;
render () {
return (
<React.Fragment>
<div className="side left">{this.props.renderLeftIcons()}</div>
<div className="side center" />
<div className="side right" />
</React.Fragment>
);
};
return (
<>
<div className="side left">{renderLeftIcons()}</div>
<div className="side center" />
<div className="side right" />
</>
);
};

View file

@ -1,48 +1,25 @@
import * as React from 'react';
import React, { forwardRef, useRef, useEffect, useImperativeHandle } from 'react';
import { Icon } from 'Component';
import { I, S, U, J, translate } from 'Lib';
class HeaderMainGraph extends React.Component<I.HeaderComponent> {
interface HeaderComponentRefProps {
setRootId: (id: string) => void;
};
refFilter: any = null;
rootId = '';
const HeaderMainGraph = forwardRef<HeaderComponentRefProps, I.HeaderComponent>((props, ref) => {
constructor (props: I.HeaderComponent) {
super(props);
this.onSearch = this.onSearch.bind(this);
this.onFilter = this.onFilter.bind(this);
this.onSettings = this.onSettings.bind(this);
};
const { renderLeftIcons, renderTabs, menuOpen, rootId } = props;
const rootIdRef = useRef('');
render () {
const { renderLeftIcons, renderTabs } = this.props;
const onSearch = () => {
const rootId = rootIdRef.current;
return (
<React.Fragment>
<div className="side left">{renderLeftIcons()}</div>
<div className="side center">{renderTabs()}</div>
<div className="side right">
<Icon id="button-header-search" className="btn-search withBackground" tooltip={translate('headerGraphTooltipSearch')} onClick={this.onSearch} />
<Icon id="button-header-filter" className="btn-filter withBackground dn" tooltip={translate('headerGraphTooltipFilters')} onClick={this.onFilter} />
<Icon id="button-header-settings" className="btn-settings withBackground" tooltip={translate('headerGraphTooltipSettings')} onClick={this.onSettings} />
</div>
</React.Fragment>
);
};
componentDidMount(): void {
this.setRootId(this.props.rootId);
};
onSearch () {
this.props.menuOpen('searchObject', '#button-header-search', {
menuOpen('searchObject', '#button-header-search', {
horizontal: I.MenuDirection.Right,
data: {
rootId: this.rootId,
blockId: this.rootId,
blockIds: [ this.rootId ],
rootId: rootId,
blockId: rootId,
blockIds: [ rootId ],
filters: U.Data.graphFilters(),
filter: S.Common.getGraph(J.Constant.graphId.global).filter,
canAdd: true,
@ -56,11 +33,11 @@ class HeaderMainGraph extends React.Component<I.HeaderComponent> {
});
};
onFilter () {
const onFilter = () => {
};
onSettings () {
this.props.menuOpen('graphSettings', '#button-header-settings', {
const onSettings = () => {
menuOpen('graphSettings', '#button-header-settings', {
horizontal: I.MenuDirection.Right,
data: {
allowLocal: true,
@ -69,10 +46,27 @@ class HeaderMainGraph extends React.Component<I.HeaderComponent> {
});
};
setRootId (id: string) {
this.rootId = id;
};
useImperativeHandle(ref, () => ({
setRootId: (id: string) => rootIdRef.current = id,
}));
};
useEffect(() => {
rootIdRef.current = rootId;
}, []);
return (
<>
<div className="side left">{renderLeftIcons()}</div>
<div className="side center">{renderTabs()}</div>
<div className="side right">
<Icon id="button-header-search" className="btn-search withBackground" tooltip={translate('headerGraphTooltipSearch')} onClick={onSearch} />
<Icon id="button-header-filter" className="btn-filter withBackground dn" tooltip={translate('headerGraphTooltipFilters')} onClick={onFilter} />
<Icon id="button-header-settings" className="btn-settings withBackground" tooltip={translate('headerGraphTooltipSettings')} onClick={onSettings} />
</div>
</>
);
});
export default HeaderMainGraph;

View file

@ -1,20 +1,18 @@
import * as React from 'react';
import React, { forwardRef } from 'react';
import { I } from 'Lib';
class HeaderMainNavigation extends React.Component<I.HeaderComponent> {
const HeaderMainNavigation = forwardRef<{}, I.HeaderComponent>((props, ref) => {
const { renderLeftIcons, renderTabs } = props;
render () {
const { renderLeftIcons, renderTabs } = this.props;
return (
<>
<div className="side left">{renderLeftIcons()}</div>
<div className="side center">{renderTabs()}</div>
<div className="side right" />
</>
);
return (
<React.Fragment>
<div className="side left">{renderLeftIcons()}</div>
<div className="side center">{renderTabs()}</div>
<div className="side right" />
</React.Fragment>
);
};
};
});
export default HeaderMainNavigation;

View file

@ -1,149 +1,75 @@
import * as React from 'react';
import React, { forwardRef, useState, useEffect, useImperativeHandle } from 'react';
import { observer } from 'mobx-react';
import { Icon, IconObject, Sync, ObjectName, Label } from 'Component';
import { I, S, U, J, keyboard, translate, sidebar } from 'Lib';
import { Icon, IconObject, ObjectName, Label } from 'Component';
import { I, S, U, J, keyboard, translate } from 'Lib';
import HeaderBanner from 'Component/page/elements/head/banner';
interface State {
templatesCnt: number;
};
const HeaderMainObject = observer(forwardRef<{}, I.HeaderComponent>((props, ref) => {
const HeaderMainObject = observer(class HeaderMainObject extends React.Component<I.HeaderComponent, State> {
const { rootId, match, isPopup, onSearch, onTooltipShow, onTooltipHide, renderLeftIcons, onRelation, menuOpen } = props;
const [ templatesCnt, setTemplateCnt ] = useState(0);
const [ dummy, setDummy ] = useState(0);
const root = S.Block.getLeaf(rootId, rootId);
const object = S.Detail.get(rootId, rootId, J.Relation.template);
const isLocked = root ? root.isLocked() : false;
const isTypeOrRelation = U.Object.isTypeOrRelationLayout(object.layout);
const isDate = U.Object.isDateLayout(object.layout);
const showRelations = !isTypeOrRelation && !isDate;
const showMenu = !isTypeOrRelation;
const cmd = keyboard.cmdSymbol();
const allowedTemplateSelect = (object.internalFlags || []).includes(I.ObjectFlag.SelectTemplate);
const bannerProps: any = {};
state = {
templatesCnt: 0
let center = null;
let banner = I.BannerType.None;
let locked = '';
if (object.isArchived && U.Space.canMyParticipantWrite()) {
banner = I.BannerType.IsArchived;
} else
if (U.Object.isTemplate(object.type)) {
banner = I.BannerType.IsTemplate;
} else
if (allowedTemplateSelect && templatesCnt) {
banner = I.BannerType.TemplateSelect;
bannerProps.count = templatesCnt + 1;
};
constructor (props: I.HeaderComponent) {
super(props);
this.onRelation = this.onRelation.bind(this);
this.onMore = this.onMore.bind(this);
this.onSync = this.onSync.bind(this);
this.onOpen = this.onOpen.bind(this);
this.updateTemplatesCnt = this.updateTemplatesCnt.bind(this);
if (isLocked) {
locked = translate('headerObjectLocked');
} else
if (U.Object.isTypeOrRelationLayout(object.layout) && !S.Block.isAllowed(object.restrictions, [ I.RestrictionObject.Delete ])) {
locked = translate('commonSystem');
};
render () {
const { rootId, onSearch, onTooltipShow, onTooltipHide, isPopup, renderLeftIcons } = this.props;
const { templatesCnt } = this.state;
const root = S.Block.getLeaf(rootId, rootId);
if (!root) {
return null;
};
const object = S.Detail.get(rootId, rootId, J.Relation.template);
const isLocked = root ? root.isLocked() : false;
const isTypeOrRelation = U.Object.isTypeOrRelationLayout(object.layout);
const isDate = U.Object.isDateLayout(object.layout);
const showRelations = !isTypeOrRelation && !isDate;
const showMenu = true; //!isTypeOrRelation;
const canSync = showMenu && !object.templateIsBundled && !U.Object.isParticipantLayout(object.layout);
const cmd = keyboard.cmdSymbol();
const allowedTemplateSelect = (object.internalFlags || []).includes(I.ObjectFlag.SelectTemplate);
const bannerProps: any = {};
let center = null;
let banner = I.BannerType.None;
let locked = '';
if (object.isArchived && U.Space.canMyParticipantWrite()) {
banner = I.BannerType.IsArchived;
} else
if (U.Object.isTemplate(object.type)) {
banner = I.BannerType.IsTemplate;
} else
if (allowedTemplateSelect && templatesCnt) {
banner = I.BannerType.TemplateSelect;
bannerProps.count = templatesCnt + 1;
};
if (isLocked) {
locked = translate('headerObjectLocked');
} else
if (U.Object.isTypeOrRelationLayout(object.layout) && !S.Block.isAllowed(object.restrictions, [ I.RestrictionObject.Delete ])) {
locked = translate('commonSystem');
};
if (banner == I.BannerType.None) {
center = (
<div
id="path"
className="path"
onClick={onSearch}
onMouseOver={e => onTooltipShow(e, translate('headerTooltipPath'))}
onMouseOut={onTooltipHide}
>
<div className="inner">
<IconObject object={object} size={18} />
<ObjectName object={object} />
{locked ? <Label text={locked} className="lock" /> : ''}
</div>
if (banner == I.BannerType.None) {
center = (
<div
id="path"
className="path"
onClick={onSearch}
onMouseOver={e => onTooltipShow(e, translate('headerTooltipPath'))}
onMouseOut={onTooltipHide}
>
<div className="inner">
<IconObject object={object} size={18} />
<ObjectName object={object} />
{locked ? <Label text={locked} className="lock" /> : ''}
</div>
);
} else {
center = <HeaderBanner type={banner} object={object} isPopup={isPopup} {...bannerProps} />;
};
return (
<React.Fragment>
<div className="side left">
{renderLeftIcons(this.onOpen)}
{canSync ? <Sync id="button-header-sync" onClick={this.onSync} /> : ''}
</div>
<div className="side center">
{center}
</div>
<div className="side right">
{showRelations ? (
<Icon
id="button-header-relation"
tooltip={translate('commonRelations')}
tooltipCaption={`${cmd} + Shift + R`}
className="relation withBackground"
onClick={this.onRelation}
/>
) : ''}
{showMenu ? (
<Icon
id="button-header-more"
tooltip={translate('commonMenu')}
className="more withBackground"
onClick={this.onMore}
/>
) : ''}
</div>
</React.Fragment>
</div>
);
} else {
center = <HeaderBanner type={banner} object={object} isPopup={isPopup} {...bannerProps} />;
};
componentDidMount () {
this.init();
};
componentDidUpdate () {
this.init();
};
init () {
this.updateTemplatesCnt();
};
onOpen () {
const { rootId } = this.props;
const onOpen = () => {
const object = S.Detail.get(rootId, rootId, []);
keyboard.disableClose(true);
S.Popup.closeAll(null, () => U.Object.openRoute(object));
};
onMore () {
const { isPopup, match, rootId, menuOpen } = this.props;
const onMore = () => {
menuOpen('object', '#button-header-more', {
horizontal: I.MenuDirection.Right,
subIds: J.Menu.object,
@ -157,29 +83,13 @@ const HeaderMainObject = observer(class HeaderMainObject extends React.Component
});
};
onSync () {
const { rootId, menuOpen } = this.props;
menuOpen('syncStatus', '#button-header-sync', {
subIds: [ 'syncStatusInfo' ],
data: {
rootId,
}
});
};
onRelation () {
const { rootId } = this.props;
const onRelationHandler = () => {
const object = S.Detail.get(rootId, rootId, [ 'isArchived' ]);
sidebar.rightPanelToggle(!S.Common.showSidebarRight, 'object/relation', { rootId });
//this.props.onRelation({}, { readonly: object.isArchived });
onRelation({}, { readonly: object.isArchived });
};
updateTemplatesCnt () {
const { rootId } = this.props;
const { templatesCnt } = this.state;
const updateTemplatesCnt = () => {
const object = S.Detail.get(rootId, rootId, [ 'internalFlags' ]);
const allowedTemplateSelect = (object.internalFlags || []).includes(I.ObjectFlag.SelectTemplate);
@ -193,11 +103,52 @@ const HeaderMainObject = observer(class HeaderMainObject extends React.Component
};
if (message.records.length != templatesCnt) {
this.setState({ templatesCnt: message.records.length });
setTemplateCnt(message.records.length);
};
});
};
});
useEffect(() => {
updateTemplatesCnt();
});
export default HeaderMainObject;
useImperativeHandle(ref, () => ({
forceUpdate: () => setDummy(dummy + 1),
}));
return (
<>
<div className="side left">
{renderLeftIcons(onOpen)}
</div>
<div className="side center">
{center}
</div>
<div className="side right">
{showRelations ? (
<Icon
id="button-header-relation"
tooltip={translate('commonRelations')}
tooltipCaption={`${cmd} + Shift + R`}
className="relation withBackground"
onClick={onRelationHandler}
/>
) : ''}
{showMenu ? (
<Icon
id="button-header-more"
tooltip={translate('commonMenu')}
className="more withBackground"
onClick={onMore}
/>
) : ''}
</div>
</>
);
}));
export default HeaderMainObject;

View file

@ -176,7 +176,7 @@ class MenuObject extends React.Component<I.Menu> {
const allowedSearch = !isFilePreview && !isInSetLayouts;
const allowedHistory = !object.isArchived && !isInFileOrSystemLayouts && !isParticipant && !isDate && !object.templateIsBundled;
const allowedFav = canWrite && !object.isArchived && !object.templateIsBundled;
const allowedLock = canWrite && !object.isArchived && S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Details ]);
const allowedLock = canWrite && !object.isArchived && S.Block.checkFlags(rootId, rootId, [ I.RestrictionObject.Details ]) && !isInFileOrSystemLayouts;
const allowedLinkTo = canWrite && !object.isArchived;
const allowedAddCollection = canWrite && !object.isArchived;
const allowedPageLink = !object.isArchived;

View file

@ -283,6 +283,10 @@ const PageMainDate = observer(class PageMainDate extends React.Component<I.PageC
C.RelationListWithValue(space, rootId, (message: any) => {
const relations = (message.relations || []).map(it => S.Record.getRelationByKey(it.relationKey)).filter(it => {
if (!it) {
return false;
};
if ([ RELATION_KEY_MENTION ].includes(it.relationKey)) {
return true;
};

View file

@ -166,7 +166,7 @@ const PageMainGraph = observer(class PageMainGraph extends React.Component<I.Pag
initRootId (id: string) {
this.rootId = id;
this.refHeader.refChild.setRootId(id);
this.refHeader.setRootId(id);
};
getRootId () {

View file

@ -457,7 +457,7 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
setVersion (version: I.HistoryVersion) {
this.refSideLeft?.forceUpdate();
this.refSideLeft?.refHeader?.refChild.setVersion(version);
this.refSideLeft?.refHeader?.setVersion(version);
this.refSideLeft?.refHead?.forceUpdate();
$(window).trigger('updateDataviewData');

View file

@ -1,40 +1,31 @@
import * as React from 'react';
import React, { FC } from 'react';
import { Title, Icon, Label, Button } from 'Component';
import { I, U, translate } from 'Lib';
class PopupAbout extends React.Component<I.Popup> {
const PopupAbout: FC<I.Popup> = () => {
constructor (props: I.Popup) {
super(props);
const version = U.Common.getElectron().version.app;
this.onVersionCopy = this.onVersionCopy.bind(this);
};
return (
<>
<div className="iconWrapper">
<Icon />
</div>
<Title text={translate('popupAboutTitle')} />
<Label text={translate('popupAboutDescription')} />
render () {
return (
<React.Fragment>
<div className="iconWrapper">
<Icon />
</div>
<Title text={translate('popupAboutTitle')} />
<Label text={translate('popupAboutDescription')} />
<div className="version">
{U.Common.sprintf(translate('popupAboutVersion'), this.getVersion())}
<Button onClick={this.onVersionCopy} text={translate('commonCopy')} className="c28" color="blank" />
</div>
<div className="copyright">{translate('popupAboutCopyright')}</div>
</React.Fragment>
);
};
getVersion () {
return U.Common.getElectron().version.app;
};
onVersionCopy () {
U.Common.copyToast(translate('commonVersion'), this.getVersion());
};
<div className="version">
{U.Common.sprintf(translate('popupAboutVersion'), version)}
<Button
onClick={() => U.Common.copyToast(translate('commonVersion'), version)}
text={translate('commonCopy')}
className="c28"
color="blank"
/>
</div>
<div className="copyright">{translate('popupAboutCopyright')}</div>
</>
);
};

View file

@ -1,44 +1,42 @@
import * as React from 'react';
import React, { FC } from 'react';
import { Title, Label, Button, IconObject } from 'Component';
import { I, translate } from 'Lib';
class PopupPhrase extends React.Component<I.Popup> {
const PopupPhrase: FC<I.Popup> = (props) => {
render () {
return (
<div>
<Title text={translate('popupPhraseTitle1')} />
<div className="rows">
<div className="row">
<IconObject size={40} iconSize={40} object={{ iconEmoji: ':game_die:' }} />
<Label text={translate('popupPhraseLabel1')} />
</div>
<div className="row">
<IconObject size={40} iconSize={40} object={{ iconEmoji: ':old_key:' }} />
<Label text={translate('popupPhraseLabel2')} />
</div>
<div className="row">
<IconObject size={40} iconSize={40} object={{ iconEmoji: ':point_up:' }} />
<Label text={translate('popupPhraseLabel3')} />
</div>
return (
<>
<Title text={translate('popupPhraseTitle1')} />
<div className="rows">
<div className="row">
<IconObject size={40} iconSize={40} object={{ iconEmoji: ':game_die:' }} />
<Label text={translate('popupPhraseLabel1')} />
</div>
<Title className="c2" text={translate('popupPhraseTitle2')} />
<div className="columns">
<div className="column">
<li>{translate('popupPhraseLabel4')}</li>
</div>
<div className="column">
<li>{translate('popupPhraseLabel5')}</li>
</div>
<div className="row">
<IconObject size={40} iconSize={40} object={{ iconEmoji: ':old_key:' }} />
<Label text={translate('popupPhraseLabel2')} />
</div>
<div className="buttons">
<Button text={translate('commonOkay')} onClick={() => this.props.close()} />
<div className="row">
<IconObject size={40} iconSize={40} object={{ iconEmoji: ':point_up:' }} />
<Label text={translate('popupPhraseLabel3')} />
</div>
</div>
);
};
<Title className="c2" text={translate('popupPhraseTitle2')} />
<div className="columns">
<div className="column">
<li>{translate('popupPhraseLabel4')}</li>
</div>
<div className="column">
<li>{translate('popupPhraseLabel5')}</li>
</div>
</div>
<div className="buttons">
<Button text={translate('commonOkay')} onClick={() => props.close()} />
</div>
</>
);
};

View file

@ -1,35 +1,26 @@
import * as React from 'react';
import React, { FC } from 'react';
import { Title, Label, Button } from 'Component';
import { I, U, J, translate, analytics } from 'Lib';
class PopupShare extends React.Component<I.Popup> {
const PopupShare: FC<I.Popup> = () => {
constructor (props: I.Popup) {
super(props);
this.onClick = this.onClick.bind(this);
};
render () {
return (
<div>
<Title text={translate('popupShareTitle')} />
<Label text={translate('popupShareLabel')} />
<div className="section">
<Label text={U.Common.sprintf(translate('popupShareLinkText'), J.Url.share, J.Url.share)} />
</div>
<Button text={translate('commonCopyLink')} onClick={this.onClick} />
</div>
);
};
onClick () {
const onClick = () => {
U.Common.copyToast(translate('commonLink'), J.Url.share);
analytics.event('ClickShareAppCopyLink');
};
return (
<>
<Title text={translate('popupShareTitle')} />
<Label text={translate('popupShareLabel')} />
<div className="section">
<Label text={U.Common.sprintf(translate('popupShareLinkText'), J.Url.share, J.Url.share)} />
</div>
<Button text={translate('commonCopyLink')} onClick={onClick} />
</>
);
};
export default PopupShare;
export default PopupShare;