1
0
Fork 0
mirror of https://github.com/anyproto/anytype-ts.git synced 2025-06-08 05:57:02 +09:00

Merge branch 'main' into nightly-ci-test-beta

This commit is contained in:
Grigory Efimov 2025-02-28 11:30:49 -03:00
commit 9f7a07730a
No known key found for this signature in database
GPG key ID: 0A88C34DFA7FD939
35 changed files with 4441 additions and 3173 deletions

View file

@ -5,7 +5,7 @@ npx lint-staged --concurrent false
# npm run typecheck
# Checking for secrets
# gitleaks protect --verbose --redact --staged
gitleaks protect --verbose --redact --staged
# Checking dependencies' licenses
npx license-checker --production --json --out licenses.json

View file

@ -76,7 +76,7 @@ class Server {
};
this.lastErrors.push(chunk);
Util.log('warn', chunk);
console.log(chunk);
});
this.cp.on('exit', () => {

View file

@ -112,13 +112,7 @@ class UpdateManager {
};
checkUpdate (auto) {
if (!this.isAllowed()) {
return;
};
Util.log('info', 'isUpdating: ' + this.isUpdating);
if (this.isUpdating) {
if (!this.isAllowed() || this.isUpdating) {
return;
};

6644
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.8841 10.0056L15.3039 8.58581C16.3779 7.51187 16.3779 5.77067 15.3039 4.69672C14.23 3.62278 12.4888 3.62278 11.4148 4.69672L9.29351 6.81804C8.21957 7.89199 8.21957 9.63319 9.29351 10.7071C9.64823 11.0618 10.0757 11.2994 10.528 11.4198C10.492 11.8129 10.3236 12.1961 10.0227 12.497L9.76827 12.7514C9.2081 12.5454 8.68261 12.2176 8.23285 11.7678C6.57312 10.1081 6.57312 7.41711 8.23285 5.75738L10.3542 3.63606C12.0139 1.97633 14.7049 1.97633 16.3646 3.63606C18.0243 5.29579 18.0243 7.98674 16.3646 9.64647L14.2433 11.7678C14.1587 11.8523 14.0715 11.9326 13.9819 12.0085C14.0774 11.3424 14.0448 10.6615 13.8841 10.0056Z" fill="#252525"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.11783 9.99439L4.69803 11.4142C3.62409 12.4881 3.62409 14.2293 4.69803 15.3033C5.77198 16.3772 7.51318 16.3772 8.58712 15.3033L10.7084 13.182C11.7824 12.108 11.7824 10.3668 10.7084 9.29287C10.3537 8.93815 9.92621 8.70059 9.47399 8.5802C9.50992 8.18714 9.67833 7.80391 9.97924 7.50301L10.2337 7.24856C10.7939 7.45457 11.3193 7.78245 11.7691 8.23221C13.4288 9.89194 13.4288 12.5829 11.7691 14.2426L9.64778 16.3639C7.98805 18.0237 5.2971 18.0237 3.63737 16.3639C1.97765 14.7042 1.97765 12.0133 3.63737 10.3535L5.7587 8.23221C5.84323 8.14767 5.93044 8.06744 6.02005 7.99152C5.92459 8.65758 5.95718 9.33846 6.11783 9.99439Z" fill="#252525"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.8841 10.0056L15.3039 8.58581C16.3779 7.51187 16.3779 5.77067 15.3039 4.69672C14.23 3.62278 12.4888 3.62278 11.4148 4.69672L9.29351 6.81804C8.21957 7.89199 8.21957 9.63319 9.29351 10.7071C9.64823 11.0618 10.0757 11.2994 10.528 11.4198C10.492 11.8129 10.3236 12.1961 10.0227 12.497L9.76827 12.7514C9.2081 12.5454 8.68261 12.2176 8.23285 11.7678C6.57312 10.1081 6.57312 7.41711 8.23285 5.75738L10.3542 3.63606C12.0139 1.97633 14.7049 1.97633 16.3646 3.63606C18.0243 5.29579 18.0243 7.98674 16.3646 9.64647L14.2433 11.7678C14.1587 11.8523 14.0715 11.9326 13.9819 12.0085C14.0774 11.3424 14.0448 10.6615 13.8841 10.0056Z" fill="#f8f8f8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.11783 9.99439L4.69803 11.4142C3.62409 12.4881 3.62409 14.2293 4.69803 15.3033C5.77198 16.3772 7.51318 16.3772 8.58712 15.3033L10.7084 13.182C11.7824 12.108 11.7824 10.3668 10.7084 9.29287C10.3537 8.93815 9.92621 8.70059 9.47399 8.5802C9.50992 8.18714 9.67833 7.80391 9.97924 7.50301L10.2337 7.24856C10.7939 7.45457 11.3193 7.78245 11.7691 8.23221C13.4288 9.89194 13.4288 12.5829 11.7691 14.2426L9.64778 16.3639C7.98805 18.0237 5.2971 18.0237 3.63737 16.3639C1.97765 14.7042 1.97765 12.0133 3.63737 10.3535L5.7587 8.23221C5.84323 8.14767 5.93044 8.06744 6.02005 7.99152C5.92459 8.65758 5.95718 9.33846 6.11783 9.99439Z" fill="#f8f8f8"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -132,6 +132,7 @@
"commonNewSpace": "New Space",
"commonSelectObject": "Select Object",
"commonCopyLink": "Copy Link",
"commonCopyDeeplink": "Copy Deeplink",
"commonSidebar": "Sidebar",
"commonLanguage": "Language",
"commonSpelling": "Spelling",

View file

@ -68,7 +68,7 @@
}
}
.block.blockMedia.isAudio > .wrapContent { border: 1px solid var(--color-shape-secondary); }
.block.blockMedia.isAudio.withContent > .wrapContent { border: 1px solid var(--color-shape-secondary); }
.block.blockMedia.isAudio > .wrapContent > .selectionTarget > .dropTarget > .focusable > .wrap { width: 100%; padding: 12px 12px 7px 14px; }
.block.blockMedia.isReadonly {
@ -98,5 +98,5 @@
.block.blockMedia.isPdf.withContent > .wrapContent > .selectionTarget.isSelectionSelected::after { border-radius: 0px; }
.block.blockMedia.isImage.withContent > .wrapContent > .selectionTarget.isSelectionSelected::after { border-radius: 0px; }
.block.blockMedia.isVideo.withContent > .wrapContent > .selectionTarget.isSelectionSelected::after { border-radius: 0px; }
.block.blockMedia.isAudio.withContent > .wrapContent > .selectionTarget.isSelectionSelected::after { border-radius: 8px; }
.block.blockMedia.isAudio.withContent > .wrapContent > .selectionTarget.isSelectionSelected::after { border-radius: 0px; }
}

View file

@ -26,36 +26,29 @@
.tabs, .sides.sidesFilter { padding: 0px 16px; }
.tabs { position: relative; }
.tabs { position: relative; font-weight: 500; color: var(--color-control-active); height: 22px; }
.tabs {
.scrollWrap { overflow-y: hidden; overflow-x: auto; padding: 0px 0px 3px 0px; }
.scrollWrap::-webkit-scrollbar { display: none; }
.scroll { display: flex; align-items: center; gap: 0px 12px; font-weight: 500; color: var(--color-control-active); }
.tab { white-space: nowrap; flex-shrink: 0; transition: $transitionAllCommon; }
.tab.active, .tab:hover { color: var(--color-text-primary); }
.controls { position: absolute; top: -4px; left: 0px; width: 100%; display: flex; justify-content: space-between; }
.controls {
.side { width: 60px; position: relative; }
.side.hide {
.icon.arrow, .gradient { display: none; }
.swiper { overflow: visible; position: absolute; left: 0px; top: 0px; width: 100%; padding: 0px 16px; }
.swiper-slide { width: auto; }
.swiper-button-prev, .swiper-button-next { width: 60px; height: 28px; position: absolute; top: -3px; z-index: 1; }
.swiper-button-prev, .swiper-button-next {
&::before {
content: ''; width: 24px; height: 24px; display: block; position: absolute; left: 12px; top: 2px; z-index: 1;
background-image: url('~img/arrow/sidebarObjectTab.svg'); background-size: 20px; background-repeat: no-repeat;
border-radius: 6px; background-position: center;
}
.icon.arrow { background-image: url('~img/arrow/sidebarObjectTab.svg'); position: absolute; z-index: 2; top: 1px; }
.gradient { position: absolute; width: 100%; height: 28px; z-index: 1; top: 0px; pointer-events: none; }
.side.left {
.icon.arrow { left: 16px; transform: rotateZ(180deg); }
.gradient { left: 0px; background-image: linear-gradient(270deg, rgba(255,255,255,0) 0px, var(--color-bg-primary) 16px, var(--color-bg-primary) 100%); }
}
.side.right {
.icon.arrow { right: 16px; }
.gradient { right: 0px; background-image: linear-gradient(90deg, rgba(255,255,255,0) 0px, var(--color-bg-primary) 16px, var(--color-bg-primary) 100%); }
&::after {
content: ''; width: 100%; height: 100%; display: block; position: absolute; left: 0px; top: 0px;
background-image: linear-gradient(90deg, rgba(255,255,255,0) 0px, var(--color-bg-primary) 16px, var(--color-bg-primary) 100%);
}
&:hover::before { background-color: var(--color-shape-highlight-medium); }
}
.swiper-button-prev { left: -16px; transform: rotateZ(180deg); }
.swiper-button-next { right: -16px; }
.swiper-button-disabled { display: none; }
}
.filter { padding: 0px 4px; border-radius: 6px; border: 1px solid var(--color-shape-secondary); }

View file

@ -37,6 +37,10 @@
border-radius: 50%; opacity: 0; transition: opacity 0.2s $easeInQuint; opacity: 0;
}
.item.isButton {
.iconWrap { background-color: var(--color-shape-highlight-dark); }
}
.item:hover, .item.hover { padding: 0px; }
.item.isActive::after { opacity: 1; }

View file

@ -98,6 +98,17 @@ html.printMedia {
.block.blockText.textCode > .wrapContent > .selectionTarget > .dropTarget #value { white-space: pre-wrap; overflow-x: visible; }
.block.blockMedia.isAudio > .wrapContent { box-shadow: 0px 0px; }
.block.blockMedia.isAudio {
.mediaAudio {
.controlsWrapper {
.controls {
.input-drag-horizontal {
.back { width: 100% !important; }
}
}
}
}
}
.block.blockDataview.isInline {
.content {

View file

@ -61,6 +61,7 @@
.item:hover::before { background: var(--color-shape-highlight-medium); }
.icon { flex-shrink: 0; }
.icon.link { background-image: url('~img/icon/widget/button/link.svg'); }
.icon.space { background-image: url('~img/icon/widget/button/member.svg'); }
.icon.export { background-image: url('~img/icon/widget/button/export.svg'); }
.icon.arrow { background-size: 6px 10px; background-image: url('~img/icon/popup/settings/forward.svg'); right: 12px; }

View file

@ -308,6 +308,7 @@
.input.isReadonly { background: rgba(255, 255, 255, 0.03); }
.outer {
.icon.link { background-image: url('#{$themePath}/icon/widget/button/link.svg'); }
.icon.space { background-image: url('#{$themePath}/icon/widget/button/member.svg'); }
.icon.export { background-image: url('#{$themePath}/icon/widget/button/export.svg'); }
}

View file

@ -88,7 +88,8 @@ const BlockBookmark = observer(class BlockBookmark extends React.Component<I.Blo
};
element = (
<div
<a
href={url}
className={cni.join(' ')}
onClick={this.onClick}
onMouseDown={this.onMouseDown}
@ -107,7 +108,7 @@ const BlockBookmark = observer(class BlockBookmark extends React.Component<I.Blo
<div className="side right">
{picture ? <img src={S.Common.imageUrl(picture, 500)} className="img" /> : ''}
</div>
</div>
</a>
);
break;
};
@ -196,6 +197,8 @@ const BlockBookmark = observer(class BlockBookmark extends React.Component<I.Blo
return;
};
e.preventDefault();
const selection = S.Common.getRef('selectionProvider');
const ids = selection?.get(I.SelectType.Block) || [];

View file

@ -27,6 +27,7 @@ const BlockTable = observer(class BlockTable extends React.Component<I.BlockComp
rowId = '';
cellId = '';
data: any = {};
frameResize = 0;
constructor (props: I.BlockComponent) {
super(props);
@ -165,6 +166,7 @@ const BlockTable = observer(class BlockTable extends React.Component<I.BlockComp
unbind () {
const { block } = this.props;
$(window).off(`resize.${block.id}`);
$(this.node).off('resizeInit resizeMove');
};
rebind () {
@ -173,6 +175,7 @@ const BlockTable = observer(class BlockTable extends React.Component<I.BlockComp
this.unbind();
win.on(`resize.${block.id}`, () => raf(() => this.resize()));
$(this.node).on('resizeInit resizeMove', e => this.resize());
};
getData () {
@ -1530,35 +1533,41 @@ const BlockTable = observer(class BlockTable extends React.Component<I.BlockComp
const row = node.find(`#row-${rows[0].id}`);
const obj = $(`#block-${block.id}`);
let width = J.Size.blockMenu + 10;
let maxWidth = 0;
let wrapperWidth = 0;
String(row.css('grid-template-columns') || '').split(' ').forEach(it => width += parseInt(it));
obj.css({ width: 'auto' });
if (parent.isPage() || parent.isLayoutDiv()) {
const container = U.Common.getPageContainer(isPopup);
maxWidth = container.width() - PADDING;
wrapperWidth = getWrapperWidth() + J.Size.blockMenu;
wrap.toggleClass('withScroll', width > maxWidth);
width = Math.max(wrapperWidth, Math.min(maxWidth, width));
obj.css({
width: (width >= wrapperWidth) ? width : 'auto',
marginLeft: (width >= wrapperWidth) ? Math.min(0, (wrapperWidth - width) / 2) : '',
});
} else {
const parentObj = $(`#block-${parent.id}`);
if (parentObj.length) {
maxWidth = parentObj.width() - J.Size.blockMenu;
};
wrap.toggleClass('withScroll', width > maxWidth);
if (this.frameResize) {
raf.cancel(this.frameResize);
};
this.frameResize = raf(() => {
let width = J.Size.blockMenu + 10;
let maxWidth = 0;
let wrapperWidth = 0;
String(row.css('grid-template-columns') || '').split(' ').forEach(it => width += parseInt(it));
obj.css({ width: 'auto', marginLeft: 0 });
if (parent.isPage() || parent.isLayoutDiv()) {
const container = U.Common.getPageContainer(isPopup);
maxWidth = container.width() - PADDING;
wrapperWidth = getWrapperWidth() + J.Size.blockMenu;
wrap.toggleClass('withScroll', width > maxWidth);
width = Math.max(wrapperWidth, Math.min(maxWidth, width));
obj.css({
width: (width >= wrapperWidth) ? width : 'auto',
marginLeft: (width >= wrapperWidth) ? Math.min(0, (wrapperWidth - width) / 2) : '',
});
} else {
const parentObj = $(`#block-${parent.id}`);
if (parentObj.length) {
maxWidth = parentObj.width() - J.Size.blockMenu;
};
wrap.toggleClass('withScroll', width > maxWidth);
};
});
};
});

View file

@ -2319,7 +2319,6 @@ const EditorPage = observer(class EditorPage extends React.Component<Props, Stat
const cover = node.find('.block.blockCover');
const pageContainer = U.Common.getPageContainer(isPopup);
const header = pageContainer.find('#header');
const root = S.Block.getLeaf(rootId, rootId);
const scrollContainer = U.Common.getScrollContainer(isPopup);
const hh = isPopup ? header.height() : J.Size.header;
@ -2393,6 +2392,8 @@ const EditorPage = observer(class EditorPage extends React.Component<Props, Stat
this.refHeader.refDrag.setValue(v);
this.refHeader.setPercent(v);
};
$('.resizable').trigger('resizeInit');
};
getWidth (w: number) {

View file

@ -358,6 +358,7 @@ const MenuBlockLink = observer(class MenuBlockLink extends React.Component<I.Men
if (item.itemId == 'link') {
let url = filter;
if (item.isLocal && url && !url.match(/^file:/)) {
url = `file://${url}`;
};

View file

@ -34,7 +34,6 @@ const MenuBlockRelationEdit = observer(class MenuBlockRelationEdit extends React
const relation = this.getRelation();
const root = S.Block.getLeaf(rootId, rootId);
const isDate = this.format == I.RelationType.Date;
const isObject = this.format == I.RelationType.Object;
const isReadonly = this.isReadonly();
@ -59,8 +58,11 @@ const MenuBlockRelationEdit = observer(class MenuBlockRelationEdit extends React
canDuplicate = canDelete = false;
};
};
if (relation && Relation.isSystemWithoutUser(relation.relationKey)) {
canDelete = false;
if (relation) {
const allowedDelete = relation ? S.Block.isAllowed(relation.restrictions, [ I.RestrictionObject.Delete ]) : false;
canDelete = allowedDelete && Relation.isSystemWithoutUser(relation.relationKey);
};
switch (ref) {
@ -155,7 +157,7 @@ const MenuBlockRelationEdit = observer(class MenuBlockRelationEdit extends React
<div className="section">
<MenuItemVertical icon="expand" name={translate('commonOpenObject')} onClick={this.onOpen} onMouseEnter={this.menuClose} />
{canDuplicate ? <MenuItemVertical icon="copy" name={translate('commonDuplicate')} onClick={this.onCopy} onMouseEnter={this.menuClose} /> : ''}
{canDelete && unlinkText && !noUnlink ? <MenuItemVertical icon="unlink" name={unlinkText} onClick={this.onUnlink} onMouseEnter={this.menuClose} /> : ''}
{unlinkText && !noUnlink ? <MenuItemVertical icon="unlink" name={unlinkText} onClick={this.onUnlink} onMouseEnter={this.menuClose} /> : ''}
{canDelete ? <MenuItemVertical icon="remove" name={translate('commonDelete')} onClick={this.onRemove} onMouseEnter={this.menuClose} /> : ''}
</div>
) : ''}

View file

@ -1,206 +1,60 @@
import * as React from 'react';
import React, { forwardRef, useRef, useEffect, useImperativeHandle } from 'react';
import $ from 'jquery';
import { observer } from 'mobx-react';
import arrayMove from 'array-move';
import { AutoSizer, CellMeasurer, InfiniteLoader, List as VList, CellMeasurerCache } from 'react-virtualized';
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
import { DndContext, closestCenter, useSensors, useSensor, PointerSensor, KeyboardSensor } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy, sortableKeyboardCoordinates, arrayMove, useSortable } from '@dnd-kit/sortable';
import { restrictToVerticalAxis, restrictToFirstScrollableAncestor } from '@dnd-kit/modifiers';
import { CSS } from '@dnd-kit/utilities';
import { Icon, Switch, Cell } from 'Component';
import { I, C, S, J, Dataview, keyboard, translate } from 'Lib';
const HEIGHT = 28;
const LIMIT = 20;
const MenuGroupList = observer(class MenuGroupList extends React.Component<I.Menu> {
node: any = null;
n = -1;
top = 0;
cache: any = {};
refList: any = null;
const MenuGroupList = observer(forwardRef<I.MenuRef, I.Menu>((props, ref) => {
constructor (props: I.Menu) {
super(props);
this.onSortStart = this.onSortStart.bind(this);
this.onSortEnd = this.onSortEnd.bind(this);
this.onSwitch = this.onSwitch.bind(this);
this.onScroll = this.onScroll.bind(this);
const { param, getId, setActive, onKeyDown, position } = props;
const { data } = param;
const { readonly, rootId, blockId, getView } = data;
const view = getView();
const items = Dataview.getGroups(rootId, blockId, view.id, true);
const block = S.Block.getLeaf(rootId, blockId);
const allowedView = S.Block.checkFlags(rootId, blockId, [ I.RestrictionDataview.View ]);
const cache = useRef({});
const listRef = useRef(null);
const top = useRef(0);
const n = useRef(-1);
const sensors = useSensors(
useSensor(PointerSensor, { activationConstraint: { distance: 10 } }),
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
);
cache.current = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: HEIGHT,
keyMapper: i => (items[i] || {}).id,
});
const rebind = () => {
unbind();
$(window).on('keydown.menu', e => onKeyDownHandler(e));
window.setTimeout(() => setActive(), 15);
};
render () {
const { param, getId } = this.props;
const { data } = param;
const { readonly, rootId, blockId, getView } = data;
const items = this.getItems();
const view = getView();
const block = S.Block.getLeaf(rootId, blockId);
const allowedView = S.Block.checkFlags(rootId, blockId, [ I.RestrictionDataview.View ]);
const Handle = SortableHandle(() => (
<Icon className="dnd" />
));
const Item = SortableElement((item: any) => {
const canHide = allowedView;
const canEdit = !readonly && allowedView;
const subId = S.Record.getSubId(rootId, [ blockId, item.id ].join(':'));
const cn = [ 'item' ];
const head = {};
head[view.groupRelationKey] = item.value;
if (!canEdit) {
cn.push('isReadonly');
};
return (
<div
ref={node => this.node = node}
id={'item-' + item.id}
className={cn.join(' ')}
onMouseEnter={e => this.onMouseEnter(e, item)}
style={item.style}
>
{allowedView ? <Handle /> : ''}
<span className="clickable">
<Cell
id={'menu-group-' + item.id}
rootId={rootId}
subId={subId}
block={block}
relationKey={view.groupRelationKey}
viewType={I.ViewType.Board}
getRecord={() => head}
readonly={true}
arrayLimit={4}
withName={true}
placeholder={translate('commonUncategorized')}
/>
</span>
{canHide ? (
<Switch
value={!item.isHidden}
onChange={(e: any, v: boolean) => { this.onSwitch(e, item, v); }}
/>
) : ''}
</div>
);
});
const rowRenderer = (param: any) => {
const item: any = items[param.index];
return (
<CellMeasurer
key={param.key}
parent={param.parent}
cache={this.cache}
columnIndex={0}
rowIndex={param.index}
>
<Item key={item.id} {...item} index={param.index} style={param.style} />
</CellMeasurer>
);
};
const List = SortableContainer(() => (
<div className="items">
<InfiniteLoader
rowCount={items.length}
loadMoreRows={() => {}}
isRowLoaded={() => true}
threshold={LIMIT}
>
{({ onRowsRendered }) => (
<AutoSizer className="scrollArea">
{({ width, height }) => (
<VList
ref={ref => this.refList = ref}
width={width}
height={height}
deferredMeasurmentCache={this.cache}
rowCount={items.length}
rowHeight={HEIGHT}
rowRenderer={rowRenderer}
onRowsRendered={onRowsRendered}
overscanRowCount={LIMIT}
onScroll={this.onScroll}
scrollToAlignment="center"
/>
)}
</AutoSizer>
)}
</InfiniteLoader>
</div>
));
return (
<div className="wrap">
<List
axis="y"
lockAxis="y"
lockToContainerEdges={true}
transitionDuration={150}
distance={10}
onSortStart={this.onSortStart}
onSortEnd={this.onSortEnd}
useDragHandle={true}
helperClass="isDragging"
helperContainer={() => $(`#${getId()} .items`).get(0)}
/>
</div>
);
};
componentDidMount() {
const items = this.getItems();
this.rebind();
this.resize();
this.cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: HEIGHT,
keyMapper: i => (items[i] || {}).id,
});
};
componentDidUpdate () {
this.resize();
this.rebind();
this.props.setActive(null, true);
this.props.position();
if (this.refList && this.top) {
this.refList.scrollToPosition(this.top);
};
};
componentWillUnmount () {
this.unbind();
S.Menu.closeAll(J.Menu.cell);
};
rebind () {
this.unbind();
$(window).on('keydown.menu', e => this.onKeyDown(e));
window.setTimeout(() => this.props.setActive(), 15);
};
unbind () {
const unbind = () => {
$(window).off('keydown.menu');
};
onKeyDown (e: any) {
const onKeyDownHandler = (e: any) => {
const item = items[n.current];
let ret = false;
const items = this.getItems();
const item = items[this.n];
keyboard.shortcut('space', e, (pressed: string) => {
e.preventDefault();
this.onSwitch(e, item, !item.isVisible);
onSwitch(e, item, !item.isVisible);
ret = true;
});
@ -208,80 +62,215 @@ const MenuGroupList = observer(class MenuGroupList extends React.Component<I.Men
return;
};
this.props.onKeyDown(e);
onKeyDown(e);
};
onMouseEnter (e: any, item: any) {
const onMouseEnter = (e: any, item: any) => {
if (!keyboard.isMouseDisabled) {
this.props.setActive(item, false);
setActive(item, false);
};
};
onSortStart () {
const onSortStart = () => {
keyboard.disableSelection(true);
};
onSortEnd (result: any) {
const { oldIndex, newIndex } = result;
const { param } = this.props;
const { data } = param;
const { rootId, blockId } = data;
const onSortEnd = (result: any) => {
const { active, over } = result;
const ids = items.map(it => it.id);
const oldIndex = ids.indexOf(active.id);
const newIndex = ids.indexOf(over.id);
S.Record.groupsSet(rootId, blockId, arrayMove(this.getItems(), oldIndex, newIndex));
this.save();
S.Record.groupsSet(rootId, blockId, arrayMove(items, oldIndex, newIndex));
save();
keyboard.disableSelection(false);
};
onSwitch (e: any, item: any, v: boolean) {
const groups = this.getItems();
const group = groups.find(it => it.id == item.id);
const onSwitch = (e: any, item: any, v: boolean) => {
const current = items.find(it => it.id == item.id);
group.isHidden = !v;
this.save();
current.isHidden = !v;
save();
};
save () {
const { param } = this.props;
const { data } = param;
const { rootId, blockId, getView } = data;
const save = () => {
const view = getView();
const groups = this.getItems();
const items = S.Record.getGroups(rootId, blockId);
const update: any[] = [];
groups.forEach((it: any, i: number) => {
items.forEach((it: any, i: number) => {
update.push({ ...it, groupId: it.id, index: i });
});
S.Record.groupsSet(rootId, blockId, groups);
S.Record.groupsSet(rootId, blockId, items);
Dataview.groupUpdate(rootId, blockId, view.id, update);
C.BlockDataviewGroupOrderUpdate(rootId, blockId, { viewId: view.id, groups: update });
};
onScroll ({ scrollTop }) {
const onScroll = ({ scrollTop }) => {
if (scrollTop) {
this.top = scrollTop;
top.current = scrollTop;
};
};
getItems () {
const { param } = this.props;
const { data } = param;
const { rootId, blockId } = data;
return S.Record.getGroups(rootId, blockId);
};
resize () {
const { getId, position } = this.props;
const items = this.getItems();
const resize = () => {
const obj = $(`#${getId()} .content`);
const height = Math.max(HEIGHT * 2, Math.min(360, items.length * HEIGHT + 16));
obj.css({ height });
position();
};
const Handle = () => (
<Icon className="dnd" />
);
const Item = (item: any) => {
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: item.id, disabled: !allowedView });
const canHide = allowedView;
const canEdit = !readonly && allowedView;
const subId = S.Record.getSubId(rootId, [ blockId, item.id ].join(':'));
const cn = [ 'item' ];
const head = {};
const style = {
transform: CSS.Transform.toString(transform),
transition,
};
head[view.groupRelationKey] = item.value;
if (!canEdit) {
cn.push('isReadonly');
};
return (
<div
id={'item-' + item.id}
className={cn.join(' ')}
onMouseEnter={e => onMouseEnter(e, item)}
ref={setNodeRef}
{...attributes}
{...listeners}
style={style}
>
{allowedView ? <Icon className="dnd" /> : ''}
<span className="clickable">
<Cell
id={'menu-group-' + item.id}
rootId={rootId}
subId={subId}
block={block}
relationKey={view.groupRelationKey}
viewType={I.ViewType.Board}
getRecord={() => head}
readonly={true}
arrayLimit={4}
withName={true}
placeholder={translate('commonUncategorized')}
/>
</span>
{canHide ? (
<Switch
value={!item.isHidden}
onChange={(e: any, v: boolean) => onSwitch(e, item, v)}
/>
) : ''}
</div>
);
};
});
const rowRenderer = (param: any) => {
const item: any = items[param.index];
return (
<CellMeasurer
key={param.key}
parent={param.parent}
cache={cache.current}
columnIndex={0}
rowIndex={param.index}
>
<Item key={item.id} {...item} index={param.index} style={param.style} />
</CellMeasurer>
);
};
useEffect(() => {
rebind();
resize();
return () => {
unbind();
S.Menu.closeAll(J.Menu.cell);
};
}, []);
useEffect(() => {
resize();
rebind();
setActive(null, true);
position();
if (top.current) {
listRef.current?.scrollToPosition(top.current);
};
});
useImperativeHandle(ref, () => ({
rebind,
unbind,
getItems: () => items,
getIndex: () => n.current,
setIndex: (i: number) => n.current = i,
}), []);
return (
<div className="wrap">
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragStart={onSortStart}
onDragEnd={onSortEnd}
modifiers={[ restrictToVerticalAxis, restrictToFirstScrollableAncestor ]}
>
<SortableContext
items={items.map((item) => item.id)}
strategy={verticalListSortingStrategy}
>
<div className="items">
<InfiniteLoader
rowCount={items.length}
loadMoreRows={() => {}}
isRowLoaded={() => true}
threshold={LIMIT}
>
{({ onRowsRendered }) => (
<AutoSizer className="scrollArea">
{({ width, height }) => (
<VList
ref={listRef}
width={width}
height={height}
deferredMeasurmentCache={cache.current}
rowCount={items.length}
rowHeight={HEIGHT}
rowRenderer={rowRenderer}
onRowsRendered={onRowsRendered}
overscanRowCount={LIMIT}
onScroll={onScroll}
scrollToAlignment="center"
/>
)}
</AutoSizer>
)}
</InfiniteLoader>
</div>
</SortableContext>
</DndContext>
</div>
);
}));
export default MenuGroupList;

View file

@ -119,7 +119,7 @@ class MenuObject extends React.Component<I.Menu> {
let history = { id: 'history', name: translate('commonVersionHistory'), caption: keyboard.getCaption('history') };
let createWidget = { id: 'createWidget', icon: 'createWidget', name: translate('menuObjectCreateWidget') };
let pageCopy = { id: 'pageCopy', icon: 'copy', name: translate('commonDuplicate') };
let pageLink = { id: 'pageLink', icon: 'link', name: translate('commonCopyLink') };
let pageLink = { id: 'pageLink', icon: 'link', name: translate('commonCopyDeeplink') };
let pageReload = { id: 'pageReload', icon: 'reload', name: translate('menuObjectReloadFromSource') };
let pageExport = { id: 'pageExport', icon: 'export', name: translate('menuObjectExport') };
let downloadFile = { id: 'downloadFile', icon: 'download', name: translate('commonDownload') };
@ -486,24 +486,7 @@ class MenuObject extends React.Component<I.Menu> {
};
case 'pageLink': {
const link = `${J.Constant.protocol}://${U.Object.universalRoute(object)}`;
const cb = (link: string) => {
U.Common.copyToast(translate('commonLink'), link);
analytics.event('CopyLink', { route });
};
if (space.isShared) {
U.Space.getInvite(S.Common.space, (cid: string, key: string) => {
if (cid && key) {
cb(link + `&cid=${cid}&key=${key}`);
} else {
cb(link);
};
});
} else {
cb(link);
};
U.Object.copyLink(object, space, 'deeplink', '');
break;
};

View file

@ -25,6 +25,11 @@ const MenuPublish = observer(forwardRef<I.MenuRef, I.Menu>((props, ref) => {
const domain = U.Space.getPublishDomain();
const url = U.Space.getPublishUrl(slug);
const items = [
{
id: 'link',
name: translate('commonCopyLink'),
onClick: () => U.Object.copyLink(object, space, 'web', ''),
},
(!space.isPersonal ?
{
id: 'space',

View file

@ -155,12 +155,16 @@ const Page = observer(class Page extends React.Component<I.PageComponent> {
ret.params.spaceId = data.spaceId;
ret.params.cid = data.cid;
ret.params.key = data.key;
ret.params.route = data.route;
};
// Invite route
if (pathname.match(/^\/invite/)) {
ret.params.page = 'main';
ret.params.action = 'invite';
ret.params.cid = data.cid;
ret.params.key = data.key;
ret.params.route = data.route;
};
// Membership route

View file

@ -8,27 +8,27 @@ interface PageMainInviteRefProps {
const PageMainInvite = forwardRef<PageMainInviteRefProps, I.PageComponent>((props, ref) => {
const { isPopup } = props;
const { isPopup, match } = props;
const nodeRef = useRef(null);
const frameRef = useRef(null);
const cid = useRef('');
const key = useRef('');
const cidRef = useRef('');
const keyRef = useRef('');
const [ error, setError ] = useState('');
const init = () => {
const data = U.Common.searchParam(U.Router.history.location.search);
const { cid, key, route } = match.params || {};
if ((cid.current == data.cid) && (key.current == data.key)) {
if ((cidRef.current == cid) && (keyRef.current == key)) {
return;
};
cid.current = data.cid;
key.current = data.key;
cidRef.current = cid;
keyRef.current = key;
if (!data.cid || !data.key) {
if (!cid || !key) {
setError(translate('pageMainInviteErrorData'));
} else {
C.SpaceInviteView(data.cid, data.key, (message: any) => {
C.SpaceInviteView(cid, key, (message: any) => {
U.Space.openDashboard({ replace: true });
S.Popup.closeAll(null, () => {
@ -75,10 +75,24 @@ const PageMainInvite = forwardRef<PageMainInviteRefProps, I.PageComponent>((prop
},
});
} else {
S.Popup.open('inviteRequest', { data: { invite: message, ...data } });
S.Popup.open('inviteRequest', {
data: {
invite: message,
cid,
key,
route,
},
});
};
} else {
S.Popup.open('inviteRequest', { data: { invite: message, ...data } });
S.Popup.open('inviteRequest', {
data: {
invite: message,
cid,
key,
route,
},
});
};
});
});

View file

@ -1,17 +1,18 @@
import React, { forwardRef, useEffect } from 'react';
import { I, C, U } from 'Lib';
import { I, C, U, analytics } from 'Lib';
const PageMainObject = forwardRef<{}, I.PageComponent>((props, ref) => {
const { match } = props;
useEffect(() => {
const { id, spaceId, cid, key } = match.params || {};
const { id, spaceId, cid, key, route } = match.params || {};
const space = U.Space.getSpaceviewBySpaceId(spaceId);
// Redirect to invite page when invite parameters are present
if ((!space || !space.isAccountActive) && cid && key) {
U.Router.go(`/main/invite/?cid=${cid}&key=${key}`, { replace: true });
analytics.event('OpenObjectByLink', { route, type: 'Invite' });
return;
};
@ -29,7 +30,10 @@ const PageMainObject = forwardRef<{}, I.PageComponent>((props, ref) => {
return;
};
U.Object.openRoute(item.details);
const object = item.details;
U.Object.openRoute(object);
analytics.event('OpenObjectByLink', { route, objectType: object.type, type: 'Object' });
});
}, []);

View file

@ -50,6 +50,14 @@ const PopupInviteRequest = observer(class PopupInviteRequest extends React.Compo
);
};
componentDidMount(): void {
const { param } = this.props;
const { data } = param;
const { route } = data;
analytics.event('ScreenInviteRequest', { route });
};
onRequest () {
const { param, close } = this.props;
const { account } = S.Auth;

View file

@ -31,6 +31,8 @@ const PreviewDefault = observer(forwardRef<{}, Props>((props, ref) => {
};
const load = () => {
console.log(rootId, idRef.current);
if (isLoading || (idRef.current == rootId)) {
return;
};
@ -49,6 +51,8 @@ const PreviewDefault = observer(forwardRef<{}, Props>((props, ref) => {
};
useEffect(() => {
console.log(initialObject);
if (initialObject) {
setObject(initialObject);
};

View file

@ -13,7 +13,7 @@ const PreviewIndex = observer(forwardRef(() => {
const polygonRef = useRef(null);
const { preview } = S.Common;
const { type, target, object: initialObject, marks, range, noUnlink, noEdit, x, y, width, height, onChange } = preview;
const [ object, setObject ] = useState(initialObject || {});
const [ object, setObject ] = useState(initialObject);
const cn = [ 'previewWrapper' ];
const win = $(window);

View file

@ -2,7 +2,9 @@ import * as React from 'react';
import { observer } from 'mobx-react';
import { AutoSizer, CellMeasurer, InfiniteLoader, List, CellMeasurerCache } from 'react-virtualized';
import { Title, Filter, Icon, Button, Label, EmptySearch } from 'Component';
import { I, U, J, S, translate, Storage, sidebar, keyboard, analytics, Action, Relation } from 'Lib';
import { I, U, J, S, translate, Storage, sidebar, keyboard, analytics, Action } from 'Lib';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Mousewheel, Navigation } from 'swiper/modules';
import Item from './allObject/item';
@ -23,6 +25,7 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
node = null;
refFilter = null;
refList = null;
refSwiper = null;
cache: any = {};
offset = 0;
sortId: I.SortId = I.SortId.Updated;
@ -40,6 +43,7 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
tabIndex = 0;
tabArray = [];
x = 0;
top = 0;
constructor (props: any) {
super(props);
@ -50,13 +54,10 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
this.onFilterClear = this.onFilterClear.bind(this);
this.onAdd = this.onAdd.bind(this);
this.onScroll = this.onScroll.bind(this);
this.onTabOver = this.onTabOver.bind(this);
this.onTabLeave = this.onTabLeave.bind(this);
this.onTabScroll = this.onTabScroll.bind(this);
this.loadMoreRows = this.loadMoreRows.bind(this);
};
render() {
render () {
const { isLoading } = this.state;
const items = this.getItems();
const isAllowedObject = this.isAllowedObject();
@ -125,25 +126,26 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
</div>
</div>
<div
id="tabs"
className="tabs"
onMouseEnter={this.onTabOver}
onMouseLeave={this.onTabLeave}
>
<div
className="scrollWrap"
onScroll={this.onTabScroll}
<div id="tabs" className="tabs">
<Swiper
onSwiper={swiper => this.refSwiper = swiper}
direction={'horizontal'}
slidesPerView={'auto'}
slidesPerGroupAuto={true}
spaceBetween={12}
mousewheel={true}
navigation={true}
modules={[ Mousewheel, Navigation ]}
>
<div className="scroll">
{typeOptions.map((it: any, i: number) => {
const cn = [ 'tab' ];
{typeOptions.map((it: any, i: number) => {
const cn = [ 'tab' ];
if (this.type == it.id) {
cn.push('active');
};
if (this.type == it.id) {
cn.push('active');
};
return (
return (
<SwiperSlide key={it.id}>
<div
key={it.id}
className={cn.join(' ')}
@ -151,22 +153,10 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
>
{it.name}
</div>
);
})}
</div>
</div>
<div className="controls">
<div className="side left">
<Icon className="arrow withBackground" onClick={() => this.onTabArrow(-1)} />
<div className="gradient" />
</div>
<div className="side right">
<Icon className="arrow withBackground" onClick={() => this.onTabArrow(1)} />
<div className="gradient" />
</div>
</div>
</SwiperSlide>
);
})}
</Swiper>
</div>
<div className="sides sidesFilter">
@ -201,7 +191,14 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
threshold={LIMIT}
>
{({ onRowsRendered }) => (
<AutoSizer className="scrollArea">
<AutoSizer
className="scrollArea"
onResize={() => {
if (this.top) {
this.refList?.scrollToPosition(this.top);
};
}}
>
{({ width, height }) => (
<List
ref={ref => this.refList = ref}
@ -235,7 +232,7 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
this.load(true);
const idx = Math.max(0, this.getTypeOptions().findIndex(it => it.id == this.type));
this.scrollToTab(idx, false);
this.refSwiper?.slideTo(idx);
analytics.event('ScreenLibrary');
};
@ -250,7 +247,6 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
});
this.setActive(items[this.n]);
this.checkTabButtons();
};
componentWillUnmount(): void {
@ -790,7 +786,10 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
};
};
onScroll () {
onScroll ({ scrollTop }) {
if (scrollTop) {
this.top = scrollTop;
};
this.renderSelection();
};
@ -985,123 +984,6 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
return [ I.SortId.Created, I.SortId.Updated ].includes(this.sortId);
};
onTabOver () {
const node = $(this.node);
const tabs = node.find('#tabs');
const controls = tabs.find('.controls');
const sideLeft = controls.find('.side.left');
const sideRight = controls.find('.side.right');
const width = tabs.outerWidth();
const cx = tabs.offset().left;
const half = width / 2;
this.onTabLeave();
const check = () => {
const x = keyboard.mouse.page.x - cx;
if ((x >= 0) && (x <= half)) {
sideLeft.addClass('hover');
};
if ((x > half) && (x <= width)) {
sideRight.addClass('hover');
};
};
check();
$(window).off('mousemove.sidebarObject').on('mousemove.sidebarObject', e => check());
};
onTabLeave () {
const node = $(this.node);
const tabs = node.find('#tabs');
const controls = tabs.find('.controls');
const sideLeft = controls.find('.side.left');
const sideRight = controls.find('.side.right');
sideLeft.removeClass('hover');
sideRight.removeClass('hover');
$(window).off('mousemove.sidebarObject');
};
onTabArrow (dir: number) {
this.tabIndex += dir;
this.checkTabIndex();
this.scrollToTab(this.tabIndex, true);
};
onTabScroll () {
const node = $(this.node);
const tabs = node.find('#tabs');
const scroll = tabs.find('.scrollWrap');
this.x = scroll.scrollLeft();
for (const item of this.tabArray) {
if ((this.x >= item.x) && (this.x <= item.x + item.w)) {
this.tabIndex = item.i;
break;
};
};
this.checkTabX();
this.checkTabIndex();
this.checkTabButtons();
};
scrollToTab (idx: number, animate: boolean) {
const node = $(this.node);
const tabs = node.find('#tabs');
const scroll = tabs.find('.scrollWrap');
this.fillTabArray();
this.tabIndex = idx;
this.checkTabIndex();
this.x = this.tabArray[this.tabIndex].x;
this.checkTabX();
if (animate) {
scroll.animate({ scrollLeft: this.x }, 200);
} else {
scroll.scrollLeft(this.x);
};
this.checkTabButtons();
};
checkTabX () {
const node = $(this.node);
const tabs = node.find('#tabs');
const scroll = tabs.find('.scroll');
const max = this.getMaxWidth();
const sw = scroll.width();
this.x = Math.floor(this.x);
this.x = Math.max(0, this.x);
this.x = Math.min(max - sw, this.x);
};
checkTabIndex () {
this.tabIndex = Math.max(0, this.tabIndex);
this.tabIndex = Math.min(this.tabArray.length - 1, this.tabIndex);
};
checkTabButtons () {
const node = $(this.node);
const tabs = node.find('#tabs');
const scroll = tabs.find('.scroll');
const controls = node.find('.controls');
const sideLeft = controls.find('.side.left');
const sideRight = controls.find('.side.right');
const max = this.getMaxWidth();
const sw = scroll.width();
sideLeft.toggleClass('hide', this.x <= 0);
sideRight.toggleClass('hide', this.x >= max - sw - 1);
};
getMaxWidth () {
const node = $(this.node);
const tabs = node.find('#tabs');
@ -1130,10 +1012,6 @@ const SidebarPageObject = observer(class SidebarPageObject extends React.Compone
};
};
resize () {
this.scrollToTab(0, false);
};
});
export default SidebarPageObject;

View file

@ -68,7 +68,7 @@ const SidebarSectionTypeRelation = observer(forwardRef<I.SidebarSectionRef, I.Si
const onAdd = (e: any, id: string) => {
const list = lists.find(it => it.id == id);
const keys = lists.reduce((acc, it) => acc.concat(it.data.map(it => it.relationKey)), []);
const keys = lists.reduce((acc, it) => acc.concat(it.data.map(it => it.relationKey)), []).concat('description');
const ids = list.data.map(it => it.id);
S.Menu.open('relationSuggest', {

View file

@ -27,9 +27,9 @@ const Vault = observer(forwardRef<VaultRefProps>((props, ref) => {
const items = U.Menu.getVaultItems();
const cn = [ 'vault' ];
const sensors = useSensors(
useSensor(PointerSensor, { activationConstraint: { distance: 10 } }),
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
);
useSensor(PointerSensor, { activationConstraint: { distance: 10 } }),
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
);
if (!showVault) {
cn.push('isHidden');
@ -322,16 +322,16 @@ const Vault = observer(forwardRef<VaultRefProps>((props, ref) => {
<div className="head" />
<div className="body">
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
sensors={sensors}
collisionDetection={closestCenter}
onDragStart={onSortStart}
onDragEnd={onSortEnd}
onDragEnd={onSortEnd}
modifiers={[ restrictToVerticalAxis, restrictToFirstScrollableAncestor ]}
>
<SortableContext
items={items.map((item) => item.id)}
strategy={verticalListSortingStrategy}
>
>
<SortableContext
items={items.map((item) => item.id)}
strategy={verticalListSortingStrategy}
>
<div id="scroll" className="side top" onScroll={onScroll}>
{items.map((item, i) => (
<VaultItem

View file

@ -596,7 +596,6 @@ class Analytics {
popupMapper (params: any): string {
const { id } = params;
const map = {
inviteRequest: 'ScreenInviteRequest',
spaceCreate: 'ScreenSettingsSpaceCreate',
};

View file

@ -635,7 +635,7 @@ class Mark {
switch (type) {
case I.MarkType.Link: {
attr = `href="${param}"`;
attr = `href="${U.Common.urlFix(param)}"`;
break;
};
@ -717,6 +717,10 @@ class Mark {
};
getTag (t: I.MarkType): string {
if (t == I.MarkType.Link) {
return 'a';
};
return I.MarkType[t] ? `markup${I.MarkType[t].toLowerCase()}` : '';
};

View file

@ -134,10 +134,10 @@ class ScrollOnMove {
const edgeLeft = BORDER;
const edgeBottom = this.viewportHeight - BORDER;
const edgeRight = this.viewportWidth - BORDER;
const isInLeftEdge = x < edgeLeft;
const isInLeftEdge = (x > 0) && (x < edgeLeft);
const isInRightEdge = x > edgeRight;
const isInTopEdge = y < edgeTop;
const isInTopEdge = (y > 0) && (y < edgeTop);
const isInBottomEdge = y > edgeBottom;
if (!(isInLeftEdge || isInRightEdge || isInTopEdge || isInBottomEdge)) {

View file

@ -1084,7 +1084,7 @@ class UtilCommon {
return text;
};
match.forEach((m: any) => {
Array.from(match).forEach((m: any) => {
const m0 = String(m[0] || '');
const m1 = String(m[1] || '');
const m2 = String(m[2] || '');

View file

@ -586,6 +586,49 @@ class UtilObject {
C.BlockListSetFields(id, [ { blockId: id, fields } ]);
};
copyLink (object: any, space: any, type: string, route: string) {
const cb = (link: string) => {
U.Common.copyToast(translate('commonLink'), link);
analytics.event('CopyLink', { route });
};
let link = '';
switch (type) {
case 'deeplink': {
link = `${J.Constant.protocol}://${U.Object.universalRoute(object)}`;
break;
};
case 'web': {
link = `https://object.any.coop/${object.id}?spaceId=${space.targetSpaceId}`;
break;
};
};
if (space.isShared) {
U.Space.getInvite(space.targetSpaceId, (cid: string, key: string) => {
if (cid && key) {
switch (type) {
case 'deeplink': {
cb(link + `&cid=${cid}&key=${key}`);
break;
};
case 'web': {
cb(link + `&inviteID=${cid}#${key}`);
break;
};
};
} else {
cb(link);
};
});
} else {
cb(link);
};
};
};
export default new UtilObject();