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

Merge branch 'main' of github.com:anyproto/anytype-ts into feature/native-messaging-host

This commit is contained in:
Andrew Simachev 2023-11-15 16:11:33 +01:00
commit 6f5b8c3338
No known key found for this signature in database
GPG key ID: 49A163D0D14E6FD8
54 changed files with 478 additions and 331 deletions

BIN
dist/img/help/36/2.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

115
dist/workers/graph.js vendored
View file

@ -15,6 +15,7 @@ const util = new Util();
// CONSTANTS
const transformThreshold = 1.5;
const delayFocus = 1000;
const ObjectLayout = {
Human: 1,
@ -70,7 +71,9 @@ let edgeMap = new Map();
let hoverAlpha = 0.2;
let fontFamily = 'Helvetica, san-serif';
let timeoutHover = 0;
let rootId = '';
let root = null;
let paused = false;
addEventListener('message', ({ data }) => {
if (this[data.id]) {
@ -82,7 +85,7 @@ init = (param) => {
data = param;
canvas = data.canvas;
settings = data.settings;
rootId = data.rootId;
ctx = canvas.getContext('2d');
util.ctx = ctx;
@ -99,16 +102,15 @@ init = (param) => {
initForces();
simulation.on('tick', () => { redraw(); });
simulation.on('tick', () => redraw());
simulation.tick(100);
// Center initially on root node
setTimeout(() => {
root = getNodeById(data.rootId);
root = getNodeById(rootId);
let x = width / 2;
let y = height / 2;
if (root) {
x = root.x;
y = root.y;
@ -199,10 +201,11 @@ initForces = () => {
.y(height * forceY.y);
updateForces();
redraw();
};
updateForces = () => {
let old = getNodeMap();
const old = getNodeMap();
edges = util.objectCopy(data.edges);
nodes = util.objectCopy(data.nodes);
@ -217,6 +220,14 @@ updateForces = () => {
edges = edges.filter(d => d.type != EdgeType.Relation);
};
// Filte local only edges
if (settings.local) {
edges = edges.filter(d => (d.source == rootId) || (d.target == rootId));
const nodeIds = util.arrayUnique([ rootId ].concat(edges.map(d => d.source)).concat(edges.map(d => d.target)));
nodes = nodes.filter(d => nodeIds.includes(d.id));
};
let map = getNodeMap();
edges = edges.filter(d => map.get(d.source) && map.get(d.target));
@ -237,7 +248,13 @@ updateForces = () => {
edges = edges.filter(d => map.get(d.source) && map.get(d.target));
// Shallow copy to disable mutations
nodes = nodes.map(d => Object.assign(old.get(d.id) || {}, d));
nodes = nodes.map(d => {
let o = old.get(d.id);
if (!o) {
o = settings.local ? { x: width / 2, y: width / 2 } : {};
};
return Object.assign(o, d);
});
edges = edges.map(d => Object.assign({}, d));
simulation.nodes(nodes);
@ -258,16 +275,28 @@ updateForces = () => {
};
updateSettings = (param) => {
const needUpdate = (param.link != settings.link) ||
(param.relation != settings.relation) ||
(param.orphan != settings.orphan);
const updateKeys = [ 'link', 'relation', 'orphan', 'local' ];
let needUpdate = false;
let needFocus = false;
for (let key of updateKeys) {
if (param[key] != settings[key]) {
needUpdate = true;
if (key == 'local') {
needFocus = true;
};
break;
};
};
settings = Object.assign(settings, param);
needUpdate ? updateForces() : redraw();
if (needUpdate) {
updateForces();
} else {
redraw();
if (needFocus) {
setTimeout(() => this.setRootId({ rootId }), delayFocus);
};
};
@ -289,7 +318,7 @@ draw = (t) => {
ctx.font = getFont();
edges.forEach(d => {
drawLine(d, radius, radius * 1.3, settings.marker && d.isDouble, settings.marker);
drawEdge(d, radius, radius * 1.3, settings.marker && d.isDouble, settings.marker);
});
nodes.forEach(d => {
@ -303,10 +332,12 @@ draw = (t) => {
redraw = () => {
cancelAnimationFrame(frame);
frame = requestAnimationFrame(draw);
if (!paused) {
frame = requestAnimationFrame(draw);
};
};
drawLine = (d, arrowWidth, arrowHeight, arrowStart, arrowEnd) => {
drawEdge = (d, arrowWidth, arrowHeight, arrowStart, arrowEnd) => {
const x1 = d.source.x;
const y1 = d.source.y;
const r1 = getRadius(d.source);
@ -577,6 +608,22 @@ onSelect = ({ x, y, selectRelated }) => {
};
};
onSetRootId = ({ x, y }) => {
const d = getNodeByCoords(x, y);
if (d) {
this.setRootId({ rootId: d.id });
};
};
onSetEdges = (param) => {
data.edges = param.edges;
updateForces();
};
onSetSelected = ({ ids }) => {
selected = ids;
};
onMouseMove = ({ x, y }) => {
const active = nodes.find(d => d.isOver);
const d = getNodeByCoords(x, y);
@ -618,12 +665,11 @@ onContextMenu = ({ x, y }) => {
const d = getNodeByCoords(x, y);
if (!d) {
send('onContextSpaceClick', { x, y });
return;
} else {
send('onContextMenu', { node: d, x, y });
d.isOver = true;
redraw();
};
d.isOver = true;
send('onContextMenu', { node: d, x, y });
redraw();
};
onAddNode = ({ target, sourceId }) => {
@ -667,21 +713,12 @@ onRemoveNode = ({ ids }) => {
data.edges = data.edges.filter(d => !ids.includes(d.source.id) && !ids.includes(d.target.id));
updateForces();
redraw();
};
onSetEdges = (param) => {
data.edges = param.edges;
setRootId = (param) => {
rootId = param.rootId;
root = getNodeById(rootId);
updateForces();
};
onSetSelected = ({ ids }) => {
selected = ids;
};
onSetRootId = ({ rootId }) => {
root = nodes.find(d => d.id == rootId);
if (!root) {
return;
};
@ -696,12 +733,14 @@ onSetRootId = ({ rootId }) => {
transform = Object.assign(transform, coords);
redraw();
})
.onComplete(() => {
send('onTransform', { ...transform });
})
.onComplete(() => send('onTransform', { ...transform }))
.start();
redraw();
if (settings.local) {
updateForces();
} else {
redraw();
};
};
restart = (alpha) => {

View file

@ -78,4 +78,8 @@ class Util {
this.ctx.restore();
};
arrayUnique (a) {
return [ ...new Set(a) ];
};
};

View file

@ -1 +1 @@
0.29.9
0.29.11

4
package-lock.json generated
View file

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

View file

@ -1,6 +1,6 @@
{
"name": "anytype",
"version": "0.35.20-beta",
"version": "0.35.23-beta",
"description": "Anytype",
"main": "electron.js",
"scripts": {

View file

@ -1173,6 +1173,7 @@
"menuGraphSettingsLinks": "Links",
"menuGraphSettingsRelations": "Relations",
"menuGraphSettingsUnlinkedObjects": "Unlinked Objects",
"menuGraphSettingsLocal": "Local graph",
"menuHelpWhatsNew": "What's New",
"menuHelpShortcut": "Keyboard Shortcuts",
@ -1440,8 +1441,7 @@
"dispatcherImportTryAgain": "Try again",
"onboardingMainGraph": "Onboarding",
"onboardingMainGraph11": "<b>Welcome to your Anytype Space.</b> Space is a graph of interconnected objects, providing a natural way to organize information.",
"onboardingMainGraph12": "To access your Homepage, click on the <span class=\"highlight\">Next</span> button.",
"onboardingMainGraph11": "<b>Space is essentially a graph</b>, and Anytype aims to provide a natural way of thinking where everything is represented as objects with specific relationships, just like in the real world.",
"onboardingMainSet": "Set & Collection",
"onboardingMainSet11": "<b>Anytype has two basic formats: Sets and Collections.</b> As in computer science, a Set is a data structure that contains only unique elements, while a Collection is any group of objects that are stored together. You can convert any set into a collection, but not the other way around.",
@ -1471,13 +1471,9 @@
"onboardingObjectCreationFinish1Button": "Ok! I like it",
"onboardingDashboard": "Onboarding",
"onboardingDashboard11": "<b>Welcome to your Homepage.</b> This is your personalized page, which you can customize to your liking.<br />We've included some materials to help you get started, but feel free to make adjustments as needed.",
"onboardingDashboard12": "Let's take a few minutes to explore the features together.",
"onboardingDashboard21": "<b>Sets, acting as filters for your objects</b>, are featured on your Homepage.",
"onboardingDashboard22": "Sets make it easy to navigate and collect specific Objects, such as Notes, Links, Tasks, ideas, and more.",
"onboardingDashboard23": "To access different Set Views, simply select them.",
"onboardingDashboard31": "<b>Objects in Anytype</b> have specific types depending on their purpose. You can use system types or define custom ones. Structure objects with Relations and links.",
"onboardingDashboard32": "To add an Object to a Set, click the <span class=\"highlight\">New</span> button and view its relation as properties in columns.",
"onboardingDashboard11": "<b>Welcome to your Homepage.</b> This is your personalized page, which you can customize to your liking.",
"onboardingDashboard12": "Feel free to make adjustments as needed.",
"onboardingDashboard13": "Let's take a few minutes to explore the features together.",
"onboardingDashboard41": "<b>You'll find the Sidebar on the left.</b> It's a navigation tool that you can customize with multiple widget types.",
"onboardingDashboard42": "Change the Widget appearance and see what looks best. Make your Favorites as a Tree Widget.",
"onboardingDashboard51": "<b>Great job!</b> You have completed this section. Feel free to explore other menus in the interface, such as Library and Sets.",
@ -1577,13 +1573,13 @@
"errorAccountRecover109": "Account has been deleted",
"errorObjectImport7": "Import has not been completed. CSV import supports up to 1000 rows and 10 columns.",
"objectOrigin0": "User",
"objectOrigin1": "Clipboard",
"objectOrigin2": "Drag'n'Drop",
"objectOrigin3": "Import",
"objectOrigin4": "Webclipper",
"objectOrigin5": "Sharing Extension",
"objectOrigin6": "Usecase",
"objectOrigin7": "Built-in"
"origin0": "User",
"origin1": "Clipboard",
"origin2": "Drag'n'Drop",
"origin3": "Import",
"origin4": "Webclipper",
"origin5": "Sharing Extension",
"origin6": "Usecase",
"origin7": "Built-in"
}

View file

@ -28,9 +28,9 @@
.day.first { border-top-width: 0px; }
.day.active {
.number {
display: inline-block; color: $colorTextInversion; background-color: $colorSystemAccent100; border-radius: 12px;
padding: 0px 7px; align-self: flex-end;
.number { padding: 0px; color: $colorTextInversion; }
.number {
.inner { background-color: $colorSystemAccent100; border-radius: 12px; padding: 0px 7px; align-self: flex-end; }
}
}
@ -39,7 +39,11 @@
}
.day {
.number { @include text-paragraph; text-align: right; }
.number { @include text-paragraph; text-align: right; padding: 0px 8px; }
.number {
.inner { display: inline-block; }
}
.item {
display: flex; flex-direction: row; align-items: center; gap: 0px 4px; @include text-small; @include text-overflow-nw;
margin: 0px 0px 2px 0px; position: relative; padding: 0px 8px; border-radius: 4px;

View file

@ -19,6 +19,14 @@
}
.card {
.dropTarget { height: 100%; }
.dropTarget.isOver { box-shadow: 0px 0px; }
.dropTarget.isOver::before { content: ""; position: absolute; background: $colorSystemAccent100; width: 2px; height: 100%; border-radius: 2px; top: 0px; }
.dropTarget.isOver.top::before { left: -10px; }
.dropTarget.isOver.bottom::before { right: -10px; }
.selectable.isSelectionSelected::after { border-radius: 12px; }
.selectable { height: 100%; }
.itemContent > .inner { padding: 16px; }
@ -92,13 +100,6 @@
.input.name { padding: 0; height: unset; }
}
}
.viewContent.viewGallery.isCollection {
.dropTarget.isOver { box-shadow: 0px 0px; }
.dropTarget.isOver::before { content: ""; position: absolute; background: $colorSystemAccent100; width: 2px; height: 100%; border-radius: 2px; top: 0px; }
.dropTarget.isOver.top::before { left: -10px; }
.dropTarget.isOver.bottom::before { right: -10px; }
}
}
}

View file

@ -112,7 +112,7 @@
.cardName { flex-wrap: nowrap; vertical-align: top; max-width: 100%; }
.cardName {
.name { @include text-overflow-nw; line-height: 19px; }
.name { @include text-overflow-nw; line-height: 19px; border-bottom: 0.075em solid; border-color: inherit; }
}
.cardDescription { @include text-small; }

View file

@ -22,8 +22,14 @@
.block.blockDataview {
.dropTarget { padding: 0px !important; }
.viewItem {
.record { left: 0px !important; top: 0px !important; overflow: hidden; }
.viewContent {
.record { position: relative !important; left: 0px !important; top: 0px !important; overflow: hidden; }
.record {
.selectable.isSelectionSelected::after { display: none; }
}
}
.viewContent.viewGallery {
.record { margin: 0px 10px 10px 0px; }
}
}
}

View file

@ -57,9 +57,15 @@
.day { display: flex; flex-direction: column; }
.day {
.number { @include text-paragraph; text-align: right; position: relative; z-index: 1; padding: 0px 8px; flex-shrink: 0; }
.number {
.inner { display: inline-block; }
}
}
.day.active {
.number { color: $colorSystemAccent100; }
.number { padding: 0px; color: $colorTextInversion; }
.number {
.inner { background-color: $colorSystemAccent100; border-radius: 12px; padding: 0px 7px; align-self: flex-end; }
}
}
.day.other {
.number { color: $colorTextSecondary; }

View file

@ -3,7 +3,14 @@
.pageMainNavigation {
.wrapper > #loader { position: fixed; top: 0px; width: 100%; height: 100%; background: $colorBgPrimary; z-index: 1; }
.sides { display: flex; padding: 0px 16px; }
.sideName { margin-bottom: 13px; @include text-common; font-weight: 500; padding: 0px 16px; }
.items { width: 33.33%; padding: 4px 0px; }
.items.center { padding: 39px 16px 4px 16px; }
.items {
.row { width: 100%; padding: 0px 32px 0px 16px; }
.item {
transition: $transitionAllCommon; position: relative; line-height: 48px; margin-bottom: 16px; padding: 0px;
height: 80px; border: 1px solid $colorShapeSecondary; border-radius: 8px;
@ -21,24 +28,31 @@
width: 24px; height: 24px; position: absolute; right: -24px; top: 50%; transform: translateY(-50%);
background-image: url('~img/arrow/nav0.svg');
}
}
.item.active { background-color: $colorShapeHighlightMedium; }
}
.sides { display: flex; padding: 0px 16px; }
.items { width: 33.33%; padding: 4px 0px; }
.items.center { padding: 39px 16px 4px 16px; }
.items {
.row { width: 100%; padding: 0px 32px 0px 16px; }
.item {
.icon.arrow {
width: 24px; height: 24px; position: absolute; right: -24px; top: 50%; transform: translateY(-50%);
background-image: url('~img/arrow/nav0.svg');
}
}
.item.selected {
padding: 16px; border-radius: 8px; border: 1px solid $colorShapeSecondary; transition: $transitionAllCommon; height: auto;
}
.item.selected {
.iconObject { margin-bottom: 8px; }
.name { margin-bottom: 1px; @include text-overflow-nw; height: 22px; }
.descr { @include text-small; color: $colorTextSecondary; @include text-overflow; max-height: 54px; }
.cover { position: relative; height: 156px; margin-top: 11px; border-radius: 2px; }
.buttons { margin-top: 16px; display: flex; flex-direction: row; align-items: center; gap: 0px 8px; }
.buttons {
.button { width: 100%; }
.button {
.icon.expand { background-image: url('~img/icon/expand.svg'); width: 20px; height: 20px; position: absolute; left: 8px; top: 6px; }
}
}
}
.item.active { background: none; border-color: $colorSystemAccent100 !important; box-shadow: 0px 0px 0px 1px $colorSystemAccent100 inset; }
.item.active {
.icon.arrow { background-image: url('~img/arrow/nav1.svg'); }
@ -50,25 +64,6 @@
}
}
.sideName { margin-bottom: 13px; @include text-common; font-weight: 500; padding: 0px 16px; }
.selected { padding: 16px; border-radius: 8px; border: 1px solid $colorShapeSecondary; transition: $transitionAllCommon; }
.selected {
.iconObject { margin-bottom: 8px; }
.name { margin-bottom: 1px; @include text-overflow-nw; height: 22px; }
.descr { @include text-small; color: $colorTextSecondary; @include text-overflow; max-height: 54px; }
.cover { position: relative; height: 156px; margin-top: 11px; border-radius: 2px; }
.buttons { margin-top: 16px; display: flex; flex-direction: row; align-items: center; gap: 0px 8px; }
.buttons {
.button { width: 100%; }
.button {
.icon.expand { background-image: url('~img/icon/expand.svg'); width: 20px; height: 20px; position: absolute; left: 8px; top: 6px; }
}
}
}
.selected.active { border-color: $colorSystemAccent100 !important; box-shadow: 0px 0px 0px 1px $colorSystemAccent100; }
.items.right {
.item {
.icon.arrow { right: auto; left: -24px; }

View file

@ -265,11 +265,6 @@
.iconObject { background-color: $colorShapeTertiary; }
}
}
.block.blockLink.text {
.linkCard {
.cardName .name { border-color: $colorShapeTertiary; }
}
}
.block.blockLink.card {
.linkCard {
.side.left, .side.right { border-color: $colorShapeTertiary; }

View file

@ -12,7 +12,7 @@ import { Page, SelectionProvider, DragProvider, Progress, Toast, Preview as Prev
import { commonStore, authStore, blockStore, detailStore, dbStore, menuStore, popupStore } from './store';
import {
I, C, UtilCommon, UtilRouter, UtilFile, UtilData, UtilObject, UtilMenu, keyboard, Storage, analytics, dispatcher, translate, Renderer,
focus, Preview, Mark, Animation, Onboarding, Survey, UtilDate
focus, Preview, Mark, Animation, Onboarding, Survey, UtilDate, Encode, Decode,
} from 'Lib';
import * as Docs from 'Docs';
@ -183,6 +183,8 @@ window.Lib = {
Onboarding,
Survey,
Docs,
Encode,
Decode,
};
/*

View file

@ -729,8 +729,8 @@ const BlockDataview = observer(class BlockDataview extends React.Component<Props
window.setTimeout(() => { ref.onClick(e); }, 15);
};
analytics.event('CreateObject', {
route: (isCollection ? 'Collection' : 'Set'),
analytics.event('CreateObject', {
route: this.analyticsRoute(),
objectType: object.type,
layout: object.layout,
});
@ -791,7 +791,7 @@ const BlockDataview = observer(class BlockDataview extends React.Component<Props
const { rootId, block } = this.props;
const menuParam = this.getMenuParam(e, dir);
const isCollection = this.isCollection();
const route = isCollection ? 'Collection' : 'Set';
const route = this.analyticsRoute();
const hasSources = isCollection || this.getSources().length;
const view = this.getView();
@ -842,7 +842,6 @@ const BlockDataview = observer(class BlockDataview extends React.Component<Props
onTemplateAdd (id?: string) {
const typeId = id || this.getTypeId();
const type = dbStore.getTypeById(typeId);
const route = this.isCollection() ? 'Collection' : 'Set';
const details: any = {
targetObjectType: typeId,
layout: type.recommendedLayout,
@ -856,7 +855,7 @@ const BlockDataview = observer(class BlockDataview extends React.Component<Props
const object = message.details;
focus.clear(true);
analytics.event('CreateTemplate', { objectType: typeId, route });
analytics.event('CreateTemplate', { objectType: typeId, route: this.analyticsRoute() });
UtilObject.openPopup(object);
});
@ -939,13 +938,13 @@ const BlockDataview = observer(class BlockDataview extends React.Component<Props
const { x, y } = keyboard.mouse.page;
return { width: 0, height: 0, x: x + 4, y: y };
},
onClose: () => { selection.clear(); },
onClose: () => selection.clear(),
data: {
targetId: this.getObjectId(),
objectIds: ids,
subId,
isCollection,
route: isCollection ? 'Collection' : 'Set',
route: this.analyticsRoute(),
}
});
};
@ -1319,6 +1318,8 @@ const BlockDataview = observer(class BlockDataview extends React.Component<Props
this.searchIds = null;
this.reloadData();
};
analytics.event('ScreenSearchDataview', { route: this.analyticsRoute() });
}, Constant.delay.keyboard);
};
@ -1361,6 +1362,10 @@ const BlockDataview = observer(class BlockDataview extends React.Component<Props
return this.searchIds;
};
analyticsRoute () {
return this.isCollection() ? 'Collection' : 'Set';
};
resize () {
if (this.frame) {
raf.cancel(this.frame);

View file

@ -34,8 +34,8 @@ const CellObject = observer(class CellObject extends React.Component<I.Cell, Sta
this.onInput = this.onInput.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
this.focus = this.focus.bind(this);
this.onDragEnd = this.onDragEnd.bind(this);
this.focus = this.focus.bind(this);
};
render () {
@ -226,6 +226,7 @@ const CellObject = observer(class CellObject extends React.Component<I.Cell, Sta
let value: any[] = Relation.getArrayValue(record[relation.relationKey]);
value = value.map(id => detailStore.get(subId, id, []));
value = value.filter(it => !it._empty_);
return value;
};

View file

@ -328,6 +328,8 @@ const Controls = observer(class Controls extends React.Component<Props> {
type: I.ViewType.Grid,
groupRelationKey: view.groupRelationKey || Relation.getGroupOption(rootId, block.id, view.type, '')?.id,
cardSize: view.cardSize || I.CardSize.Medium,
filters: [],
sorts: [],
};
C.BlockDataviewViewCreate(rootId, block.id, newView, sources, (message: any) => {

View file

@ -80,7 +80,9 @@ const Item = observer(class Item extends React.Component<Props> {
ref={node => this.node = node}
className={cn.join(' ')}
>
<div className="number">{d}</div>
<div className="number">
<div className="inner">{d}</div>
</div>
<div className="items">
{slice.map((item, i) => (
<Item key={[ y, m, d, item.id ].join('-')} {...item} />

View file

@ -357,6 +357,9 @@ const BlockLink = observer(class BlockLink extends React.Component<I.BlockCompon
const icon = node.find('.iconObject');
const rect = (node.get(0) as Element).getBoundingClientRect();
const mw = getWrapperWidth();
const name = node.find('.cardName');
UtilCommon.textStyle(name, { border: 0.4 });
icon.length ? card.addClass('withIcon') : card.removeClass('withIcon');
rect.width <= mw / 2 ? card.addClass('vertical') : card.removeClass('vertical');

View file

@ -320,9 +320,7 @@ const BlockText = observer(class BlockText extends React.Component<Props> {
return;
};
items.each((i: number, item) => {
this.textStyle($(item));
});
items.each((i: number, item) => this.textStyle($(item)));
items.off('mouseenter.link');
items.on('mouseenter.link', e => {

View file

@ -90,15 +90,13 @@ class DragLayer extends React.Component<object, State> {
const node = $(this.node);
const inner = node.find('#inner').html('');
const container = UtilCommon.getPageContainer(keyboard.isPopup());
const wrap = $('<div></div>');
let items: any[] = [];
switch (type) {
case I.DropType.Block: {
wrap.addClass('blocks');
items = ids.map(id => blockStore.getLeaf(rootId, id)).filter(it => it).map(it => new M.Block(UtilCommon.objectCopy(it)));
const items = ids.map(id => blockStore.getLeaf(rootId, id)).filter(it => it).map(it => new M.Block(UtilCommon.objectCopy(it)));
items.forEach(block => {
const clone = container.find(`#block-${block.id}`).clone();
@ -122,7 +120,7 @@ class DragLayer extends React.Component<object, State> {
wrap.addClass('menus').append(add);
items = ids.map(relationKey => dbStore.getRelationByKey(relationKey)).filter(it => it);
const items = ids.map(relationKey => dbStore.getRelationByKey(relationKey)).filter(it => it);
items.forEach(item => {
const el = $(`#menuBlockRelationView #item-${item.id}`);
@ -148,11 +146,10 @@ class DragLayer extends React.Component<object, State> {
ids.forEach((id: string, idx: number) => {
const el = container.find(`#record-${id}`);
const margin = idx * 10;
const clone = el.clone().addClass('record');
view.append(clone);
clone.css({ marginLeft: margin, marginTop: margin, zIndex: (ids.length - idx), width: el.width() });
clone.css({ width: el.width() });
});
break;
};

View file

@ -837,9 +837,7 @@ const EditorPage = observer(class EditorPage extends React.Component<Props, Stat
};
if (range.from == range.to) {
keyboard.shortcut(`${cmd}+k`, e, () => {
keyboard.onSearchPopup();
});
keyboard.shortcut(`${cmd}+k`, e, () => keyboard.onSearchPopup('Shortcut'));
};
if (!isInsideTable && block.isText()) {

View file

@ -76,7 +76,7 @@ class Header extends React.Component<Props> {
};
onSearch () {
keyboard.onSearchPopup();
keyboard.onSearchPopup('Header');
};
onNavigation () {

View file

@ -56,7 +56,9 @@ const MenuCalendarDay = observer(class MenuCalendarDay extends React.Component<I
return (
<div className={cn.join(' ')}>
<div className="number">{d}</div>
<div className="number">
<div className="inner">{d}</div>
</div>
<div className="items">
{items.map((item, i) => (
<Item key={i} {...item} />

View file

@ -77,7 +77,7 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
switch (relation.format) {
case I.RelationType.Tag:
case I.RelationType.Status:
case I.RelationType.Status: {
Item = (element: any) => {
return (
<div
@ -113,8 +113,9 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
</React.Fragment>
);
break;
};
case I.RelationType.Object:
case I.RelationType.Object: {
Item = (element: any) => {
const type = dbStore.getTypeById(element.type);
@ -150,8 +151,9 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
</React.Fragment>
);
break;
};
case I.RelationType.Checkbox:
case I.RelationType.Checkbox: {
value = (
<div className="item">
<Select
@ -160,13 +162,14 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
arrowClassName="light"
options={checkboxOptions}
value={item.value ? '1' : '0'}
onChange={(v: string) => { this.onChange('value', Boolean(Number(v)), true); }}
onChange={v => this.onChange('value', Boolean(Number(v)), true)}
/>
</div>
);
break;
};
case I.RelationType.Date:
case I.RelationType.Date: {
if ([ I.FilterQuickOption.NumberOfDaysAgo, I.FilterQuickOption.NumberOfDaysNow ].includes(item.quickOption)) {
value = (
<div key="filter-value-date-days" className="item">
@ -201,10 +204,10 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
);
onSubmit = (e: any) => { this.onSubmitDate(e); };
};
break;
};
default:
default: {
value = (
<div className="item">
<Input
@ -212,13 +215,29 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
value={item.value}
placeholder={translate('commonValue')}
onFocus={this.onFocusText}
onKeyUp={(e: any, v: string) => { this.onChange('value', v, true); }}
onSelect={(e: any) => { this.onSelect(e); }}
onKeyUp={(e: any, v: string) => this.onChange('value', v, true)}
onSelect={e => this.onSelect(e)}
/>
<Icon className="clear" onClick={this.onClear} />
</div>
);
break;
};
};
if (Relation.isDictionary(item.relationKey)) {
value = (
<div className="item">
<Select
id={[ 'filter', 'dictionary', item.id ].join('-')}
className="checkboxValue"
arrowClassName="light"
options={Relation.getDictionaryOptions(item.relationKey)}
value={item.value}
onChange={v => this.onChange('value', Number(v), true)}
/>
</div>
);
};
if ([ I.FilterCondition.None, I.FilterCondition.Empty, I.FilterCondition.NotEmpty ].includes(item.condition)) {
@ -333,12 +352,18 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
const relationOptions = this.getRelationOptions();
const relationOption: any = relationOptions.find(it => it.id == item.relationKey) || {};
const conditionOptions = Relation.filterConditionsByType(relation.format);
const conditionOption: any = conditionOptions.find(it => it.id == item.condition) || {};
const filterQuickOptions = Relation.filterQuickOptions(relation.format, item.condition);
const filterOption: any = filterQuickOptions.find(it => it.id == item.quickOption) || {};
let conditionOptions = [];
if (Relation.isDictionary(item.relationKey)) {
conditionOptions = Relation.filterConditionsDictionary();
} else {
conditionOptions = Relation.filterConditionsByType(relation.format);
};
const conditionOption: any = conditionOptions.find(it => it.id == item.condition) || {};
const ret: any[] = [
{ id: 'relation', icon: relationOption.icon, name: relationOption.name, arrow: true },
{ id: 'condition', icon: '', name: conditionOption.name, format: relation.format, arrow: true },
@ -352,7 +377,11 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
};
onOver (e: any, item: any) {
const { getId, getSize, setActive } = this.props;
const { getId, getSize, setActive, param } = this.props;
const { data } = param;
const { getView, itemId } = data;
const view = getView();
const filter = view.getFilter(itemId);
if (!keyboard.isMouseDisabled) {
setActive(item, false);
@ -369,7 +398,11 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
};
case 'condition': {
options = Relation.filterConditionsByType(item.format);
if (Relation.isDictionary(filter.relationKey)) {
options = Relation.filterConditionsDictionary();
} else {
options = Relation.filterConditionsByType(item.format);
};
break;
};

View file

@ -253,7 +253,7 @@ const MenuDataviewObjectList = observer(class MenuDataviewObjectList extends Rea
const { data } = param;
const { types, filter } = data;
const filters: I.Filter[] = [
{ operator: I.FilterOperator.And, relationKey: 'layout', condition: I.FilterCondition.NotIn, value: UtilObject.getSystemLayouts() }
{ operator: I.FilterOperator.And, relationKey: 'layout', condition: I.FilterCondition.NotIn, value: UtilObject.excludeFromSet() }
].concat(data.filters || []);
const sorts = [
{ relationKey: 'lastOpenedDate', type: I.SortType.Desc },

View file

@ -141,7 +141,7 @@ const MenuViewLayout = observer(class MenuViewLayout extends React.Component<I.M
save (withName?: boolean) {
const { param } = this.props;
const { data } = param;
const { rootId, blockId, onSave, readonly, getView } = data;
const { rootId, blockId, onSave, readonly } = data;
const block = blockStore.getLeaf(rootId, blockId);
if (readonly || !block) {
@ -172,6 +172,9 @@ const MenuViewLayout = observer(class MenuViewLayout extends React.Component<I.M
this.param.name = this.getViewName();
};
let view = data.view.get();
view = Object.assign(view, this.param);
C.BlockDataviewViewUpdate(rootId, blockId, current.id, this.param, () => {
if (clearGroups) {
Dataview.groupUpdate(rootId, blockId, current.id, []);
@ -389,6 +392,8 @@ const MenuViewLayout = observer(class MenuViewLayout extends React.Component<I.M
};
getViewName (name?: string) {
console.log(name, this.param.name);
return (name || this.param.name || Dataview.defaultViewName(this.param.type)).trim();
};

View file

@ -1,12 +1,11 @@
import * as React from 'react';
import $ from 'jquery';
import arrayMove from 'array-move';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
import { AutoSizer, CellMeasurer, InfiniteLoader, List as VList, CellMeasurerCache } from 'react-virtualized';
import { Icon } from 'Component';
import { I, C, UtilCommon, keyboard, Relation, analytics, UtilObject, translate, UtilMenu } from 'Lib';
import { I, C, UtilCommon, keyboard, Relation, analytics, UtilObject, translate, UtilMenu, Dataview } from 'Lib';
import { menuStore, dbStore, blockStore } from 'Store';
import Constant from 'json/constant.json';
@ -217,35 +216,21 @@ const MenuViewList = observer(class MenuViewList extends React.Component<I.Menu>
};
onAdd () {
const { param, getId, getSize, close } = this.props;
const { param, close } = this.props;
const { data } = param;
const { rootId, blockId, getView, loadData, getSources, isInline, getTarget, onViewSwitch } = data;
const { rootId, blockId, getView, getSources, isInline, getTarget, onViewSwitch } = data;
const view = getView();
const sources = getSources();
const relations = UtilCommon.objectCopy(view.relations);
const filters: I.Filter[] = [];
const allowed = blockStore.checkFlags(rootId, blockId, [ I.RestrictionDataview.View ]);
const object = getTarget();
for (const relation of relations) {
if (relation.isHidden || !relation.isVisible) {
continue;
};
filters.push({
relationKey: relation.relationKey,
operator: I.FilterOperator.And,
condition: I.FilterCondition.None,
value: null,
});
};
const newView = {
name: '',
name: Dataview.defaultViewName(I.ViewType.Grid),
type: I.ViewType.Grid,
groupRelationKey: Relation.getGroupOption(rootId, blockId, view.type, '')?.id,
filters,
cardSize: I.CardSize.Medium,
filters,
sorts: [],
};
C.BlockDataviewViewCreate(rootId, blockId, newView, sources, (message: any) => {
@ -256,9 +241,7 @@ const MenuViewList = observer(class MenuViewList extends React.Component<I.Menu>
const view = dbStore.getView(rootId, blockId, message.viewId);
close();
window.setTimeout(() => {
onViewSwitch(view);
}, Constant.delay.menu);
window.setTimeout(() => onViewSwitch(view), Constant.delay.menu);
analytics.event('AddView', {
type: view.type,

View file

@ -218,6 +218,9 @@ const MenuViewSettings = observer(class MenuViewSettings extends React.Component
this.param.name = this.getViewName();
};
let view = data.view.get();
view = Object.assign(view, this.param);
C.BlockDataviewViewUpdate(rootId, blockId, current.id, this.param, onSave);
};

View file

@ -84,7 +84,7 @@ const MenuGraphSettings = observer(class MenuGraphSettings extends React.Compone
};
getSections (): any[] {
const { graph } = commonStore;
const { graph, config } = commonStore;
let sections: any[] = [
{
@ -99,12 +99,13 @@ const MenuGraphSettings = observer(class MenuGraphSettings extends React.Compone
{ id: 'link', name: translate('menuGraphSettingsLinks') },
{ id: 'relation', name: translate('menuGraphSettingsRelations') },
{ id: 'orphan', name: translate('menuGraphSettingsUnlinkedObjects') },
config.experimental ? { id: 'local', name: translate('menuGraphSettingsLocal') } : null,
]
}
];
sections = sections.map(s => {
s.children = s.children.map(c => {
s.children = s.children.filter(it => it).map(c => {
c.switchValue = graph[c.id];
c.withSwitch = true;
c.onSwitch = (e: any, v: boolean) => { this.onClick(e, c); };

View file

@ -23,7 +23,15 @@ const MenuItemFilter = observer(class MenuItemFilter extends React.Component<Pro
render () {
const { id, index, relation, condition, quickOption, subId, readonly, style, onOver, onClick, onRemove } = this.props;
const conditionOptions = Relation.filterConditionsByType(relation.format);
const isDictionary = Relation.isDictionary(relation.relationKey);
let conditionOptions = [];
if (isDictionary) {
conditionOptions = Relation.filterConditionsDictionary();
} else {
conditionOptions = Relation.filterConditionsByType(relation.format);
};
const conditionOption: any = conditionOptions.find(it => it.id == condition) || {};
const filterOptions = Relation.filterQuickOptions(relation.format, conditionOption.id);
const filterOption: any = filterOptions.find(it => it.id == quickOption) || {};
@ -124,6 +132,15 @@ const MenuItemFilter = observer(class MenuItemFilter extends React.Component<Pro
};
};
if (isDictionary) {
const options = Relation.getDictionaryOptions(relation.relationKey);
const option = options.find(it => it.id == v);
if (option) {
v = option.name;
};
};
if ([ I.FilterCondition.None, I.FilterCondition.Empty, I.FilterCondition.NotEmpty ].includes(condition)) {
v = null;
};

View file

@ -226,12 +226,6 @@ const MenuOnboarding = observer(class MenuSelect extends React.Component<I.Menu,
break;
};
case 'dashboard': {
close();
UtilObject.openHome('route');
break;
};
case 'changeType':
menuStore.open('typeSuggest', {
element: `#${getId()}`,

View file

@ -95,7 +95,7 @@ const Page = observer(class Page extends React.Component<I.PageComponent> {
} else {
content = (
<div className="pageFlex">
<Sidebar {...this.props} />
<Sidebar key="sidebar" {...this.props} />
<div id="sidebarDummyLeft" className="sidebarDummy left" />
{wrap}
<div id="sidebarDummyRight" className="sidebarDummy right" />
@ -155,8 +155,7 @@ const Page = observer(class Page extends React.Component<I.PageComponent> {
const { account } = authStore;
const { isPopup } = this.props;
const match = this.getMatch();
const param = this.getMatchParams();
const { page, action, spaceId } = this.getMatchParams();
const { page, action } = this.getMatchParams();
const isIndex = this.isIndex();
const isAuth = this.isAuth();
const isMain = this.isMain();
@ -224,7 +223,7 @@ const Page = observer(class Page extends React.Component<I.PageComponent> {
const { id } = this.getMatchParams();
const isPopup = keyboard.isPopup();
if (!home || !id || (home.id != id) || isPopup || Storage.getOnboarding('dashboard')) {
if (!home || !id || (home.id != id) || isPopup) {
return;
};
@ -232,7 +231,12 @@ const Page = observer(class Page extends React.Component<I.PageComponent> {
return;
};
Onboarding.start('dashboard', false, false);
if (!Onboarding.isCompleted('dashboard')) {
Onboarding.start('dashboard', false, false);
} else
if (!Onboarding.isCompleted('navigation') && !$('#navigationPanel').hasClass('hide')) {
Onboarding.start('navigation', false, false);
};
};
unbind () {

View file

@ -108,7 +108,7 @@ const PageMainNavigation = observer(class PageMainNavigation extends React.Compo
const { name, description, layout, snippet, coverType, coverId, coverX, coverY, coverScale } = item;
return (
<div id={'item-' + item.id} className="selected">
<div id={'item-' + item.id} className="item selected">
<IconObject object={item} forceLetter={true} size={48} />
<ObjectName object={item} />
<ObjectDescription object={item} />
@ -116,7 +116,7 @@ const PageMainNavigation = observer(class PageMainNavigation extends React.Compo
{coverId && coverType ? <Cover type={coverType} id={coverId} image={coverId} className={coverId} x={coverX} y={coverY} scale={coverScale} withScale={true} /> : ''}
<div className="buttons">
<Button text={translate('popupNavigationOpen')} className="c36" onClick={(e: any) => { this.onConfirm(e, item); }} />
<Button text={translate('popupNavigationOpen')} className="c36" onClick={e => this.onConfirm(e, item)} />
{isPopup ? <Button text={translate('popupNavigationCancel')} className="c36" color="blank" onClick={() => { popupStore.close('page'); }} /> : ''}
</div>
</div>
@ -344,16 +344,10 @@ const PageMainNavigation = observer(class PageMainNavigation extends React.Compo
this.setActive();
});
keyboard.shortcut('enter, space', e, (pressed: string) => {
keyboard.shortcut('enter, space', e, () => {
const item = items[this.n];
if (!item) {
return;
};
if (this.panel == Panel.Center) {
this.onConfirm(e, item);
} else {
this.loadPage(item.id);
if (item) {
UtilObject.openAuto({ ...item, layout: I.ObjectLayout.Navigation });
};
});
};
@ -426,13 +420,11 @@ const PageMainNavigation = observer(class PageMainNavigation extends React.Compo
return;
};
let pagesIn = message.object.links.inbound.map(this.getPage);
let pagesOut = message.object.links.outbound.map(this.getPage);
pagesIn = pagesIn.filter(this.filterMapper);
pagesOut = pagesOut.filter(this.filterMapper);
const pagesIn = message.object.links.inbound.map(this.getPage).filter(this.filterMapper);
const pagesOut = message.object.links.outbound.map(this.getPage).filter(this.filterMapper);
this.panel = Panel.Center;
this.setState({
loading: false,
info: this.getPage(message.object.info),

View file

@ -174,6 +174,10 @@ const PopupSearch = observer(class PopupSearch extends React.Component<I.Popup,
};
componentDidMount () {
const { param } = this.props;
const { data } = param;
const { route } = data;
this._isMounted = true;
this.n = -1;
@ -182,6 +186,8 @@ const PopupSearch = observer(class PopupSearch extends React.Component<I.Popup,
this.resize();
focus.clear(true);
analytics.event('ScreenSearch', { route });
};
componentDidUpdate () {

View file

@ -295,7 +295,6 @@ const SelectionProvider = observer(class SelectionProvider extends React.Compone
this.hide();
this.setIsSelecting(false);
this.cache.clear();
this.focused = '';
this.range = null;
@ -337,7 +336,11 @@ const SelectionProvider = observer(class SelectionProvider extends React.Compone
};
};
cacheRect (node: any) {
cacheRect (node: any): { x: number; y: number; width: number; height: number; } {
if (!node.id) {
return { x: 0, y: 0, width: 0, height: 0 };
};
let cached = this.cache.get(node.id);
if (cached) {
return cached;

View file

@ -83,7 +83,7 @@ const Graph = observer(class Graph extends React.Component<Props> {
this.unbind();
win.on('updateGraphSettings.graph', () => { this.updateSettings(); });
win.on('updateGraphRoot.graph', (e: any, data: any) => { this.setRootId(data.id); });
win.on('updateGraphRoot.graph', (e: any, data: any) => this.setRootId(data.id));
win.on('updateTheme.graph', () => { this.send('updateTheme', { theme: commonStore.getThemeClass() }); });
};
@ -138,8 +138,14 @@ const Graph = observer(class Graph extends React.Component<Props> {
.call(this.zoom)
.call(this.zoom.transform, d3.zoomIdentity.translate(0, 0).scale(1.5))
.on('click', (e: any) => {
const { local } = commonStore.graph;
const [ x, y ] = d3.pointer(e);
this.send(e.shiftKey ? 'onSelect' : 'onClick', { x, y });
if (local) {
this.send('onSetRootId', { x, y });
} else {
this.send(e.shiftKey ? 'onSelect' : 'onClick', { x, y });
};
})
.on('dblclick', (e: any) => {
if (e.shiftKey) {
@ -464,7 +470,7 @@ const Graph = observer(class Graph extends React.Component<Props> {
};
setRootId (id: string) {
this.send('onSetRootId', { rootId: id });
this.send('setRootId', { rootId: id });
};
send (id: string, param: any, transfer?: any[]) {

View file

@ -125,7 +125,7 @@ class Navigation extends React.Component {
};
onSearch () {
keyboard.onSearchPopup();
keyboard.onSearchPopup('Navigation');
};
onProfile () {

View file

@ -72,7 +72,7 @@ const Progress = observer(class Progress extends React.Component {
node.addClass('hide');
win.off('resize.progress');
window.setTimeout(() => { commonStore.progressClear(); }, 200);
window.setTimeout(() => commonStore.progressClear(), 200);
};
};
@ -87,23 +87,6 @@ const Progress = observer(class Progress extends React.Component {
C.ProcessCancel(id);
};
resize () {
if (!this._isMounted) {
return;
};
const node = $(this.node);
const coords = Storage.get('progress');
this.obj = node.find('#inner');
this.height = this.obj.outerHeight();
this.width = this.obj.outerWidth();
if (coords) {
this.setStyle(coords.x, coords.y);
};
};
onDragStart (e: any) {
const win = $(window);
const offset = this.obj.offset();
@ -148,11 +131,30 @@ const Progress = observer(class Progress extends React.Component {
return { x, y };
};
resize () {
if (!this._isMounted) {
return;
};
const node = $(this.node);
const coords = Storage.get('progress');
this.obj = node.find('#inner');
this.height = this.obj.outerHeight();
this.width = this.obj.outerWidth();
if (coords) {
this.setStyle(coords.x, coords.y);
};
};
setStyle (x: number, y: number) {
const coords = this.checkCoords(x, y);
this.obj.css({ margin: 0, left: coords.x, top: coords.y });
Storage.set('progress', coords);
if ((coords.x !== null) && (coords.y !== null)) {
this.obj.css({ margin: 0, left: coords.x, top: coords.y });
Storage.set('progress', coords, true);
};
};
});

View file

@ -403,7 +403,7 @@ const WidgetIndex = observer(class WidgetIndex extends React.Component<Props> {
};
case Constant.widgetId.recentEdit: {
filters.push({ operator: I.FilterOperator.And, relationKey: 'lastModifiedDate', condition: I.FilterCondition.Greater, value: space.createdDate });
filters.push({ operator: I.FilterOperator.And, relationKey: 'lastModifiedDate', condition: I.FilterCondition.Greater, value: space.createdDate + 3 });
break;
};

View file

@ -5,15 +5,9 @@ export default {
category: translate('onboardingMainGraph'),
items: [
{
description: `
<p>${translate('onboardingMainGraph11')}</p>
<p>${translate('onboardingMainGraph12')}</p>
`,
description: translate('onboardingMainGraph11'),
video: './img/help/onboarding/space.mp4',
noButton: true,
buttons: [
{ text: translate('commonNext'), action: 'dashboard' },
],
buttonText: translate('commonFinish'),
}
],
@ -185,31 +179,19 @@ export default {
category: translate('onboardingDashboard'),
showConfetti: true,
onComplete: (force: boolean) => {
Onboarding.start('navigation', keyboard.isPopup(), force);
if (!$('#navigationPanel').hasClass('hide')) {
Onboarding.start('navigation', keyboard.isPopup(), force);
};
},
items: [
{
description: `
<p>${translate('onboardingDashboard11')}</p>
<p>${translate('onboardingDashboard12')}</p>
<p>${translate('onboardingDashboard13')}</p>
`,
video: './img/help/onboarding/homepage.mp4',
},
{
description: `
<p>${translate('onboardingDashboard21')}</p>
<p>${translate('onboardingDashboard22')}</p>
<p>${translate('onboardingDashboard23')}</p>
`,
video: './img/help/onboarding/sets.mp4',
},
{
description: `
<p>${translate('onboardingDashboard31')}</p>
<p>${translate('onboardingDashboard32')}</p>
`,
video: './img/help/onboarding/objects.mp4',
},
{
description: `
<p>${translate('onboardingDashboard41')}</p>

View file

@ -28,7 +28,6 @@ export default [
video('./img/help/36/1.mp4', 'c70'),
text(`Spaces were first introduced in June of this year as a container for your graph of objects. From today's release onwards, you'll be able to level up your space game by creating separate spaces, each with their own graph of objects, widget sidebar, and eventually - privacy settings.`),
text(`Simply click your profile picture to create new spaces, or navigate between existing ones. Use the space management menu at the top of your sidebar to customize your space settings or delete your space. For now, your account is limited to 10 spaces.`),
img('./img/help/36/2.png', 'c70'),
h3(`Calendar View for Sets & Collections`),
video('./img/help/36/3.mp4', 'c70'),

View file

@ -391,9 +391,7 @@ class Analytics {
popupMapper (params: any): string {
const { id } = params;
const map = {
search: 'ScreenSearch',
};
const map = {};
return map[id] || '';
};

View file

@ -92,7 +92,7 @@ const WalletCloseSession = (token: string, callBack?: (message: any) => void) =>
const WorkspaceCreate = (details: any, usecase: I.Usecase, callBack?: (message: any) => void) => {
const request = new Rpc.Workspace.Create.Request();
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
request.setUsecase(usecase as number);
dispatcher.request(WorkspaceCreate.name, request, callBack);
@ -127,7 +127,7 @@ const WorkspaceSetInfo = (spaceId:string, details: any, callBack?: (message: any
const request = new Rpc.Workspace.SetInfo.Request();
request.setSpaceid(spaceId);
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
dispatcher.request(WorkspaceSetInfo.name, request, callBack);
};
@ -391,7 +391,7 @@ const BlockSetFields = (contextId: string, blockId: string, fields: any, callBac
request.setContextid(contextId);
request.setBlockid(blockId);
request.setFields(Encode.encodeStruct(fields || {}));
request.setFields(Encode.struct(fields || {}));
dispatcher.request(BlockSetFields.name, request, callBack);
};
@ -579,9 +579,9 @@ const BlockLinkCreateWithObject = (contextId: string, targetId: string, details:
request.setContextid(contextId);
request.setTargetid(targetId);
request.setPosition(position as number);
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
request.setTemplateid(templateId);
request.setFields(Encode.encodeStruct(fields || {}));
request.setFields(Encode.struct(fields || {}));
request.setInternalflagsList(flags.map(Mapper.To.InternalFlag));
request.setObjecttypeuniquekey(typeKey);
request.setSpaceid(spaceId);
@ -1169,7 +1169,7 @@ const ObjectTypeRelationRemove = (objectTypeId: string, relationKeys: string[],
const ObjectCreate = (details: any, flags: I.ObjectFlag[], templateId: string, typeKey: string, spaceId: string, callBack?: (message: any) => void) => {
const request = new Rpc.Object.Create.Request();
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
request.setInternalflagsList(flags.map(Mapper.To.InternalFlag));
request.setTemplateid(templateId);
request.setSpaceid(spaceId);
@ -1182,7 +1182,7 @@ const ObjectCreateSet = (sources: string[], details: any, templateId: string, sp
const request = new Rpc.Object.CreateSet.Request();
request.setSourceList(sources);
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
request.setTemplateid(templateId);
request.setSpaceid(spaceId);
@ -1192,7 +1192,7 @@ const ObjectCreateSet = (sources: string[], details: any, templateId: string, sp
const ObjectCreateBookmark = (details: any, spaceId: string, callBack?: (message: any) => void) => {
const request = new Rpc.Object.CreateBookmark.Request();
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
request.setSpaceid(spaceId);
dispatcher.request(ObjectCreateBookmark.name, request, callBack);
@ -1201,7 +1201,7 @@ const ObjectCreateBookmark = (details: any, spaceId: string, callBack?: (message
const ObjectCreateObjectType = (details: any, flags: I.ObjectFlag[], spaceId: string, callBack?: (message: any) => void) => {
const request = new Rpc.Object.CreateObjectType.Request();
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
request.setInternalflagsList(flags.map(Mapper.To.InternalFlag));
request.setSpaceid(spaceId);
@ -1213,7 +1213,7 @@ const ObjectCreateRelation = (details: any, spaceId: string, callBack?: (message
const request = new Rpc.Object.CreateRelation.Request();
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
request.setSpaceid(spaceId);
dispatcher.request(ObjectCreateRelation.name, request, callBack);
@ -1222,7 +1222,7 @@ const ObjectCreateRelation = (details: any, spaceId: string, callBack?: (message
const ObjectCreateRelationOption = (details: any, spaceId: string, callBack?: (message: any) => void) => {
const request = new Rpc.Object.CreateRelation.Request();
request.setDetails(Encode.encodeStruct(details));
request.setDetails(Encode.struct(details));
request.setSpaceid(spaceId);
dispatcher.request(ObjectCreateRelationOption.name, request, callBack);

View file

@ -205,7 +205,7 @@ class Dispatcher {
};
case 'accountDetails': {
detailStore.update(Constant.subId.profile, { id: UtilObject.getIdentityId(), details: Decode.decodeStruct(data.getDetails()) }, false);
detailStore.update(Constant.subId.profile, { id: UtilObject.getIdentityId(), details: Decode.struct(data.getDetails()) }, false);
break;
};
@ -330,7 +330,7 @@ class Dispatcher {
break;
};
blockStore.update(rootId, id, { fields: data.hasFields() ? Decode.decodeStruct(data.getFields()) : {} });
blockStore.update(rootId, id, { fields: data.hasFields() ? Decode.struct(data.getFields()) : {} });
break;
};
@ -366,7 +366,7 @@ class Dispatcher {
};
if (data.hasFields()) {
block.content.fields = Decode.decodeStruct(data.getFields());
block.content.fields = Decode.struct(data.getFields());
};
blockStore.updateContent(rootId, id, block.content);
@ -862,7 +862,7 @@ class Dispatcher {
id = data.getId();
subIds = data.getSubidsList() || [];
block = blockStore.getLeaf(rootId, id);
details = Decode.decodeStruct(data.getDetails());
details = Decode.struct(data.getDetails());
this.detailsUpdate(details, rootId, id, subIds, true);
break;
@ -875,7 +875,7 @@ class Dispatcher {
details = {};
for (const item of (data.getDetailsList() || [])) {
details[item.getKey()] = Decode.decodeValue(item.getValue());
details[item.getKey()] = Decode.value(item.getValue());
};
this.detailsUpdate(details, rootId, id, subIds, false);
@ -1067,6 +1067,10 @@ class Dispatcher {
UtilRouter.switchSpace(authStore.accountSpaceId, '');
};
if (!rootId) {
return;
};
detailStore.update(rootId, { id, details }, clear);
const root = blockStore.getLeaf(rootId, id);

View file

@ -80,14 +80,14 @@ export const Mapper = {
ObjectInfo: (obj: any): I.PageInfo => {
return {
id: obj.getId(),
details: Decode.decodeStruct(obj.getDetails()),
details: Decode.struct(obj.getDetails()),
snippet: obj.getSnippet(),
hasInboundLinks: obj.getHasinboundlinks(),
};
},
Record: (obj: any): any => {
return Decode.decodeStruct(obj);
return Decode.struct(obj);
},
Range: (obj: any): I.TextRange => {
@ -119,7 +119,7 @@ export const Mapper = {
Details: (obj: any): any => {
return {
id: obj.getId(),
details: Decode.decodeStruct(obj.getDetails()),
details: Decode.struct(obj.getDetails()),
};
},
@ -251,7 +251,7 @@ export const Mapper = {
id: obj.getId(),
type: type,
childrenIds: obj.getChildrenidsList() || [],
fields: Decode.decodeStruct(obj.getFields()),
fields: Decode.struct(obj.getFields()),
hAlign: obj.getAlign(),
vAlign: obj.getVerticalalign(),
bgColor: obj.getBackgroundcolor(),
@ -330,7 +330,7 @@ export const Mapper = {
operator: obj.getOperator(),
condition: obj.getCondition(),
quickOption: obj.getQuickoption(),
value: obj.hasValue() ? Decode.decodeValue(obj.getValue()) : null,
value: obj.hasValue() ? Decode.value(obj.getValue()) : null,
};
},
@ -339,7 +339,7 @@ export const Mapper = {
id: obj.getId(),
relationKey: obj.getRelationkey(),
type: obj.getType(),
customOrder: (obj.getCustomorderList() || []).map(Decode.decodeValue),
customOrder: (obj.getCustomorderList() || []).map(Decode.value),
};
},
@ -507,7 +507,7 @@ export const Mapper = {
const item = new Rpc.Object.SetDetails.Detail();
item.setKey(obj.key);
item.setValue(Encode.encodeValue(obj.value));
item.setValue(Encode.value(obj.value));
return item;
},
@ -516,7 +516,7 @@ export const Mapper = {
const item = new Rpc.Block.ListSetFields.Request.BlockField();
item.setBlockid(obj.blockId);
item.setFields(Encode.encodeStruct(obj.fields || {}));
item.setFields(Encode.struct(obj.fields || {}));
return item;
},
@ -665,7 +665,7 @@ export const Mapper = {
};
if (obj.fields) {
block.setFields(Encode.encodeStruct(obj.fields || {}));
block.setFields(Encode.struct(obj.fields || {}));
};
const fb = UtilCommon.toCamelCase('set-' + obj.type.toLowerCase());
@ -702,7 +702,7 @@ export const Mapper = {
item.setOperator(obj.operator);
item.setCondition(obj.condition);
item.setQuickoption(obj.quickOption);
item.setValue(Encode.encodeValue(obj.value));
item.setValue(Encode.value(obj.value));
item.setIncludetime(obj.includeTime);
return item;
@ -714,7 +714,7 @@ export const Mapper = {
item.setId(obj.id);
item.setRelationkey(obj.relationKey);
item.setType(obj.type);
item.setCustomorderList((obj.customOrder || []).map(Encode.encodeValue));
item.setCustomorderList((obj.customOrder || []).map(Encode.value));
item.setFormat(obj.format);
item.setIncludetime(obj.includeTime);

View file

@ -111,28 +111,28 @@ export const WalletCreateSession = (response: Rpc.Wallet.CreateSession.Response)
export const ObjectCreate = (response: Rpc.Object.Create.Response) => {
return {
objectId: response.getObjectid(),
details: Decode.decodeStruct(response.getDetails()),
details: Decode.struct(response.getDetails()),
};
};
export const ObjectCreateSet = (response: Rpc.Object.CreateSet.Response) => {
return {
objectId: response.getObjectid(),
details: Decode.decodeStruct(response.getDetails()),
details: Decode.struct(response.getDetails()),
};
};
export const ObjectCreateBookmark = (response: Rpc.Object.CreateBookmark.Response) => {
return {
objectId: response.getObjectid(),
details: Decode.decodeStruct(response.getDetails()),
details: Decode.struct(response.getDetails()),
};
};
export const ObjectCreateObjectType = (response: Rpc.Object.CreateObjectType.Response) => {
return {
objectId: response.getObjectid(),
details: Decode.decodeStruct(response.getDetails()),
details: Decode.struct(response.getDetails()),
};
};
@ -140,14 +140,14 @@ export const ObjectCreateRelation = (response: Rpc.Object.CreateRelation.Respons
return {
objectId: response.getObjectid(),
relationKey: response.getKey(),
details: Decode.decodeStruct(response.getDetails()),
details: Decode.struct(response.getDetails()),
};
};
export const ObjectCreateRelationOption = (response: Rpc.Object.CreateRelationOption.Response) => {
return {
objectId: response.getObjectid(),
details: Decode.decodeStruct(response.getDetails()),
details: Decode.struct(response.getDetails()),
};
};
@ -165,7 +165,7 @@ export const ObjectShow = (response: Rpc.Object.Show.Response) => {
export const ObjectSearch = (response: Rpc.Object.Search.Response) => {
return {
records: (response.getRecordsList() || []).map(Decode.decodeStruct),
records: (response.getRecordsList() || []).map(Decode.struct),
};
};
@ -184,22 +184,22 @@ export const ObjectSearchSubscribe = (response: Rpc.Object.SearchSubscribe.Respo
nextCount: counters.getNextcount(),
prevCount: counters.getPrevcount(),
},
records: (response.getRecordsList() || []).map(Decode.decodeStruct),
dependencies: (response.getDependenciesList() || []).map(Decode.decodeStruct),
records: (response.getRecordsList() || []).map(Decode.struct),
dependencies: (response.getDependenciesList() || []).map(Decode.struct),
};
};
export const ObjectSubscribeIds = (response: Rpc.Object.SubscribeIds.Response) => {
return {
records: (response.getRecordsList() || []).map(Decode.decodeStruct),
dependencies: (response.getDependenciesList() || []).map(Decode.decodeStruct),
records: (response.getRecordsList() || []).map(Decode.struct),
dependencies: (response.getDependenciesList() || []).map(Decode.struct),
};
};
export const ObjectGraph = (response: Rpc.Object.Graph.Response) => {
return {
edges: (response.getEdgesList() || []).map(Mapper.From.GraphEdge),
nodes: (response.getNodesList() || []).map(Decode.decodeStruct),
nodes: (response.getNodesList() || []).map(Decode.struct),
};
};
@ -374,7 +374,7 @@ export const WorkspaceOpen = (response: Rpc.Workspace.Open.Response) => {
export const WorkspaceObjectAdd = (response: Rpc.Workspace.Object.Add.Response) => {
return {
objectId: response.getObjectid(),
details: Decode.decodeStruct(response.getDetails()),
details: Decode.struct(response.getDetails()),
};
};

View file

@ -1,32 +1,42 @@
import Struct from 'google-protobuf/google/protobuf/struct_pb.js';
const prepare = (o: any) => {
if (typeof o === 'undefined') {
o = null;
} else
if (typeof o === 'object') {
for (const k in o) {
if (typeof o[k] === 'object') {
o[k] = prepare(o[k]);
} else
if (typeof o[k] === 'undefined') {
o[k] = null;
};
};
};
return o;
};
export class Encode {
static encodeStruct (obj: any) {
if (typeof obj === 'undefined') {
obj = null;
};
return Struct.Struct.fromJavaScript(obj);
public static struct (obj: any) {
return Struct.Struct.fromJavaScript(prepare(obj));
};
static encodeValue (value: any) {
if (typeof value === 'undefined') {
value = null;
};
return Struct.Value.fromJavaScript(value);
public static value (value: any) {
return Struct.Value.fromJavaScript(prepare(value));
};
};
export class Decode {
static decodeValue (value: any) {
public static value (value: any) {
let data = null;
try { data = value ? value.toJavaScript() : null; } catch (e) { /**/ };
return data;
};
static decodeStruct (struct: any) {
public static struct (struct: any) {
let data = {};
try { data = struct ? struct.toJavaScript() : {}; } catch (e) { /**/ };
return data;

View file

@ -206,7 +206,7 @@ class Keyboard {
return;
};
this.onSearchPopup();
this.onSearchPopup('Shortcut');
});
this.shortcut(`${cmd}+l`, e, () => {
@ -698,6 +698,8 @@ class Keyboard {
if (clearTheme) {
UtilCommon.addBodyClass('theme', '');
};
$('#link-prism').remove();
focus.clearRange(true);
};
@ -764,9 +766,9 @@ class Keyboard {
}, Constant.delay.menu);
};
onSearchPopup () {
onSearchPopup (route: string) {
popupStore.open('search', {
data: { isPopup: this.isPopup() },
data: { isPopup: this.isPopup(), route },
});
};

View file

@ -99,6 +99,16 @@ class Relation {
return ret;
};
public filterConditionsDictionary () {
return [
{ id: I.FilterCondition.None, name: translate('filterConditionNone') },
{ id: I.FilterCondition.Equal, name: translate('filterConditionEqual') },
{ id: I.FilterCondition.NotEqual, name: translate('filterConditionNotEqual') },
{ id: I.FilterCondition.Empty, name: translate('filterConditionEmpty') },
{ id: I.FilterCondition.NotEmpty, name: translate('filterConditionNotEmpty') },
];
};
public filterQuickOptions (type: I.RelationType, condition: I.FilterCondition) {
if ([ I.FilterCondition.Empty, I.FilterCondition.NotEmpty ].includes(condition)) {
return [];
@ -263,7 +273,7 @@ class Relation {
case 'origin': {
value = Number(value) || I.ObjectOrigin.None;
return (value == I.ObjectOrigin.None) ? null : translate(`objectOrigin${value}`);
return (value == I.ObjectOrigin.None) ? null : translate(`origin${value}`);
};
};
return null;
@ -385,6 +395,24 @@ class Relation {
return options.map(it => ({ id: it, name: it }));
};
public getDictionaryOptions (relationKey: string) {
const options = [];
const dictionary = {
layout: I.ObjectLayout,
origin: I.ObjectOrigin,
};
const item = dictionary[relationKey];
if (item) {
const keys = Object.keys(item).filter(v => !isNaN(Number(v)));
keys.forEach((key, index) => {
options.push({ id: index, name: translate(`${relationKey}${index}`) });
});
};
return options;
};
public getStringValue (value: any) {
if ((typeof value === 'object') && value && UtilCommon.hasProperty(value, 'length')) {
return String(value.length ? value[0] : '');
@ -551,9 +579,17 @@ class Relation {
return this.systemKeys().filter(it => !skipKeys.includes(it));
};
isSystem (relationKey: string) {
isSystem (relationKey: string): boolean {
return this.systemKeys().includes(relationKey);
};
dictionaryKeys () {
return [ 'layout', 'origin' ];
};
isDictionary (relationKey: string): boolean {
return this.dictionaryKeys().includes(relationKey);
};
};

View file

@ -399,39 +399,37 @@ class UtilData {
const { withSet, withBookmark, withCollection, withDefault } = param || {};
const { space, config } = commonStore;
const pageLayouts = UtilObject.getPageLayouts();
const bookmark = dbStore.getTypeByKey(Constant.typeKey.bookmark);
const collection = dbStore.getTypeByKey(Constant.typeKey.collection);
const set = dbStore.getTypeByKey(Constant.typeKey.set);
const task = dbStore.getTypeByKey(Constant.typeKey.task);
const page = dbStore.getTypeByKey(Constant.typeKey.page);
const note = dbStore.getTypeByKey(Constant.typeKey.note);
let items: any[] = [];
if (!withDefault) {
const skipLayouts = [
I.ObjectLayout.Note,
I.ObjectLayout.Page,
I.ObjectLayout.Task,
I.ObjectLayout.Bookmark,
].concat(UtilObject.getSetLayouts());
const skipIds = [ bookmark, collection, set, task, page, note ].filter(it => it).map(it => it.id);
items = items.concat(dbStore.getTypes().filter(it => {
return pageLayouts.includes(it.recommendedLayout) && !skipLayouts.includes(it.recommendedLayout) && (it.spaceId == space);
return pageLayouts.includes(it.recommendedLayout) && !skipIds.includes(it.id) && (it.spaceId == space);
}));
items.sort(this.sortByName);
};
if (withBookmark) {
items.unshift(dbStore.getTypeByKey(Constant.typeKey.bookmark));
items.unshift(bookmark);
};
if (withCollection) {
items.unshift(dbStore.getTypeByKey(Constant.typeKey.collection));
items.unshift(collection);
};
if (withSet) {
items.unshift(dbStore.getTypeByKey(Constant.typeKey.set));
items.unshift(set);
};
items.unshift(dbStore.getTypeByKey(Constant.typeKey.task));
items.unshift(dbStore.getTypeByKey(Constant.typeKey.page));
items.unshift(dbStore.getTypeByKey(Constant.typeKey.note));
items = [ note, page, task ].concat(items);
items = items.filter(it => it);
if (!config.debug.ho) {

View file

@ -16,6 +16,7 @@ interface Graph {
label: boolean;
relation: boolean;
link: boolean;
local: boolean;
filter: string;
};
@ -64,6 +65,7 @@ class CommonStore {
label: true,
relation: true,
link: true,
local: false,
filter: '',
};

View file

@ -27,6 +27,11 @@ class DetailStore {
/** Idempotent. adds details to the detail store. */
public set (rootId: string, items: Item[]) {
if (!rootId) {
console.log('[detailStore].set: rootId is not defined');
return;
};
const map = observable.map(new Map());
for (const item of items) {
@ -52,7 +57,13 @@ class DetailStore {
/** Idempotent. updates details in the detail store. if clear is set, map wil delete details by item id. */
public update (rootId: string, item: Item, clear: boolean): void {
if (!rootId) {
console.log('[detailStore].update: rootId is not defined');
return;
};
if (!item.details) {
console.log('[detailStore].update: details are not defined');
return;
};