1
0
Fork 0
mirror of https://github.com/anyproto/anytype-ts.git synced 2025-06-08 05:57:02 +09:00
This commit is contained in:
Andrew Simachev 2024-03-11 17:33:24 +01:00
commit aa1a47a34e
No known key found for this signature in database
GPG key ID: 49A163D0D14E6FD8
108 changed files with 1590 additions and 1240 deletions

View file

@ -1,8 +1,8 @@
{
"manifest_version": 3,
"name": "Anytype Web Clipper",
"description": "Anytype is a next generation software that breaks down barriers between applications, gives back privacy and data ownership to users",
"version": "0.0.2",
"description": "Save web content to the Anytype — open, encrypted, and local-first application that connects everything as objects.",
"version": "0.0.3",
"icons": {
"16": "img/icon16x16.png",
"128": "img/icon128x128.png"

View file

@ -143,9 +143,10 @@ function createWindow () {
};
if (Api[cmd]) {
Api[cmd].apply(Api, [ win ].concat(args || []));
return Api[cmd].apply(Api, [ win ].concat(args || []));
} else {
console.error('[Api] method not defined:', cmd);
return null;
};
});
};

View file

@ -17,7 +17,6 @@ const KEYTAR_SERVICE = 'Anytype';
class Api {
account = null;
phrase = '';
isPinChecked = false;
appOnLoad (win) {
@ -35,7 +34,6 @@ class Api {
isChild: win.isChild,
route: win.route,
account: this.account,
phrase: this.phrase,
isPinChecked: this.isPinChecked,
languages: win.webContents.session.availableSpellCheckerLanguages,
css: String(css || ''),
@ -104,16 +102,12 @@ class Api {
keytarSet (win, key, value) {
if (key && value) {
this.phrase = value;
keytar.setPassword(KEYTAR_SERVICE, key, value);
};
};
keytarGet (win, key) {
keytar.getPassword(KEYTAR_SERVICE, key).then(value => {
this.phrase = value;
Util.send(win, 'keytarGet', key, value);
});
async keytarGet (win, key) {
return await keytar.getPassword(KEYTAR_SERVICE, key);
};
keytarDelete (win, key) {

View file

@ -22,6 +22,8 @@ class MenuManager {
const WindowManager = require('./window.js');
const UpdateManager = require('./update.js');
config.debug = config.debug || {};
const menuParam = [
{
label: 'Anytype',
@ -66,16 +68,6 @@ class MenuManager {
Separator,
{
label: Util.translate('electronMenuDebug'), submenu: [
{ label: Util.translate('electronMenuDebugSpace'), click: () => Util.send(this.win, 'commandGlobal', 'debugSpace') },
{ label: Util.translate('electronMenuDebugObject'), click: () => Util.send(this.win, 'commandGlobal', 'debugTree') },
{ label: Util.translate('electronMenuDebugProcess'), click: () => Util.send(this.win, 'commandGlobal', 'debugProcess') },
],
},
Separator,
{ role: 'close', label: Util.translate('electronMenuClose') },
]
},
@ -172,42 +164,48 @@ class MenuManager {
},
];
//if (config.allowDebug || config.allowBeta) {
config.debug = config.debug || {};
const flags = {
ui: Util.translate('electronMenuFlagInterface'),
ho: Util.translate('electronMenuFlagHidden'),
mw: Util.translate('electronMenuFlagMiddleware'),
th: Util.translate('electronMenuFlagThreads'),
fi: Util.translate('electronMenuFlagFiles'),
an: Util.translate('electronMenuFlagAnalytics'),
js: Util.translate('electronMenuFlagJson'),
};
const flagMenu = [];
const flags = {
ui: Util.translate('electronMenuFlagInterface'),
ho: Util.translate('electronMenuFlagHidden'),
mw: Util.translate('electronMenuFlagMiddleware'),
th: Util.translate('electronMenuFlagThreads'),
fi: Util.translate('electronMenuFlagFiles'),
an: Util.translate('electronMenuFlagAnalytics'),
js: Util.translate('electronMenuFlagJson'),
};
const flagMenu = [];
for (const i in flags) {
flagMenu.push({
label: flags[i], type: 'checkbox', checked: config.debug[i],
click: () => {
config.debug[i] = !config.debug[i];
Api.setConfig(this.win, { debug: config.debug });
if ([ 'ho' ].includes(i)) {
this.win.reload();
};
}
});
};
menuParam.push({
label: Util.translate('electronMenuDebug'),
submenu: [
{ label: Util.translate('electronMenuFlags'), submenu: flagMenu },
{ label: Util.translate('electronMenuDevTools'), accelerator: 'Alt+CmdOrCtrl+I', click: () => this.win.toggleDevTools() },
]
for (const i in flags) {
flagMenu.push({
label: flags[i], type: 'checkbox', checked: config.debug[i],
click: () => {
config.debug[i] = !config.debug[i];
Api.setConfig(this.win, { debug: config.debug });
if ([ 'ho' ].includes(i)) {
this.win.reload();
};
}
});
//};
};
menuParam.push({
label: Util.translate('electronMenuDebug'),
submenu: [
{ label: Util.translate('electronMenuFlags'), submenu: flagMenu },
Separator,
{ label: Util.translate('electronMenuDebugSpace'), click: () => Util.send(this.win, 'commandGlobal', 'debugSpace') },
{ label: Util.translate('electronMenuDebugObject'), click: () => Util.send(this.win, 'commandGlobal', 'debugTree') },
{ label: Util.translate('electronMenuDebugProcess'), click: () => Util.send(this.win, 'commandGlobal', 'debugProcess') },
{ label: Util.translate('electronMenuDebugStat'), click: () => Util.send(this.win, 'commandGlobal', 'debugStat') },
Separator,
{ label: Util.translate('electronMenuDevTools'), accelerator: 'Alt+CmdOrCtrl+I', click: () => this.win.toggleDevTools() },
]
});
const channels = ConfigManager.getChannels().map(it => {
it.click = () => {

View file

@ -53,6 +53,6 @@ contextBridge.exposeInMainWorld('Electron', {
cmd = String(cmd || '');
args = args || [];
ipcRenderer.invoke('Api', id, cmd, args);
return ipcRenderer.invoke('Api', id, cmd, args);
},
});

View file

@ -58,7 +58,6 @@ class WindowManager {
win = null;
});
win.once('ready-to-show', () => win.show());
win.on('focus', () => {
UpdateManager.setWindow(win);
MenuManager.setWindow(win);
@ -127,6 +126,8 @@ class WindowManager {
};
win.loadURL(is.development ? `http://localhost:${port}` : 'file://' + path.join(Util.appPath, 'dist', 'index.html'));
win.once('ready-to-show', () => win.show());
win.on('enter-full-screen', () => MenuManager.initMenu());
win.on('leave-full-screen', () => MenuManager.initMenu());
@ -147,12 +148,17 @@ class WindowManager {
win.loadURL('file://' + path.join(Util.appPath, 'dist', 'challenge', `index.html`));
win.setMenu(null);
win.showInactive();
win.webContents.once('did-finish-load', () => {
win.webContents.postMessage('challenge', options);
});
setTimeout(() => win.close(), 5000);
setTimeout(() => {
if (win && !win.isDestroyed()) {
win.close();
};
}, 30000);
return win;
};

View file

@ -165,6 +165,7 @@
"https://*.vimeo.com",
"https://w.soundcloud.com",
"https://*.google.com",
"https://miro.com",
"https://*.miro.com",
"https://*.figma.com",
"https://*.github.com",

View file

@ -26,6 +26,7 @@ window.isExtension = true;
window.Electron = {
currentWindow: () => ({}),
Api: () => {},
platform: '',
};
window.Anytype = {

View file

@ -6,7 +6,7 @@ import { RouteComponentProps } from 'react-router';
import { Provider } from 'mobx-react';
import { configure } from 'mobx';
import { ListMenu } from 'Component';
import { C, UtilRouter } from 'Lib';
import { C, UtilRouter, UtilData } from 'Lib';
import { commonStore, authStore, blockStore, detailStore, dbStore, menuStore, popupStore, extensionStore } from 'Store';
import Index from './iframe/index';
@ -111,11 +111,13 @@ class Iframe extends React.Component {
});
win.off('beforeunload').on('beforeunload', (e: any) => {
if (authStore.token) {
C.WalletCloseSession(authStore.token, () => {
authStore.tokenSet('');
});
if (!authStore.token) {
return;
};
UtilData.destroySubscriptions(() => {
C.WalletCloseSession(authStore.token, () => authStore.tokenSet(''));
});
});
};

View file

@ -98,10 +98,13 @@ const Create = observer(class Create extends React.Component<I.PageComponent, St
componentDidUpdate (): void {
this.initBlocks();
};
init () {
const spaces = dbStore.getSpaces().map(it => ({ ...it, id: it.targetSpaceId, object: it, iconSize: 16 })).filter(it => it);
const spaces = dbStore.getSpaces()
.filter(it => it && UtilObject.canParticipantWrite(it.targetSpaceId))
.map(it => ({ ...it, id: it.targetSpaceId, object: it, iconSize: 16 }));
if (this.refSpace && spaces.length) {
const space = commonStore.space || spaces[0].targetSpaceId;
@ -141,6 +144,9 @@ const Create = observer(class Create extends React.Component<I.PageComponent, St
blockStore.set(ROOT_ID, blocks);
blockStore.setStructure(ROOT_ID, structure);
blockStore.updateStructureParents(ROOT_ID);
blockStore.updateNumbers(ROOT_ID);
blockStore.updateMarkup(ROOT_ID);
this.forceUpdate();
});

View file

@ -50,13 +50,17 @@ class Util {
authorize (appKey: string, onSuccess?: () => void, onError?: (error) => void) {
authStore.appKeySet(appKey);
UtilData.createSession((message: any) => {
UtilData.createSession('', appKey, (message: any) => {
if (message.error.code) {
if (onError) {
onError(message.error);
};
return;
};
if (message.accountId) {
authStore.accountSet({ id: message.accountId });
};
if (onSuccess) {
onSuccess();

View file

@ -5,7 +5,7 @@ import { RouteComponentProps } from 'react-router';
import { Provider } from 'mobx-react';
import { configure } from 'mobx';
import { ListMenu } from 'Component';
import { UtilRouter, C } from 'Lib';
import { UtilRouter, C, UtilData } from 'Lib';
import { commonStore, authStore, blockStore, detailStore, dbStore, menuStore, popupStore, extensionStore } from 'Store';
import Extension from 'json/extension.json';
@ -97,11 +97,13 @@ class Popup extends React.Component {
});
win.off('beforeunload').on('beforeunload', (e: any) => {
if (authStore.token) {
C.WalletCloseSession(authStore.token, () => {
authStore.tokenSet('');
});
if (!authStore.token) {
return;
};
UtilData.destroySubscriptions(() => {
C.WalletCloseSession(authStore.token, () => authStore.tokenSet(''));
});
});
};

View file

@ -172,7 +172,7 @@ const Create = observer(class Create extends React.Component<I.PageComponent, St
this.initName();
this.initType();
this.setState({ withContent: Boolean(Number(Storage.get('withContent'))) });
this.setState({ withContent: Boolean(Storage.get('withContent')) });
});
};
@ -242,7 +242,9 @@ const Create = observer(class Create extends React.Component<I.PageComponent, St
};
getSpaces () {
return dbStore.getSpaces().map(it => ({ ...it, id: it.targetSpaceId, object: it })).filter(it => it)
return dbStore.getSpaces()
.filter(it => it && UtilObject.canParticipantWrite(it.targetSpaceId))
.map(it => ({ ...it, id: it.targetSpaceId, object: it }));
};
getTypes () {
@ -431,12 +433,14 @@ const Create = observer(class Create extends React.Component<I.PageComponent, St
if (message.error.code) {
this.setState({ error: message.error.description });
} else {
extensionStore.createdObject = message.details;
UtilRouter.go('/success', {});
return;
};
const object = message.details;
extensionStore.createdObject = object;
UtilRouter.go('/success', {});
this.isCreating = false;
});
};
@ -444,7 +448,7 @@ const Create = observer(class Create extends React.Component<I.PageComponent, St
onCheckbox () {
const { withContent } = this.state;
Storage.set('withContent', Number(!withContent));
Storage.set('withContent', !withContent);
this.setState({ withContent: !withContent });
};

View file

@ -60,6 +60,8 @@ const Index = observer(class Index extends React.Component<I.PageComponent, Stat
Util.init(response.ports[0], response.ports[1]);
this.login();
clearInterval(this.interval);
});
});
};

View file

@ -1 +1 @@
0.32.0
0.32.1

993
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,7 @@
"dist/img/**/*",
"dist/css/**/*",
"dist/js/**/*",
"dist/*.js",
"!dist/js/main.js.map",
"dist/anytypeHelper.exe",
"dist/anytypeHelper",

View file

@ -1,6 +1,6 @@
{
"name": "anytype",
"version": "0.38.30-beta",
"version": "0.39.1-alpha",
"description": "Anytype",
"main": "electron.js",
"scripts": {
@ -70,7 +70,7 @@
"license-checker": "^25.0.1",
"lint-staged": "^13.0.3",
"node-loader": "^1.0.2",
"npm": "^10.2.5",
"npm": "^10.5.0",
"npm-run-all": "^4.1.5",
"patch-package": "^6.4.7",
"sass": "^1.62.0",
@ -218,6 +218,7 @@
"dist/img/**/*",
"dist/css/**/*",
"dist/js/**/*",
"dist/*.js",
"!dist/js/main.js.map",
"dist/anytypeHelper.exe",
"dist/anytypeHelper",

View file

@ -1,11 +1,4 @@
<svg width="96" height="96" viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="96" height="96" fill="url(#paint0_linear_10786_37397)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M40 22V24H36V26H32V28H30V30H28V32H26V36H24V40H22V48V56H24V60H26V64H28V66H30V68H32V70H36V72H40V74H48H56V72H60V70H64V68H66V66H68V64H70V60H72V56H74V48V40H72V36H70V32H68V30H66V28H64V26H60V24H56V22H48H40ZM53 28V24H56V26H60V28H64V30H66V32H68V36H70V39H59V34H57V32H55V28H53ZM42 28V24H40V26H36V28H32V30H30V32H28V36H26V39H36V34H38V39H57V34H55V32H53V28H51V24H48H44V28H42ZM40 32H38V34H40V32ZM40 32H42V28H40V32ZM61 44V41H70V40H72V48V56H70V55H61V52H63V48V44H61ZM61 48V52H59V55H36V52H34V48V44H36V41H59V44H61V48ZM34 44H32V48V52H34V55H26V56H24V48V40H25V41H34V44ZM57 62H59V57H70V60H68V64H66V66H64V68H60V70H56V72H53V68H55V64H57V62ZM38 62V57H57V62H55V64H53V68H51V72H48H44V68H42V64H40V62H38ZM38 62V64H40V68H42V72H40V70H36V68H32V66H30V64H28V60H26V57H36V62H38Z" fill="black"/>
<defs>
<linearGradient id="paint0_linear_10786_37397" x1="48" y1="2.86102e-06" x2="96" y2="96" gradientUnits="userSpaceOnUse">
<stop offset="0.37125" stop-color="white"/>
<stop offset="0.67875" stop-color="#FBF1CD"/>
<stop offset="1" stop-color="#FFBEB0"/>
</linearGradient>
</defs>
<rect width="96" height="96" rx="8" fill="black"/>
<path opacity="0.9" fill-rule="evenodd" clip-rule="evenodd" d="M49.062 47.9995L65.8272 31.2343C67.803 33.671 68.2921 37.4877 67.0516 42.1116C65.7716 46.8825 62.7033 52.2209 58.073 57.0105L49.062 47.9995ZM69.1222 35.5732C74.535 44.759 73.4434 56.7176 65.8474 64.7849L59.1338 58.0713C66.2564 50.7117 69.9152 41.9847 69.1222 35.5732ZM66.251 29.4815L65.8549 29.0853L65.8479 29.0923C55.8402 19.6355 40.162 19.6352 30.154 29.0915L30.146 29.0835L29.0853 30.1441L29.0933 30.1521C19.6362 40.1601 19.6362 55.8389 29.0933 65.8469L29.0853 65.8549L29.6156 66.3851L30.146 66.9155L30.154 66.9075C40.162 76.3638 55.8402 76.3635 65.8479 66.9067L65.8549 66.9137L66.2493 66.5192C66.2948 66.4744 66.3401 66.4295 66.3853 66.3843C66.4304 66.3391 66.4754 66.2938 66.5202 66.2484L66.9155 65.853L66.9085 65.846C76.3645 55.8383 76.3645 40.1608 66.9085 30.153L66.9155 30.146L66.5185 29.7489C66.4743 29.7041 66.4299 29.6593 66.3853 29.6147C66.3406 29.5701 66.2959 29.5257 66.251 29.4815ZM64.7867 65.8456L58.0732 59.132C50.7144 66.2546 41.9882 69.914 35.5765 69.1226C44.7623 74.534 56.7201 73.4417 64.7867 65.8456ZM26.8781 60.4248C26.0864 54.013 29.7459 45.2865 36.8686 37.9275L30.1544 31.2132C22.558 39.2803 21.4659 51.2388 26.8781 60.4248ZM31.2151 30.1526L37.9293 36.8668C45.2892 29.744 54.0166 26.0852 60.4281 26.8785C51.2421 21.4649 39.2828 22.5563 31.2151 30.1526ZM48.0014 49.0602L57.0124 58.0712C52.2223 62.7025 46.8831 65.7714 42.1116 67.0516C37.4878 68.2921 33.671 67.803 31.2344 65.8272L48.0014 49.0602ZM46.9407 47.9995L30.1737 64.7665C28.1977 62.3298 27.7085 58.513 28.9491 53.889C30.2293 49.1175 33.2981 43.7784 37.9294 38.9883L46.9407 47.9995ZM48.0014 46.9388L38.9901 37.9276C43.7798 33.2973 49.1182 30.2291 53.889 28.9491C58.5131 27.7085 62.3299 28.1977 64.7665 30.1737L48.0014 46.9388Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

View file

@ -51,16 +51,16 @@
},
"fileExtension": {
"image": ["jpg", "jpeg", "png", "gif", "svg", "webp"],
"video": ["mp4", "m4v", "mov"],
"cover": ["jpg", "jpeg", "png"],
"audio": ["mp3", "m4a", "flac", "ogg", "wav"],
"pdf": ["pdf"],
"image": [ "jpg", "jpeg", "png", "gif", "svg", "webp" ],
"video": [ "mp4", "m4v", "mov" ],
"cover": [ "jpg", "jpeg", "png" ],
"audio": [ "mp3", "m4a", "flac", "ogg", "wav" ],
"pdf": [ "pdf" ],
"import": {
"1": ["zip", "md"],
"3": ["zip", "pb", "json"],
"4": ["zip", "html", "htm", "mhtml"],
"5": ["zip", "txt"]
"1": [ "zip", "md" ],
"3": [ "zip", "pb", "json" ],
"4": [ "zip", "html", "htm", "mhtml" ],
"5": [ "zip", "txt" ]
}
},
@ -92,7 +92,7 @@
"blockColor",
"blockBackground"
],
"add": ["searchObject", "blockRelationEdit", "typeSuggest"],
"add": [ "searchObject", "blockRelationEdit", "typeSuggest" ],
"action": [
"blockStyle",
"blockColor",
@ -102,8 +102,8 @@
"searchObject",
"typeSuggest"
],
"more": ["select", "searchObject", "blockAlign", "typeSuggest"],
"index": ["searchObject"],
"more": [ "select", "searchObject", "blockAlign", "typeSuggest" ],
"index": [ "searchObject" ],
"relationEdit": [
"select",
"searchObject",
@ -111,19 +111,19 @@
"dataviewObjectValues",
"dataviewObjectList"
],
"layout": ["blockAlign"],
"latex": ["previewLatex"],
"viewEdit": ["select"],
"featuredType": ["searchObject", "typeSuggest"],
"dataviewHead": ["dataviewSource", "searchObject"],
"store": ["typeSuggest", "relationSuggest"],
"widget": ["searchObject", "select"],
"dataviewTemplate": ["previewObject"],
"table": ["select2", "blockColor", "blockBackground"],
"navigation": ["quickCapture"]
"layout": [ "blockAlign" ],
"latex": [ "previewLatex" ],
"viewEdit": [ "select" ],
"featuredType": [ "searchObject", "typeSuggest" ],
"dataviewHead": [ "dataviewSource", "searchObject" ],
"store": [ "typeSuggest", "relationSuggest" ],
"widget": [ "searchObject", "select" ],
"dataviewTemplate": [ "previewObject" ],
"table": [ "select2", "blockColor", "blockBackground" ],
"navigation": [ "quickCapture", "space" ]
},
"popupPinIds": ["search"],
"popupPinIds": [ "search" ],
"defaultRelationKeys": [
"id",
@ -270,7 +270,6 @@
"pageCoverRelationKey": "pageCover",
"subId": {
"index": "index",
"search": "search",
"profile": "profile",
"deleted": "deleted",
@ -352,6 +351,10 @@
"default": 140
},
"menu": {
"border": 10
},
"dataview": {
"gallery": {
"width": 224,

View file

@ -125,6 +125,7 @@
"commonLanguage": "Language",
"commonSpelling": "Spelling",
"commonGallery": "Gallery",
"commonLeaveSpace": "Leave space",
"commonLCCollection": "Collection",
"commonLCSet": "Set",
@ -165,10 +166,12 @@
"electronMenuImport": "Import to Space",
"electronMenuExport": "Export Space",
"electronMenuSaveAs": "Export Object",
"electronMenuDebug": "Debug",
"electronMenuDebugSpace": "Space",
"electronMenuDebugObject": "Current Object",
"electronMenuDebugProcess": "Process",
"electronMenuDebugTree": "Tree diagnostics",
"electronMenuDebugStat": "Statistics",
"electronMenuClose": "Close Window",
"electronMenuEdit": "Edit",
"electronMenuUndo": "Undo",
@ -205,7 +208,6 @@
"electronMenuFlagFiles": "Files",
"electronMenuFlagAnalytics": "Analytics",
"electronMenuFlagJson": "JSON",
"electronMenuDebug": "Debug",
"electronMenuFlags": "Flags",
"electronMenuDevTools": "Dev Tools",
"electronMenuVersion": "Version",
@ -391,7 +393,8 @@
"pageMainImportTitle": "Downloading manifest",
"pageMainInviteTitle": "Downloading invite",
"pageMainInviteError": "Incorrect invite data",
"pageMainInviteErrorData": "Incorrect invite data",
"pageMainInviteErrorDuplicate": "You are joining or have already joined the %s space",
"pageAuthLoginInvalidPhrase": "Invalid Recovery Phrase",
@ -662,6 +665,7 @@
"popupSettingsSpacesListTitle": "Spaces",
"popupSettingsSpacesListSpace": "Space",
"popupSettingsSpacesCancelRequest": "Cancel request",
"popupSettingsSpacesListAccess": "Access",
"popupSettingsSpacesListSize": "Size",
"popupSettingsSpacesListNetwork": "Network",
@ -670,8 +674,10 @@
"popupSettingsDataManagementTitle": "Data management",
"popupSettingsDataManagementLocalStorageTitle": "Local storage",
"popupSettingsDataManagementLocalStorageText": "In order to save space on your local device, you can offload all your files to our encrypted backup node. The files will be loaded back when you open them.",
"popupSettingsDataManagementLocalStorageTextLocalOnly": "In order to save space on this device, you can remove all your files. Be careful: your client is in local-only mode, and data is not backing up to external nodes. Ensure that your files are synced to your other devices before removing them.",
"popupSettingsDataManagementLocalStorageUsage": "%s used",
"popupSettingsDataManagementOffloadFiles": "Offload files",
"popupSettingsDataManagementOffloadFilesLocalOnly": "Remove files from this device",
"popupSettingsDataManagementDeleteTitle": "Danger zone",
"popupSettingsDataManagementDeleteText": "Once you request your account to be deleted, you have 30 days to cancel this request. After 30 days, your encrypted account data is permanently removed from the backup node, you won't be able to sign into Anytype on new devices.",
"popupSettingsDataManagementDeleteButton": "Delete account",
@ -775,11 +781,6 @@
"popupConfirmSpaceShareMoreInfoTitle": "How to share a space?",
"popupConfirmSpaceShareMoreInfoText": "<ul><li>Please provide the link to the person you'd like to collaborate with.</li><li>By clicking the link, a person requests to join the space.</li><li>After approving the request, you can choose the access rights for that person.</li></ul>",
"popupSettingsSpaceLeave": "Leave %s?",
"popupSettingsSpaceLeaveTitle": "Leave space",
"popupSettingsSpaceLeaveText": "You will no longer see the space and all files inside.<br \/>You could be back again via the invite link.",
"popupSettingsSpaceLeaveButton": "Yes, I want to leave",
"popupSettingsSpaceRemove": "Move %s to Bin?",
"popupSettingsSpaceRemoveTitle": "Move to Bin",
"popupSettingsSpaceRemoveText": "Members could no longer see any objects inside",
@ -792,7 +793,10 @@
"popupSettingsDataLocalFiles": "Local files",
"popupSettingsDataOffloadWarningTitle": "Are you sure?",
"popupSettingsDataOffloadWarningText": "All media files stored <b>in Anytype</b> will be deleted from your current device. They can be downloaded again from a backup node or another device.",
"popupSettingsDataOffloadWarningTextLocalOnly": "Be careful: your client is in local-only mode, and data is not backing up to external nodes. Ensure that your files are synced to your other devices before removing them.",
"popupSettingsDataFilesOffloaded": "Files offloaded",
"popupSettingsDataKeepFiles": "Keep files",
"popupSettingsDataRemoveFiles": "Remove files",
"popupSettingsDeleteTitle1": "1. You have 30 days to cancel account deletion",
"popupSettingsDeleteText1": "We're sorry to see you go. Once you request your account to be deleted, you have 30 days to cancel this request. After 30 days, your account data is permanently removed from the backup node, you won't be able to sign into Anytype on new devices.",
@ -1544,7 +1548,7 @@
"unsplashString": "Photo by %s on %s",
"templateBannner": "You are editing a template",
"deletedBanner": "This file is in the Bin and is shown in view mode",
"deletedBanner": "This Object is in the Bin and is shown in view mode",
"deletedBannerRestore": "Restore",
"selectTemplateBanner": "This type has templates",
"selectTemplateBannerWithNumber": "This type has %s %s",

View file

@ -48,6 +48,53 @@
--color-teal: #0fc8ba;
--color-lime: #5dd400;
--color-green: #57c600;
/* Font */
--font-size-9: 9px;
--line-height-9: 12px;
--letter-spacing-9: 0.14px;
--font-size-very-small: 11px;
--line-height-very-small: 18px;
--letter-spacing-very-small: 0.2px;
--font-size-small: 12px;
--line-height-small: 18px;
--letter-spacing-small: 0px;
--font-size-common: 14px;
--line-height-common: 22px;
--letter-spacing-common: -0.12px;
--font-size-paragraph: 16px;
--line-height-paragraph: 24px;
--letter-spacing-paragraph: -0.2px;
--font-size-title: 36px;
--line-height-title: 40px;
--letter-spacing-title: -0.64px;
--font-weight-title: 700;
--font-size-header1: 28px;
--line-height-header1: 32px;
--letter-spacing-header1: -0.56px;
--font-weight-header1: 700;
--font-size-header2: 22px;
--line-height-header2: 28px;
--letter-spacing-header2: -0.48px;
--font-weight-header2: 700;
--font-size-header3: 18px;
--line-height-header3: 26px;
--letter-spacing-header3: -0.28px;
--font-weight-header3: 700;
--font-size-description: 18px;
--line-height-description: 26px;
--letter-spacing-description: -0.28px;
}
$easeInQuint: cubic-bezier(0.22, 1, 0.36, 1);
@ -57,16 +104,41 @@ $transitionAllCommon: all $transitionCommon;
@mixin text-overflow { overflow: hidden; text-overflow: ellipsis; }
@mixin text-overflow-nw { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@mixin text-9 { font-size: 9px; line-height: 12px; letter-spacing: 0.14px; }
@mixin text-very-small { font-size: 11px; line-height: 18px; letter-spacing: 0.2px; color: var(--color-control-active); }
@mixin text-small { font-size: 12px; line-height: 18px; letter-spacing: 0px; }
@mixin text-common { font-size: 14px; line-height: 22px; letter-spacing: -0.12px; }
@mixin text-paragraph { font-size: 16px; line-height: 24px; letter-spacing: -0.2px; }
@mixin text-title { font-size: 36px; line-height: 40px; letter-spacing: -0.64px; font-weight: 700; }
@mixin text-header1 { font-size: 28px; line-height: 32px; letter-spacing: -0.56px; font-weight: 700; }
@mixin text-header2 { font-size: 22px; line-height: 28px; letter-spacing: -0.48px; font-weight: 700; }
@mixin text-header3 { font-size: 18px; line-height: 26px; letter-spacing: -0.28px; font-weight: 700; }
@mixin text-description { font-size: 18px; line-height: 26px; letter-spacing: -0.28px; }
@mixin text-9 {
font-size: var(--font-size-9); line-height: var(--line-height-9); letter-spacing: var(--letter-spacing-9);
}
@mixin text-very-small {
font-size: var(--font-size-very-small); line-height: var(--line-height-very-small);
letter-spacing: var(--letter-spacing-very-small); color: var(--color-control-active);
}
@mixin text-small {
font-size: var(--font-size-small); line-height: var(--line-height-small); letter-spacing: var(--letter-spacing-small);
}
@mixin text-common {
font-size: var(--font-size-common); line-height: var(--line-height-common); letter-spacing: var(--letter-spacing-common);
}
@mixin text-paragraph {
font-size: var(--font-size-paragraph); line-height: var(--line-height-paragraph); letter-spacing: var(--letter-spacing-paragraph);
}
@mixin text-title {
font-size: var(--font-size-title); line-height: var(--line-height-title);
letter-spacing: var(--letter-spacing-title); font-weight: var(--font-weight-title);
}
@mixin text-header1 {
font-size: var(--font-size-header1); line-height: var(--letter-spacing-header1);
letter-spacing: var(--letter-spacing-header1); font-weight: var(--font-weight-header1);
}
@mixin text-header2 {
font-size: var(--font-size-header2); line-height: var(--line-height-header2);
letter-spacing: var(--letter-spacing-header2); font-weight: var(--font-weight-header2);
}
@mixin text-header3 {
font-size: var(--font-size-header3); line-height: var(--font-size-header3);
letter-spacing: var(--letter-spacing-header3); font-weight: var(--font-weight-header3);
}
@mixin text-description {
font-size: var(--font-size-description); line-height: var(--letter-spacing-description); letter-spacing: var(--letter-spacing-description);
}
@mixin pos-abs-mid { position: absolute; left: 50%; top: 50%; }

View file

@ -53,7 +53,7 @@
}
.btn {
font-weight: 500; font-size: 14px; height: 28px; line-height: 28px; display: inline-block;
font-weight: 500; font-size: var(--font-size-common); height: 28px; line-height: 28px; display: inline-block;
padding: 0px 8px; border-radius: 6px; margin-right: 8px; white-space: nowrap; transition: background $transitionCommon;
}
.btn:last-child { margin: 0px; }

View file

@ -63,10 +63,13 @@
.dataviewHead { display: flex; flex-direction: row; align-items: center; gap: 0px 2px; width: 100%; color: var(--color-text-primary); }
.dataviewHead {
.icon.source { width: 28px; height: 28px; background-size: 24px; background-image: url('~img/icon/dataview/button/source0.svg'); opacity: 0; }
.icon.source {
width: 28px; height: 28px; background-size: 24px; background-image: url('~img/icon/dataview/button/source0.svg'); opacity: 0;
flex-shrink: 0;
}
.icon.source.active { opacity: 1; }
.editableWrap { @include text-header2; height: 28px; max-width: calc(100% - 26px); @include text-overflow-nw; }
.editableWrap { @include text-header2; height: 28px; @include text-overflow-nw; }
.editableWrap.isEmpty { min-width: 90px; }
.editableWrap {
.editable { height: 100%; }
@ -85,7 +88,6 @@
.dataviewControls { font-weight: 500; color: var(--color-control-active); position: relative; }
.dataviewControls::after { content: ''; display: none; height: 1px; width: 100%; background: var(--color-shape-secondary); position: absolute; bottom: 0px; }
.dataviewControls.viewGrid::after, .dataviewControls.viewList::after { display: block; }
.dataviewControls {
@ -238,9 +240,10 @@
.dataviewEmpty { height: auto; padding: 48px 0px; border-top: 1px solid var(--color-shape-secondary); border-bottom: 1px solid var(--color-shape-secondary); }
.dataviewControls { margin: 0px 0px 8px 0px; }
.dataviewControls {
> .sides {
> .side { padding: 0px 0px 8px 0px; }
> .side { padding: 0px; }
> .side.left { display: flex; flex-direction: column; align-items: flex-start; gap: 4px 0px; }
> .side.right { transition: opacity $transitionCommon; opacity: 0; }
}

View file

@ -34,10 +34,7 @@
.cellContent.isName { @include text-paragraph; color: var(--color-text-primary); display: flex; gap: 0px 6px; position: relative; }
.cellContent.isName {
.iconObject { position: absolute; left: 0px; top: 0px; margin: 0px; cursor: default; }
.name {
line-height: 20px; font-size: 14px; font-weight: 500; letter-spacing: -0.12px;
vertical-align: top; white-space: normal; overflow: hidden; @include clamp2;
}
.name { @include text-common; line-height: 20px; font-weight: 500; vertical-align: top; white-space: normal; @include clamp2; }
}
.cellContent.isName.withIcon {

View file

@ -5,7 +5,7 @@
.block.blockFile.withContent { padding: 0px; }
.block.blockFile {
.loaderWrapper { border-radius: 4px; border: solid 1px var(--color-shape-primary); height: 48px; width: 100%; }
.error { margin: 0px; font-size: 12px; line-height: 24px; height: 24px; }
.error { margin: 0px; font-size: var(--font-size-small); line-height: 24px; height: 24px; }
.name {
min-width: 40px; height: 24px; line-height: 24px; display: inline-block; font-weight: 500;

View file

@ -138,15 +138,15 @@ search.active { background: orange !important; }
.textColor-lime { color: var(--color-lime) !important; }
.bgColor-grey { background: var(--color-shape-tertiary) !important; }
.bgColor-yellow { background: #fef9cc !important; }
.bgColor-orange { background: #fef3c5 !important; }
.bgColor-red { background: #ffebe5 !important; }
.bgColor-pink { background: #fee3f5 !important; }
.bgColor-purple { background: #f4e3fa !important; }
.bgColor-blue { background: #e4e7fc !important; }
.bgColor-ice { background: #d6effd !important; }
.bgColor-teal { background: #d6f5f3 !important; }
.bgColor-lime { background: #e3f7d0 !important; }
.bgColor-yellow { background: #fcf8d6 !important; }
.bgColor-orange { background: #fff2d7 !important; }
.bgColor-red { background: #fee7e0 !important; }
.bgColor-pink { background: #fbdff2 !important; }
.bgColor-purple { background: #f3e7f8 !important; }
.bgColor-blue { background: #e4e8fc !important; }
.bgColor-ice { background: #ddf1fc !important; }
.bgColor-teal { background: #d9f6f4 !important; }
.bgColor-lime { background: #e5f8d6 !important; }
.isMultiSelect.archive { color: var(--color-text-secondary); background: var(--color-shape-tertiary); }
.isMultiSelect.tagColor-default { color: var(--color-text-primary) !important; background: var(--color-bg-primary) !important; box-shadow: 0px 0px 0px 1px var(--color-shape-secondary) inset; }

View file

@ -42,7 +42,7 @@
}
.btn {
background: var(--color-bg-primary); font-weight: 500; font-size: 14px; color: var(--color-control-active); display: inline-block;
background: var(--color-bg-primary); font-weight: 500; font-size: var(--font-size-common); color: var(--color-control-active); display: inline-block;
transition: background $transitionCommon, color $transitionCommon; height: 28px; padding: 0px 8px 0px 6px; border-radius: 6px; display: flex;
flex-direction: row; align-items: center;
}

View file

@ -1,4 +1,4 @@
@import "~scss/_vars";
.error { color: var(--color-red); margin: 1em 0px; font-size: 14px; line-height: 22px; letter-spacing: 0.2px; word-break: break-word; user-select: text !important; }
.error { @include text-common; color: var(--color-red); margin: 1em 0px; word-break: break-word; user-select: text !important; }
.error:empty { display: none; }

View file

@ -1,14 +1,14 @@
@import "~scss/_vars";
.phraseWrapper {
border-radius: 24px; background: #17171799; width: 100%; position: relative; padding: 23px 48px;
font-size: 18px; line-height: 38px; transition: $transitionAllCommon; text-align: center; letter-spacing: -0.12px;
border-radius: 24px; width: 100%; position: relative; padding: 23px 48px; font-size: var(--font-size-header3); line-height: 38px;
transition: $transitionAllCommon; text-align: center; letter-spacing: -0.12px;
}
.phraseWrapper {
.phraseInnerWrapper { word-break: break-word; min-height: 38px; position: relative; z-index: 1; }
.word {
font-size: 18px; line-height: 18px; height: 18px; user-select: text !important; display: inline; margin: 10px; vertical-align: middle;
font-size: var(--font-size-header3); line-height: 18px; height: 18px; user-select: text !important; display: inline; margin: 10px; vertical-align: middle;
white-space: nowrap; text-transform: lowercase;
}
.word:empty { margin: 0px; }
@ -25,7 +25,7 @@
.placeholder { color: var(--color-text-tertiary); top: 0; display: flex; flex-direction: row; align-items: center; justify-content: center; }
#entry {
display: inline; font-size: 18px; line-height: 18px; height: 18px; -webkit-user-modify: read-write-plaintext-only; user-select: text;
display: inline; font-size: var(--font-size-header3); line-height: 18px; height: 18px; -webkit-user-modify: read-write-plaintext-only; user-select: text;
vertical-align: middle; margin-left: 10px; text-transform: lowercase;
}

View file

@ -2,10 +2,10 @@
.pin {
.input {
width: 40px; height: 40px; margin-right: 8px; padding: 0px; text-align: center; vertical-align: top; font-size: 18px;
width: 40px; height: 40px; margin-right: 8px; padding: 0px; text-align: center; vertical-align: top; font-size: var(--font-size-header3);
border: 1px solid var(--color-shape-primary); border-radius: 2px;
}
.input.isFocused { box-shadow: 0px 0px 0px 1px var(--color-system-accent-100) inset; border-color: var(--color-system-accent-100); }
.input-password { font-size: 14px; line-height: 1; }
.input-password { font-size: var(--font-size-common); line-height: 1; }
.input:last-child { margin: 0px; }
}

View file

@ -2,7 +2,7 @@
.menus {
.menu.menuBlockAdd, .menu.menuBlockStyle, .menu.menuBlockAction, .menu.menuBlockMore {
.item.empty { font-size: 12px; line-height: 18px; padding-top: 8px; }
.item.empty { @include text-small; padding-top: 8px; }
}
.menu.menuBlockAction { width: 240px; }

View file

@ -88,6 +88,10 @@
.cellContent.isName { display: flex; align-items: center; }
.cellContent.c-object {
.element { max-width: 150px; }
}
.cell {
padding: 5px 8px; border-radius: 4px; width: calc(100% - 236px); line-height: 22px; transition: background $transitionCommon;
position: relative; margin-right: 6px;

View file

@ -79,7 +79,7 @@
.item.withCaption { align-items: center; justify-content: space-between; }
.item {
.clickable { width: 100%; height: 20px; display: flex; }
.buttons { margin: 0px; position: absolute; right: 10px; top: 2px; }
.buttons { margin: 0px; position: absolute; right: 10px; top: 2px; display: none; }
.icon.delete { transition: none; }
.name { @include text-overflow-nw; width: calc(100% - 40px); }
@ -95,7 +95,7 @@
}
.item.empty { padding: 13px 16px; }
.item:hover, .item.hover {
.item:not(.isReadonly):hover, .item:not(.isReadonly).hover {
.clickable { margin-right: 6px; }
.caption { display: none; }
.buttons { display: block; }

View file

@ -16,7 +16,7 @@
.highlight {
background: var(--color-shape-secondary); white-space: nowrap; border-radius: 4px; padding: 2px 6px; color: var(--color-text-primary);
font-family: 'Plex'; font-weight: 400; font-size: 14px; line-height: 14px; letter-spacing: -0.12px;
font-family: 'Plex'; @include text-common; line-height: 14px;
}
a { color: var(--color-text-inversion); text-decoration: underline; }

View file

@ -18,7 +18,7 @@
.section { height: auto; padding: 0px; border: 0px; }
.section > .name { @include text-small; color: var(--color-text-secondary); padding: 4px 0px; margin: 0px 0px 4px 0px; width: 100%; flex-shrink: 0; }
.items { display: flex; gap: 0px 8px; }
.items { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.item {
position: relative; display: flex; flex-wrap: nowrap; height: 48px; align-items: center; gap: 0px 8px; padding: 0px 14px;
@ -46,10 +46,8 @@
.wrap { height: 312px; }
.sections { overflow-x: hidden; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px 0px; }
.items { flex-wrap: wrap; gap: 8px; }
.items { gap: 8px; justify-content: flex-start; }
.item { box-shadow: none; }
.item.isDefault {
border-color: var(--color-system-accent-100); box-shadow: 0px 0px 0px 1px var(--color-system-accent-100) inset !important;
}
.item.isDefault { border-color: var(--color-system-accent-100); box-shadow: 0px 0px 0px 1px var(--color-system-accent-100) inset !important; }
}
}

View file

@ -33,7 +33,7 @@ html.bodyIndex, html.bodyAuth {
#popupConfirm-innerWrap {
.content { text-align: left; }
h1 { font-size: 18px; margin-bottom: 16px; color: var(--color-text-primary) !important; }
h1 { font-size: var(--font-size-header3); margin-bottom: 16px; color: var(--color-text-primary) !important; }
b { display: block; font-weight: 700; color: var(--color-text-primary) !important; margin-bottom: 8px; }
p { margin-bottom: 8px; }
ul { list-style-position: inside; padding-left: 0.75em; margin-bottom: 8px; }
@ -75,6 +75,22 @@ html.bodyIndex, html.bodyAuth {
ul { list-style-position: inside; padding-left: 0.75em; }
}
/* Notifications */
.notifications {
@mixin shadow { box-shadow: 0px 4px 16px rgb(0 0 0 / 20%), 0px 0px 0px 1px #393933 inset; }
.head {
.icon { border-color: var(--color-bg-secondary); }
}
.notification { background: var(--color-bg-secondary); @include shadow; border: 0px; }
.notification {
.icon.delete { background-color: var(--color-bg-secondary); }
}
}
.loaderWrapper {
.loader { border-color: #555; border-left-color: var(--color-system-accent-100) !important; }
.dot { border-color: #fff; }
@ -149,7 +165,7 @@ html.bodyAuthDeleted {
.error { position: absolute; z-index: 1; width: 100%; left: 0px; top: 0px; transform: translateY(calc(-100% - 16px)); }
.title { margin: 0px 0px 20px 0px; }
.phraseWrapper { margin: 0px 0px 20px 0px; }
.phraseWrapper { margin: 0px 0px 20px 0px; background: var(--color-button-blank-hover); }
}
.pageAuthInvite {
@ -164,7 +180,7 @@ html.bodyAuthDeleted {
.pin {
.input {
width: 86px; height: 86px; border-radius: 24px; background: var(--color-input-opaque) !important; padding: 0px; text-align: center;
vertical-align: top; font-size: 18px; border-width: 2px; border-color: rgba(0,0,0,0);
vertical-align: top; font-size: var(--font-size-header3); border-width: 2px; border-color: rgba(0,0,0,0);
}
.input.active { box-shadow: 0px 0px; border-color: var(--color-system-accent-100) !important; }
}
@ -180,10 +196,6 @@ html.bodyAuthDeleted {
}
}
.pageAuthAccountSelect {
.frame { padding-bottom: 48px; }
}
.pageAuthOnboard, .pageAuthInvite, .pageAuthLogin, .pageAuthDeleted, .pageAuthSetup {
.frame { display: flex; flex-direction: column; align-items: center; }
.title { @include text-header3; color: var(--color-text-primary) !important; }
@ -219,8 +231,11 @@ html.bodyAuthDeleted {
}
.inputWrapper {
.input { border-radius: 26px; border: none !important; background: var(--color-input-opaque) !important; color: var(--color-text-primary) !important; font-size: 18px; padding: 36px 26px; width: 392px; height: auto; }
.input:hover { filter: brightness(1.2) }
.input {
border-radius: 26px; border: none !important; background: var(--color-input-opaque) !important; color: var(--color-text-primary) !important;
font-size: var(--font-size-header3); padding: 36px 26px; width: 392px; height: auto;
}
.input:hover { filter: brightness(1.2); }
.input::placeholder { color: var(--color-text-tertiary) !important; }
}
}

View file

@ -37,10 +37,7 @@
.tabs { white-space: nowrap; text-align: left; display: flex; flex-direction: row; gap: 0px 24px; }
.tabs {
.tab {
display: inline-block; font-weight: 700; font-size: 18px; line-height: 26px; letter-spacing: -0.16px;
color: var(--color-control-active); transition: $transitionAllCommon;
}
.tab { display: inline-block; @include text-header3; color: var(--color-control-active); transition: $transitionAllCommon; }
.tab:hover, .tab.active { color: var(--color-text-primary); }
}

View file

@ -136,7 +136,7 @@
.phraseWrapper { border-radius: 12px; background-color: var(--color-shape-tertiary); padding: 16px 44px; line-height: unset; }
.phraseWrapper {
.phraseInnerWrapper { min-height: unset; display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; word-break: unset; }
.word { font-size: 12px; line-height: 18px; font-weight: 500; margin: 0; }
.word { @include text-small; font-weight: 500; margin: 0; }
.bg { filter: blur(8px); opacity: 0.5; }
.icon { width: 28px; height: 28px; background-size: 20px; margin: 0px; top: 12px; right: 12px; border-radius: 6px; z-index: 1; }

View file

@ -11,7 +11,7 @@
.clickable { display: flex; flex-direction: row; align-items: center; gap: 0px 12px; flex-grow: 1; width: 100%; }
.clickable {
.iconObject { flex-shrink: 0; }
.name { @include text-paragraph; @include text-overflow-nw; line-height: 24px; font-weight: 600; flex-grow: 1; }
.name { @include text-paragraph; @include text-overflow-nw; font-weight: 600; flex-grow: 1; }
}
.iconWrap { width: 24px; height: 24px; border-radius: 4px; cursor: default; flex-shrink: 0; display: flex; align-items: center; justify-content: center; }

View file

@ -177,7 +177,6 @@ class App extends React.Component<object, State> {
super(props);
this.onInit = this.onInit.bind(this);
this.onKeytarGet = this.onKeytarGet.bind(this);
this.onPopup = this.onPopup.bind(this);
this.onUpdateCheck = this.onUpdateCheck.bind(this);
this.onUpdateConfirm = this.onUpdateConfirm.bind(this);
@ -261,7 +260,6 @@ class App extends React.Component<object, State> {
registerIpcEvents () {
Renderer.on('init', this.onInit);
Renderer.on('keytarGet', this.onKeytarGet);
Renderer.on('route', (e: any, route: string) => UtilRouter.go(route, {}));
Renderer.on('popup', this.onPopup);
Renderer.on('checking-for-update', this.onUpdateCheck);
@ -305,7 +303,7 @@ class App extends React.Component<object, State> {
};
onInit (e: any, data: any) {
const { dataPath, config, isDark, isChild, account, phrase, languages, isPinChecked, css } = data;
const { dataPath, config, isDark, isChild, account, languages, isPinChecked, css } = data;
const win = $(window);
const body = $('body');
const node = $(this.node);
@ -352,18 +350,18 @@ class App extends React.Component<object, State> {
if (accountId) {
if (isChild) {
authStore.phraseSet(phrase);
Renderer.send('keytarGet', accountId).then((phrase: string) => {
UtilData.createSession(phrase, '', () => {
keyboard.setPinChecked(isPinChecked);
commonStore.redirectSet(route);
UtilData.createSession(() => {
keyboard.setPinChecked(isPinChecked);
commonStore.redirectSet(route);
if (account) {
authStore.accountSet(account);
commonStore.configSet(account.config, false);
UtilData.onInfo(account.info);
UtilData.onAuth({}, cb);
};
if (account) {
authStore.accountSet(account);
commonStore.configSet(account.config, false);
UtilData.onInfo(account.info);
UtilData.onAuth({}, cb);
};
});
});
win.off('unload').on('unload', (e: any) => {
@ -380,8 +378,7 @@ class App extends React.Component<object, State> {
});
} else {
commonStore.redirectSet(route);
Renderer.send('keytarGet', accountId);
UtilRouter.go('/auth/setup/init', { replace: true });
cb();
};
} else {
@ -389,28 +386,6 @@ class App extends React.Component<object, State> {
};
};
onKeytarGet (e: any, key: string, value: string) {
const accountId = Storage.get('accountId');
const phrase = Storage.get('phrase');
if (!accountId || (key != accountId)) {
return;
};
if (phrase) {
value = phrase;
Renderer.send('keytarSet', accountId, phrase);
Storage.delete('phrase');
};
if (value) {
authStore.phraseSet(value);
UtilRouter.go('/auth/setup/init', { replace: true });
} else {
Storage.logout();
};
};
onPopup (e: any, id: string, param: any, close?: boolean) {
if (Constant.popupPinIds.includes(id) && !keyboard.isPinChecked) {
return;

View file

@ -833,15 +833,12 @@ const BlockDataview = observer(class BlockDataview extends React.Component<Props
});
};
canCellEdit (relationKey: string, recordId: string): boolean {
canCellEdit (relation: any, record: any): boolean {
const { readonly } = this.props;
if (readonly) {
return false;
};
const relation = dbStore.getRelationByKey(relationKey);
const record = this.getRecord(recordId);
if (!relation || !record || relation.isReadonlyValue || record.isReadonly) {
return false;
};

View file

@ -49,7 +49,7 @@ const Cell = observer(class Cell extends React.Component<Props> {
};
const id = Relation.cellId(idPrefix, relation.relationKey, record.id);
const canEdit = this.canCellEdit();
const canEdit = this.canCellEdit(relation, record);
const cn = [
'cellContent',
'c-' + relation.relationKey,
@ -159,8 +159,9 @@ const Cell = observer(class Cell extends React.Component<Props> {
const { config } = commonStore;
const cellId = Relation.cellId(idPrefix, relation.relationKey, record.id);
const value = record[relation.relationKey] || '';
const canEdit = this.canCellEdit(relation, record);
if (!this.canCellEdit()) {
if (!canEdit) {
if (Relation.isUrl(relation.format) && value) {
Renderer.send('urlOpen', Relation.getUrlScheme(relation.format, value) + value);
};
@ -485,15 +486,12 @@ const Cell = observer(class Cell extends React.Component<Props> {
return dbStore.getRelationByKey(this.props.relationKey);
};
canCellEdit (): boolean {
const { readonly, recordId, getRecord } = this.props;
canCellEdit (relation: any, record: any): boolean {
const { readonly } = this.props;
if (readonly) {
return false;
};
const record = getRecord(recordId);
const relation = this.getRelation();
if (!relation || !record || relation.isReadonlyValue || record.isReadonly) {
return false;
};

View file

@ -368,9 +368,13 @@ const Controls = observer(class Controls extends React.Component<Props> {
onViewContext (e: any, element: string, view: any) {
e.stopPropagation();
const { rootId, block } = this.props;
const { rootId, block, readonly } = this.props;
if (readonly) {
return;
};
const contextParam = {
this.onViewSet(view);
UtilMenu.viewContextMenu({
rootId,
blockId: block.id,
view,
@ -382,10 +386,7 @@ const Controls = observer(class Controls extends React.Component<Props> {
horizontal: I.MenuDirection.Center,
noFlipY: true,
}
};
this.onViewSet(view);
UtilMenu.viewContextMenu(contextParam);
});
};
onSortStart () {

View file

@ -18,7 +18,7 @@ interface Props {
onRef?(ref: any, id: string): void;
onCellClick?(e: any, key: string, id?: string): void;
onCellChange?(id: string, key: string, value: any, callBack?: (message: any) => void): void;
canCellEdit?(relationKey: string, recordId: string): boolean;
canCellEdit?(relation: any, recordId: any): boolean;
};
const BodyCell = observer(class BodyCell extends React.Component<Props> {
@ -41,7 +41,7 @@ const BodyCell = observer(class BodyCell extends React.Component<Props> {
const width = Relation.width(this.props.width, relation.format);
const size = Constant.size.dataview.cell;
const subId = dbStore.getSubId(rootId, block.id);
const canEdit = canCellEdit(relationKey, record.id);
const canEdit = canCellEdit(relation, record);
if (relationKey == 'name') {
cn.push('isName');

View file

@ -3,7 +3,6 @@ import * as ReactDOM from 'react-dom';
import $ from 'jquery';
import Prism from 'prismjs';
import raf from 'raf';
import mermaid from 'mermaid';
import { instance as viz } from '@viz-js/viz';
import DOMPurify from 'dompurify';
import { observer } from 'mobx-react';
@ -18,6 +17,7 @@ import 'excalidraw/dist/excalidraw.min.css';
const katex = require('katex');
const pako = require('pako');
const mermaid = require('mermaid').default;
require('katex/dist/contrib/mhchem');

View file

@ -58,7 +58,7 @@ const BlockLink = observer(class BlockLink extends React.Component<I.BlockCompon
className="loading"
{...UtilCommon.dataProps({ 'target-block-id': object.id })}
>
<Loader />
<Loader type="loader" />
<div className="name">{translate('blockLinkSyncing')}</div>
</div>
);

View file

@ -15,7 +15,8 @@ const SNAP = 10;
const BlockTable = observer(class BlockTable extends React.Component<I.BlockComponent> {
_isMounted = false;
node: any = null;
node = null;
refTable = null;
offsetX = 0;
cache: any = {};
scrollX = 0;
@ -81,7 +82,7 @@ const BlockTable = observer(class BlockTable extends React.Component<I.BlockComp
<div className="inner">
<div id="selectionFrameContainer" />
<div id="table" className="table">
<div ref={ref => this.refTable = ref} id="table" className="table">
<div className="rows">
{rows.map((row: any, i: number) => {
return (
@ -596,8 +597,7 @@ const BlockTable = observer(class BlockTable extends React.Component<I.BlockComp
this.onOptionsClose();
const node = $(this.node);
const table = node.find('#table');
const table = $(this.refTable);
switch (type) {
case I.BlockType.TableColumn: {
@ -635,8 +635,7 @@ const BlockTable = observer(class BlockTable extends React.Component<I.BlockComp
return;
};
const node = $(this.node);
const table = node.find('#table');
const table = $(this.refTable);
table.find('.isHighlightedColumn').removeClass('isHighlightedColumn isFirst isLast');
table.find('.isHighlightedRow').removeClass('isHighlightedRow');

View file

@ -804,7 +804,6 @@ const BlockText = observer(class BlockText extends React.Component<Props> {
e.preventDefault();
value = parsed.value;
this.marks = Mark.checkRanges(value, this.marks);
UtilData.blockSetText(rootId, block.id, value, this.marks, true, () => {
onKeyDown(e, value, this.marks, range, this.props);
});
@ -812,9 +811,11 @@ const BlockText = observer(class BlockText extends React.Component<Props> {
};
} else
if (!menuOpenAdd && !menuOpenMention && !range.to) {
const parsed = this.getMarksFromHtml();
if (block.canHaveMarks()) {
const { marks } = this.getMarksFromHtml();
this.marks = marks;
};
this.marks = Mark.checkRanges(value, parsed.marks);
UtilData.blockSetText(rootId, block.id, value, this.marks, true, () => {
onKeyDown(e, value, this.marks, range, this.props);
});
@ -1109,9 +1110,8 @@ const BlockText = observer(class BlockText extends React.Component<Props> {
skipIds: [ rootId ],
onChange: (text: string, marks: I.Mark[], from: number, to: number) => {
value = UtilCommon.stringInsert(value, text, from, from);
this.marks = Mark.checkRanges(value, marks);
UtilData.blockSetText(rootId, block.id, value, this.marks, true, () => {
UtilData.blockSetText(rootId, block.id, value, marks, true, () => {
focus.set(block.id, { from: to, to: to });
focus.apply();

View file

@ -1312,10 +1312,10 @@ const EditorPage = observer(class EditorPage extends React.Component<Props, Stat
};
const element = blockStore.getMapElement(rootId, block.id);
const parent = blockStore.getLeaf(rootId, element.parentId);
const parentElement = blockStore.getMapElement(rootId, parent.id);
const parent = blockStore.getLeaf(rootId, element?.parentId);
const parentElement = blockStore.getMapElement(rootId, parent?.id);
if (!element || !parentElement) {
if (!element || !parent || !parentElement) {
return;
};
@ -1489,7 +1489,12 @@ const EditorPage = observer(class EditorPage extends React.Component<Props, Stat
if (isInsideTable) {
const element = blockStore.getMapElement(rootId, block.id);
const rowElement = blockStore.getMapElement(rootId, element.parentId);
const rowElement = blockStore.getMapElement(rootId, element?.parentId);
if (!rowElement) {
return;
};
const idx = rowElement.childrenIds.indexOf(block.id);
if (idx < 0) {
@ -2092,7 +2097,7 @@ const EditorPage = observer(class EditorPage extends React.Component<Props, Stat
const element = blockStore.getMapElement(rootId, last.id);
const parent = blockStore.getLeaf(rootId, element.parentId);
if (!parent.isLayoutDiv() && !parent.isPage()) {
if (parent && !parent.isLayoutDiv() && !parent.isPage()) {
last = null;
};
};

View file

@ -28,9 +28,9 @@ class Editable extends React.Component<Props> {
_isMounted = false;
node: any = null;
placeholder: any = null;
editable: any = null;
composition = false;
refPlaceholder = null;
refEditable = null;
constructor (props: Props) {
super(props);
@ -70,6 +70,7 @@ class Editable extends React.Component<Props> {
editor = (
<div
id={id}
ref={ref => this.refEditable = ref}
className={cne.join(' ')}
contentEditable={true}
suppressContentEditableWarning={true}
@ -81,6 +82,7 @@ class Editable extends React.Component<Props> {
editor = (
<div
id={id}
ref={ref => this.refEditable = ref}
className={cne.join(' ')}
contentEditable={true}
suppressContentEditableWarning={true}
@ -107,77 +109,61 @@ class Editable extends React.Component<Props> {
onMouseDown={onMouseDown}
>
{editor}
<div id="placeholder" className={cnp.join(' ')}>{placeholder}</div>
<div
id="placeholder"
className={cnp.join(' ')}
ref={ref => this.refPlaceholder = ref}
>
{placeholder}
</div>
</div>
);
};
componentDidMount () {
this._isMounted = true;
this.init();
};
componentDidUpdate (): void {
this.init();
};
componentWillUnmount () {
this._isMounted = false;
};
init () {
const pl = this.placeholder ? this.placeholder.length : 0;
const el = this.editable ? this.editable.length : 0;
if (pl && el) {
return;
};
const node = $(this.node);
if (!pl) {
this.placeholder = node.find('#placeholder');
};
if (!el) {
this.editable = node.find('.editable');
};
};
placeholderCheck () {
this.getTextValue() ? this.placeholderHide() : this.placeholderShow();
};
placeholderSet (v: string) {
this.placeholder.text(v);
$(this.refPlaceholder).text(v);
};
placeholderHide () {
this.placeholder.hide();
$(this.refPlaceholder).hide();
};
placeholderShow () {
this.placeholder.show();
$(this.refPlaceholder).show();
};
setValue (html: string) {
this.editable.get(0).innerHTML = UtilCommon.sanitize(html);
$(this.refEditable).get(0).innerHTML = UtilCommon.sanitize(html);
};
getTextValue (): string {
const obj = Mark.cleanHtml(this.editable.html());
const obj = Mark.cleanHtml($(this.refEditable).html());
return String(obj.get(0).innerText || '');
};
getHtmlValue () : string {
return String(this.editable.html() || '');
return String($(this.refEditable).html() || '');
};
getRange (): I.TextRange {
const range = getRange(this.editable.get(0) as Element);
const range = getRange($(this.refEditable).get(0) as Element);
return range ? { from: range.start, to: range.end } : null;
};
setRange (range: I.TextRange) {
const el = this.editable.get(0);
const el = $(this.refEditable).get(0);
el.focus({ preventScroll: true });
setRange(el, { start: range.from, end: range.to });

View file

@ -121,11 +121,9 @@ class Phrase extends React.Component<Props, State> {
componentDidMount () {
const { value, isHidden } = this.props;
const text = this.normalizeWhiteSpace(value);
const phrase = text.length ? text.split(' '): [];
this.init();
this.setState({ isHidden, phrase });
this.setState({ isHidden });
this.setValue(value);
this.focus();
};
@ -264,6 +262,13 @@ class Phrase extends React.Component<Props, State> {
return String(val || '').replace(/\s\s+/g, ' ').trim() || '';
};
setValue (value: string) {
const text = this.normalizeWhiteSpace(value);
const phrase = text.length ? text.split(' '): [];
this.setState({ phrase });
};
getValue () {
return this.state.phrase.join(' ').trim().toLowerCase();
};

View file

@ -87,7 +87,7 @@ class ListObjectPreview extends React.Component<Props> {
size={I.PreviewSize.Large}
rootId={item.id}
onClick={e => this.onClick(e, item)}
onMore={e => onMenu(e, item)}
onMore={onMenu ? e => onMenu(e, item) : null}
/>
);
};

View file

@ -171,13 +171,15 @@ const ListWidget = observer(class ListWidget extends React.Component<Props, Stat
icon="store"
onClick={this.onLibrary}
/>
<Button
text={translate('widgetBin')}
color=""
className="widget"
icon="bin"
onClick={this.onArchive}
/>
{canWrite ? (
<Button
text={translate('widgetBin')}
color=""
className="widget"
icon="bin"
onClick={this.onArchive}
/>
) : ''}
</DropTarget>
<div className="buttons">

View file

@ -170,7 +170,7 @@ class MenuBlockMore extends React.Component<I.Menu> {
const allowedFav = canWrite && !object.isArchived && !UtilObject.getFileAndSystemLayouts().includes(object.layout) && !object.templateIsBundled;
const allowedLock = canWrite && blockStore.checkFlags(rootId, rootId, [ I.RestrictionObject.Details ]);
const allowedLinkTo = canWrite;
const allowedPageLink = config.experimental;
const allowedPageLink = true;
const allowedCopy = canWrite && blockStore.checkFlags(rootId, rootId, [ I.RestrictionObject.Duplicate ]);
const allowedReload = canWrite && object.source && block.isObjectBookmark();
const allowedInstall = canWrite && !object.isInstalled && UtilObject.isTypeOrRelationLayout(object.layout);
@ -199,6 +199,11 @@ class MenuBlockMore extends React.Component<I.Menu> {
if (!allowedLinkTo) linkTo = null;
if (!allowedPageLink) pageLink = null;
if (!canWrite) {
template = null;
setDefaultTemplate = null;
};
let sections = [];
if (hasShortMenu) {
if (!UtilObject.isSetLayout(object.layout)) {

View file

@ -82,8 +82,9 @@ class MenuContext extends React.Component<I.Menu> {
getSections () {
const { param } = this.props;
const { data } = param;
const { subId, objectIds, getObject, isCollection, allowedLink, allowedOpen } = data;
const { subId, objectIds, getObject, isCollection } = data;
const length = objectIds.length;
const canWrite = UtilObject.canParticipantWrite();
let pageCopy = { id: 'copy', icon: 'copy', name: translate('commonDuplicate') };
let open = { id: 'open', icon: 'expand', name: translate('commonOpenObject') };
@ -91,7 +92,7 @@ class MenuContext extends React.Component<I.Menu> {
let changeType = { id: 'changeType', icon: 'pencil', name: translate('blockFeaturedTypeMenuChangeType'), arrow: true };
let createWidget = { id: 'createWidget', icon: 'createWidget', name: translate('menuBlockMoreCreateWidget') };
let exportObject = { id: 'export', icon: 'export', name: translate('menuBlockMoreExport') };
let unlink = null;
let unlink = { id: 'unlink', icon: 'unlink', name: translate('menuDataviewContextUnlinkFromCollection') };
let archive = null;
let archiveCnt = 0;
let fav = null;
@ -101,10 +102,11 @@ class MenuContext extends React.Component<I.Menu> {
let allowedFav = true;
let allowedCopy = true;
let allowedType = true;
if (isCollection) {
unlink = { id: 'unlink', icon: 'unlink', name: translate('menuDataviewContextUnlinkFromCollection') };
};
let allowedLink = data.allowedLink;
let allowedOpen = data.allowedOpen;
let allowedUnlink = isCollection;
let allowedExport = true;
let allowedWidget = true;
objectIds.forEach((it: string) => {
let object = null;
@ -143,17 +145,27 @@ class MenuContext extends React.Component<I.Menu> {
};
if (length > 1) {
open = null;
linkTo = null;
createWidget = null;
allowedOpen = false;
allowedLink = false;
allowedWidget = false;
};
if (!canWrite) {
allowedArchive = false;
allowedFav = false;
allowedCopy = false;
allowedType = false;
allowedLink = false;
allowedUnlink = false;
allowedWidget = false;
};
if (archiveCnt == length) {
open = null;
linkTo = null;
unlink = null;
changeType = null;
exportObject = null;
allowedOpen = false;
allowedLink = false;
allowedUnlink = false;
allowedType = false;
allowedFav = false;
archive = { id: 'unarchive', icon: 'restore', name: translate('commonRestoreFromBin') };
} else {
archive = { id: 'archive', icon: 'remove', name: translate('commonMoveToBin') };
@ -165,6 +177,9 @@ class MenuContext extends React.Component<I.Menu> {
if (!allowedType) changeType = null;
if (!allowedLink) linkTo = null;
if (!allowedOpen) open = null;
if (!allowedUnlink) unlink = null;
if (!allowedExport) exportObject = null;
if (!allowedWidget) createWidget = null;
let sections = [
{ children: [ createWidget, open, fav, linkTo, exportObject ] },

View file

@ -101,7 +101,7 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
return (
<div
id={`item-tag-${element.id}`}
className="item"
className={[ 'item', (isReadonly ? 'isReadonly' : '') ].join(' ')}
onMouseEnter={() => {
menuStore.close('select');
setHover({ id: `tag-${element.id}` });
@ -140,7 +140,7 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
return (
<div
id={`item-object-${element.id}`}
className="item withCaption"
className={[ 'item', 'withCaption', (isReadonly ? 'isReadonly' : '') ].join(' ')}
onMouseEnter={() => setHover({ id: `object-${element.id}` })}
>
<div className="clickable" onClick={e => this.onObject(e, item)}>
@ -591,6 +591,11 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
};
onFocusDate (e: any) {
const isReadonly = this.isReadonly();
if (isReadonly) {
return;
};
const { param } = this.props;
const { data } = param;
const { getView, itemId } = data;
@ -630,6 +635,11 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
};
onTag () {
const isReadonly = this.isReadonly();
if (isReadonly) {
return;
};
const { param, getId, getSize } = this.props;
const { data } = param;
const { rootId, blockId, getView, itemId } = data;
@ -657,6 +667,11 @@ const MenuDataviewFilterValues = observer(class MenuDataviewFilterValues extends
};
onObject (e: any, item: any) {
const isReadonly = this.isReadonly();
if (isReadonly) {
return;
};
const { param, getId, getSize } = this.props;
const { data } = param;
const { rootId, blockId } = data;

View file

@ -283,13 +283,14 @@ const MenuRelationEdit = observer(class MenuRelationEdit extends React.Component
const { rootId, blockId, getView, loadData } = data;
const view = getView();
const relation = this.getRelation();
const relations = Dataview.viewGetRelations(rootId, blockId, view);
const idx = view.relations.findIndex(it => it.relationKey == relation.relationKey);
if (!relation) {
return;
};
const relations = Dataview.viewGetRelations(rootId, blockId, view);
const idx = view.relations.findIndex(it => it && (it.relationKey == relation.relationKey));
let close = true;
switch (item.id) {

View file

@ -72,6 +72,7 @@ const MenuSort = observer(class MenuSort extends React.Component<I.Menu> {
options={relationOptions}
value={item.relationKey}
onChange={v => this.onChange(item.id, 'relationKey', v)}
readonly={isReadonly}
/>
<Select
@ -80,6 +81,7 @@ const MenuSort = observer(class MenuSort extends React.Component<I.Menu> {
options={typeOptions}
value={item.type}
onChange={v => this.onChange(item.id, 'type', v)}
readonly={isReadonly}
/>
</div>
{!isReadonly ? (

View file

@ -82,7 +82,6 @@ interface State {
tab: string;
};
const BORDER = 10;
const ARROW_WIDTH = 17;
const ARROW_HEIGHT = 8;
@ -444,6 +443,7 @@ const Menu = observer(class Menu extends React.Component<I.Menu, State> {
position () {
const { id, param } = this.props;
const { element, recalcRect, type, vertical, horizontal, fixedX, fixedY, isSub, noFlipX, noFlipY, withArrow } = param;
const { border } = Constant.size.menu;
const borderTop = Number(window.AnytypeGlobalConfig?.menuBorderTop) || UtilCommon.sizeHeader();
const borderBottom = Number(window.AnytypeGlobalConfig?.menuBorderBottom) || 80;
@ -535,7 +535,7 @@ const Menu = observer(class Menu extends React.Component<I.Menu, State> {
x += offsetX;
// Switch
if (!noFlipX && (x >= ww - width - BORDER)) {
if (!noFlipX && (x >= ww - width - border)) {
x = ox - width;
flipX = true;
};
@ -549,7 +549,7 @@ const Menu = observer(class Menu extends React.Component<I.Menu, State> {
x -= width + offsetX - ew;
// Switch
if (!noFlipX && (x <= BORDER)) {
if (!noFlipX && (x <= border)) {
x = ox + ew;
flipX = true;
};
@ -561,8 +561,8 @@ const Menu = observer(class Menu extends React.Component<I.Menu, State> {
y -= scrollTop;
};
x = Math.max(BORDER, x);
x = Math.min(ww - width - BORDER, x);
x = Math.max(border, x);
x = Math.min(ww - width - border, x);
y = Math.max(borderTop, y);
y = Math.min(wh - height - borderBottom, y);
@ -930,6 +930,7 @@ const Menu = observer(class Menu extends React.Component<I.Menu, State> {
const node = $(this.node);
const menu = node.find('.menu');
const { border } = Constant.size.menu;
menu.find('.item.hover').removeClass('hover');
@ -958,7 +959,7 @@ const Menu = observer(class Menu extends React.Component<I.Menu, State> {
const pt = el.position().top;
const eh = el.outerHeight();
const ch = scrollWrap.height();
const top = Math.max(0, st + pt + eh - BORDER - ch);
const top = Math.max(0, st + pt + eh - border - ch);
scrollWrap.scrollTop(top);
};

View file

@ -59,6 +59,8 @@ const MenuOnboarding = observer(class MenuSelect extends React.Component<I.Menu,
buttons = item.forceButtons;
};
buttons = buttons.filter(it => it);
const Steps = () => (
<div className="steps">
{l > 1 ? (

View file

@ -150,14 +150,17 @@ class MenuQuickCapture extends React.Component<I.Menu, State> {
const check = async () => {
const items = await this.getClipboardData();
if (this.clipboardItems !== items) {
this.clipboardItems = items;
const needUpdate = this.clipboardItems.length != items.length;
this.clipboardItems = items;
if (needUpdate) {
this.forceUpdate();
};
};
check();
this.intervalClipboard = window.setInterval(check, 1000);
this.intervalClipboard = window.setInterval(check, 2000);
};
componentDidUpdate () {
@ -306,7 +309,7 @@ class MenuQuickCapture extends React.Component<I.Menu, State> {
id: SystemIds.Clipboard,
icon: 'clipboard',
name: '',
tooltip: translate('menuQuickCaptureTooltipSearch'),
tooltip: translate('menuQuickCaptureTooltipClipboard'),
caption: '0',
});
};
@ -401,15 +404,21 @@ class MenuQuickCapture extends React.Component<I.Menu, State> {
if (item.itemId == SystemIds.Search) {
this.onExpand();
analytics.event('ScreenObjectTypeSearch');
return;
};
const { close } = this.props;
const cb = (created?: any) => {
const { isExpanded } = this.state;
const flags: I.ObjectFlag[] = [ I.ObjectFlag.SelectTemplate, I.ObjectFlag.DeleteEmpty ];
const type = created || item;
if (isExpanded && this.filter.length) {
analytics.event('TypeSearchResult');
};
C.ObjectCreate({ layout: type.recommendedLayout }, flags, item.defaultTemplateId, type.uniqueKey, commonStore.space, (message: any) => {
if (message.error.code || !message.details) {
return;
@ -489,13 +498,14 @@ class MenuQuickCapture extends React.Component<I.Menu, State> {
case 'pin': {
isPinned ? Storage.removePinnedType(item.itemId) : Storage.addPinnedType(item.itemId);
analytics.event(isPinned ? 'UnpinObjectType' : 'PinObjectType', { objectType: item.uniqueKey, route: 'Navigation' });
this.forceUpdate();
break;
};
case 'default': {
commonStore.typeSet(item.uniqueKey);
analytics.event('DefaultTypeChange', { objectType: item.uniqueKey, route: 'Settings' });
analytics.event('DefaultTypeChange', { objectType: item.uniqueKey, route: 'Navigation' });
this.forceUpdate();
break;
};
@ -503,6 +513,7 @@ class MenuQuickCapture extends React.Component<I.Menu, State> {
case 'remove': {
if (blockStore.isAllowed(item.restrictions, [ I.RestrictionObject.Delete ])) {
Action.uninstall({ ...item, id: item.itemId }, true);
analytics.event('ObjectUninstall', { route: 'Navigation' });
};
break;
};
@ -558,6 +569,8 @@ class MenuQuickCapture extends React.Component<I.Menu, State> {
const type = dbStore.getTypeById(commonStore.type);
const data = await this.getClipboardData();
analytics.event('CreateObject', { route: 'Clipboard' });
data.forEach(async item => {
let text = '';
let html = '';
@ -611,14 +624,23 @@ class MenuQuickCapture extends React.Component<I.Menu, State> {
};
beforePosition () {
const node = $(this.node);
const { getId } = this.props;
const obj = $(`#${getId()}`);
const { ww } = UtilCommon.getWindowDimensions();
const sidebar = $('#sidebar');
const sw = sidebar.outerWidth();
obj.css({ width: '' });
node.find('.item').each((i: number, item: any) => {
obj.find('.item').each((i: number, item: any) => {
item = $(item);
item.find('.iconObject').length ? item.addClass('withIcon') : item.removeClass('withIcon');
item.css({ width: Math.ceil(item.outerWidth()) });
item.css({ width: '' });
item.css({ width: Math.max(48, Math.ceil(item.outerWidth())) });
});
obj.css({ width: Math.min(ww - Constant.size.menu.border * 2 - sw, obj.width()) });
};
};

View file

@ -3,7 +3,7 @@ import $ from 'jquery';
import { observer } from 'mobx-react';
import { AutoSizer, CellMeasurer, InfiniteLoader, List, CellMeasurerCache } from 'react-virtualized';
import { Filter, Icon, MenuItemVertical, Loader } from 'Component';
import { I, analytics, keyboard, UtilData, Relation, Action, UtilCommon, translate } from 'Lib';
import { I, analytics, keyboard, UtilData, Relation, Action, UtilCommon, UtilObject, translate } from 'Lib';
import { commonStore, menuStore, detailStore } from 'Store';
import Constant from 'json/constant.json';
@ -273,26 +273,29 @@ const MenuRelationSuggest = observer(class MenuRelationSuggest extends React.Com
const library = items.filter(it => it.isInstalled && !systemKeys.includes(it.relationKey));
const system = items.filter(it => it.isInstalled && systemKeys.includes(it.relationKey));
const librarySources = library.map(it => it.sourceObject);
const canWrite = UtilObject.canParticipantWrite();
let sections: any[] = [
{ id: 'library', name: translate('menuRelationSuggestMyRelations'), children: library },
{ id: 'system', name: translate('menuRelationSuggestSystem'), children: system },
];
if (filter) {
const store = items.filter(it => !it.isInstalled && !librarySources.includes(it.id) && !systemKeys.includes(it.relationKey));
sections = sections.concat([
{ id: 'store', name: translate('commonAnytypeLibrary'), children: store },
{ children: [ { id: 'add', name: UtilCommon.sprintf(translate('menuRelationSuggestCreateRelation'), filter) } ] }
]);
} else {
sections = sections.concat([
{
children: [
{ id: 'store', icon: 'store', name: translate('commonAnytypeLibrary'), arrow: true }
]
},
]);
if (canWrite) {
if (filter) {
const store = items.filter(it => !it.isInstalled && !librarySources.includes(it.id) && !systemKeys.includes(it.relationKey));
sections = sections.concat([
{ id: 'store', name: translate('commonAnytypeLibrary'), children: store },
{ children: [ { id: 'add', name: UtilCommon.sprintf(translate('menuRelationSuggestCreateRelation'), filter) } ] }
]);
} else {
sections = sections.concat([
{
children: [
{ id: 'store', icon: 'store', name: translate('commonAnytypeLibrary'), arrow: true }
]
},
]);
};
};
sections = sections.filter((section: any) => {

View file

@ -240,12 +240,13 @@ const MenuSearchObject = observer(class MenuSearchObject extends React.Component
const { filter, label, canAdd, addParam } = data;
const length = this.items.length;
const items = [].concat(this.items);
const canWrite = UtilObject.canParticipantWrite();
if (label && length) {
items.unshift({ isSection: true, name: label });
};
if (canAdd) {
if (canAdd && canWrite) {
if (length && (addParam || filter)) {
items.push({ isDiv: true });
};

View file

@ -1,8 +1,8 @@
import * as React from 'react';
import { observer } from 'mobx-react';
import { IconObject, Icon, ObjectName } from 'Component';
import { I, UtilCommon, UtilObject, UtilRouter, keyboard, translate, Action, analytics, Storage } from 'Lib';
import { authStore, dbStore, popupStore, menuStore, blockStore, detailStore } from 'Store';
import { I, UtilCommon, UtilObject, UtilRouter, keyboard, translate, UtilMenu, analytics, Storage } from 'Lib';
import { authStore, dbStore, popupStore, blockStore } from 'Store';
import Constant from 'json/constant.json';
const ITEM_WIDTH = 112;
@ -159,31 +159,13 @@ const MenuSpace = observer(class MenuSpace extends React.Component<I.Menu> {
onContextMenu (e: any, item: any) {
const { param } = this.props;
const { classNameWrap } = param;
const { accountSpaceId } = authStore;
if ((item.targetSpaceId == accountSpaceId)) {
return;
};
menuStore.open('select', {
classNameWrap,
UtilMenu.spaceContext(item, {
classNameWrap: param.classNameWrap,
recalcRect: () => {
const { x, y } = keyboard.mouse.page;
return { width: 0, height: 0, x: x + 4, y: y };
},
data: {
options: [
{ id: 'remove', color: 'red', name: translate('commonDelete') }
],
onSelect: (e: any, element: any) => {
switch (element.id) {
case 'remove':
Action.removeSpace(item.targetSpaceId, 'Navigation');
break;
};
},
},
});
};
@ -209,13 +191,14 @@ const MenuSpace = observer(class MenuSpace extends React.Component<I.Menu> {
getItems () {
const items = UtilCommon.objectCopy(dbStore.getSpaces());
if (items.length < Constant.limit.space) {
items.push({ id: 'add', name: translate('commonCreateNew') });
};
const length = items.length;
items.push({ id: 'gallery', name: translate('commonGallery') });
if (length < Constant.limit.space) {
items.push({ id: 'add', name: translate('commonCreateNew') });
};
return items;
};

View file

@ -3,7 +3,7 @@ import $ from 'jquery';
import { observer } from 'mobx-react';
import { AutoSizer, CellMeasurer, InfiniteLoader, List, CellMeasurerCache } from 'react-virtualized';
import { Filter, Icon, MenuItemVertical, Loader } from 'Component';
import { I, C, analytics, keyboard, UtilData, Action, UtilCommon, translate, Storage } from 'Lib';
import { I, C, analytics, keyboard, UtilData, Action, UtilCommon, translate, UtilObject } from 'Lib';
import { commonStore, detailStore, menuStore, dbStore } from 'Store';
import Constant from 'json/constant.json';
@ -283,26 +283,29 @@ const MenuTypeSuggest = observer(class MenuTypeSuggest extends React.Component<I
const items = UtilCommon.objectCopy(this.items || []).map(it => ({ ...it, object: it }));
const library = items.filter(it => (it.spaceId == space));
const librarySources = library.map(it => it.sourceObject);
const canWrite = UtilObject.canParticipantWrite();
let sections: any[] = [
{ id: 'library', name: translate('menuTypeSuggestMyTypes'), children: library },
];
if (filter) {
const store = items.filter(it => (it.spaceId == Constant.storeSpaceId) && !librarySources.includes(it.id));
if (canWrite) {
if (filter) {
const store = items.filter(it => (it.spaceId == Constant.storeSpaceId) && !librarySources.includes(it.id));
sections = sections.concat([
{ id: 'store', name: translate('commonAnytypeLibrary'), children: store },
{ children: [ { id: 'add', name: UtilCommon.sprintf(translate('menuTypeSuggestCreateType'), filter) } ] }
]);
} else {
sections = sections.concat([
{
children: [
{ id: 'store', icon: 'store', name: translate('commonAnytypeLibrary'), arrow: true }
]
},
]);
sections = sections.concat([
{ id: 'store', name: translate('commonAnytypeLibrary'), children: store },
{ children: [ { id: 'add', name: UtilCommon.sprintf(translate('menuTypeSuggestCreateType'), filter) } ] }
]);
} else {
sections = sections.concat([
{
children: [
{ id: 'store', icon: 'store', name: translate('commonAnytypeLibrary'), arrow: true }
]
},
]);
};
};
sections = sections.filter((section: any) => {

View file

@ -125,7 +125,7 @@ const PageAuthDeleted = observer(class PageAuthDeleted extends React.Component<I
};
onExport () {
Action.export([], I.ExportType.Markdown, {
Action.export('', [], I.ExportType.Markdown, {
zip: true,
nested: true,
files: true,

View file

@ -76,7 +76,7 @@ const PageAuthLogin = observer(class PageAuthLogin extends React.Component<I.Pag
};
componentDidUpdate () {
const { accounts, phrase } = authStore;
const { accounts } = authStore;
this.focus();
@ -84,7 +84,7 @@ const PageAuthLogin = observer(class PageAuthLogin extends React.Component<I.Pag
const account = accounts[0];
authStore.accountSet(account);
Renderer.send('keytarSet', account.id, phrase);
Renderer.send('keytarSet', account.id, this.refPhrase.getValue());
this.select();
};
@ -118,10 +118,8 @@ const PageAuthLogin = observer(class PageAuthLogin extends React.Component<I.Pag
return;
};
authStore.phraseSet(phrase);
authStore.accountListClear();
UtilData.createSession(() => {
UtilData.createSession(phrase, '', () => {
C.AccountRecover(message => this.setError(message.error));
});
});

View file

@ -21,6 +21,7 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component<I
refNext: Button = null;
isDelayed = false;
isCreating = false;
phrase = '';
state: State = {
stage: Stage.Void,
@ -81,7 +82,7 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component<I
<div className="animation" onClick={this.onCopy}>
<Phrase
ref={ref => this.refPhrase = ref}
value={authStore.phrase}
value={this.phrase}
readonly={true}
isHidden={!phraseVisible}
onCopy={this.onCopy}
@ -157,6 +158,7 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component<I
componentWillUnmount (): void {
this.unbind();
this.phrase = '';
};
unbind () {
@ -207,13 +209,13 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component<I
const { account, name } = authStore;
const next = () => {
Animation.from(() => {
this.refNext.setLoading(false);
this.refNext?.setLoading(false);
this.setState({ stage: stage + 1 });
});
};
if (stage == Stage.Void) {
this.refNext.setLoading(true);
this.refNext?.setLoading(true);
if (account) {
this.accountUpdate(() => next());
@ -260,7 +262,7 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component<I
};
accountCreate (callBack?: () => void) {
this.refNext.setLoading(true);
this.refNext?.setLoading(true);
const { name, networkConfig } = authStore;
const { mode, path } = networkConfig;
@ -272,11 +274,9 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component<I
return;
};
const phrase = message.mnemonic;
this.phrase = message.mnemonic;
authStore.phraseSet(phrase);
UtilData.createSession((message) => {
UtilData.createSession(this.phrase, '', (message) => {
if (message.error.code) {
this.setError(message.error.description);
return;
@ -293,7 +293,7 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component<I
commonStore.isSidebarFixedSet(true);
UtilData.onInfo(message.account.info);
Renderer.send('keytarSet', message.account.id, phrase);
Renderer.send('keytarSet', message.account.id, this.phrase);
analytics.event('CreateAccount', { middleTime: message.middleTime });
analytics.event('CreateSpace', { middleTime: message.middleTime, usecase: I.Usecase.GetStarted });
@ -316,7 +316,7 @@ const PageAuthOnboard = observer(class PageAuthOnboard extends React.Component<I
/** Copies key phrase to clipboard and shows a toast */
onCopy () {
UtilCommon.copyToast(translate('commonPhrase'), authStore.phrase);
UtilCommon.copyToast(translate('commonPhrase'), this.phrase);
analytics.event('KeychainCopy', { type: 'Onboarding' });
};

View file

@ -1,6 +1,6 @@
import * as React from 'react';
import { Frame, Title, Label, Error, Button, Header, Footer, Icon, Loader } from 'Component';
import { I, Storage, translate, C, UtilData, UtilCommon, Action, Animation, analytics, UtilRouter } from 'Lib';
import { I, Storage, translate, C, UtilData, UtilCommon, Action, Animation, analytics, UtilRouter, Renderer } from 'Lib';
import { authStore, commonStore } from 'Store';
import { observer } from 'mobx-react';
import Errors from 'json/error.json';
@ -117,30 +117,28 @@ const PageAuthSetup = observer(class PageAuthSetup extends React.Component<I.Pag
};
init () {
const { phrase } = authStore;
const { dataPath } = commonStore;
const accountId = Storage.get('accountId');
if (!phrase) {
return;
};
C.WalletRecover(dataPath, phrase, (message: any) => {
if (this.setError(message.error)) {
return;
};
UtilData.createSession((message: any) => {
Renderer.send('keytarGet', accountId).then((phrase: string) => {
C.WalletRecover(dataPath, phrase, (message: any) => {
if (this.setError(message.error)) {
return;
};
if (accountId) {
authStore.phraseSet(phrase);
this.select(accountId, false);
} else {
UtilRouter.go('/auth/account-select', { replace: true });
};
UtilData.createSession(phrase, '' ,(message: any) => {
if (this.setError(message.error)) {
return;
};
this.select(accountId, false);
});
});
});
};

View file

@ -11,7 +11,6 @@ import PageAuthSelect from './auth/select';
import PageAuthLogin from './auth/login';
import PageAuthPinCheck from './auth/pinCheck';
import PageAuthSetup from './auth/setup';
import PageAuthAccountSelect from './auth/accountSelect';
import PageAuthOnboard from './auth/onboard';
import PageAuthDeleted from './auth/deleted';
@ -40,7 +39,6 @@ const Components = {
'auth/login': PageAuthLogin,
'auth/pin-check': PageAuthPinCheck,
'auth/setup': PageAuthSetup,
'auth/account-select': PageAuthAccountSelect,
'auth/onboard': PageAuthOnboard,
'auth/deleted': PageAuthDeleted,

View file

@ -30,6 +30,8 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
scrollLeft = 0;
scrollRight = 0;
lastId = '';
refSideLeft = null;
refSideRight = null;
constructor (props: I.PageComponent) {
super(props);
@ -115,7 +117,7 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
<Header component="mainHistory" ref={ref => this.refHeader = ref} {...this.props} rootId={rootId} />
<div id="body" className="flex">
<div id="sideLeft" className="wrapper">
<div ref={ref => this.refSideLeft = ref} id="sideLeft" className="wrapper">
<div id="editorWrapper" className={cn.join(' ')}>
<div className="editor">
<div className="blocks">
@ -139,7 +141,7 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
</div>
</div>
<div id="sideRight" className="list">
<div ref={ref => this.refSideRight = ref} id="sideRight" className="list">
<div className="wrap">
{groups.map((item: any, i: number) => (
<Section key={i} {...item} />
@ -161,9 +163,8 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
componentDidUpdate () {
const rootId = this.getRootId();
const node = $(this.node);
const sideLeft = node.find('#body > #sideLeft');
const sideRight = node.find('#body > #sideRight');
const sideLeft = $(this.refSideLeft);
const sideRight = $(this.refSideRight);
this.resize();
this.rebind();
@ -229,8 +230,7 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
onScrollLeft () {
const { isPopup } = this.props;
const node = $(this.node);
const sideLeft = node.find('#body > #sideLeft');
const sideLeft = $(this.refSideLeft);
const container = UtilCommon.getScrollContainer(isPopup);
this.scrollLeft = sideLeft.scrollTop();
@ -240,10 +240,8 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
onScrollRight () {
const { isPopup } = this.props;
const { versions } = this.state;
const node = $(this.node);
const container = UtilCommon.getPageContainer(isPopup);
const sideRight = node.find('#body > #sideRight');
const sideRight = $(this.refSideRight);
const wrap = sideRight.find('.wrap');
const sections = wrap.find('.section');
const { wh } = UtilCommon.getWindowDimensions();
@ -297,8 +295,7 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
};
const group = month.list.find(it => it.groupId == version.groupId);
const node = $(this.node);
const sideRight = node.find('#body > #sideRight');
const sideRight = $(this.refSideRight);
const item = sideRight.find(`#item-${version.id}`);
sideRight.find('.active').removeClass('active');
@ -316,8 +313,7 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
toggleChildren (e: any, id: string) {
e.stopPropagation();
const node = $(this.node);
const sideRight = node.find('#body > #sideRight');
const sideRight = $(this.refSideRight);
const item = sideRight.find(`#item-${id}`);
const children = sideRight.find(`#children-${id}`);
const isActive = item.hasClass('expanded');
@ -451,8 +447,8 @@ const PageMainHistory = observer(class PageMainHistory extends React.Component<I
const { isPopup } = this.props;
const node = $(this.node);
const sideLeft = node.find('#body > #sideLeft');
const sideRight = node.find('#body > #sideRight');
const sideLeft = $(this.refSideLeft);
const sideRight = $(this.refSideRight);
const editorWrapper = sideLeft.find('#editorWrapper');
const cover = node.find('.block.blockCover');
const container = UtilCommon.getPageContainer(isPopup);

View file

@ -1,6 +1,6 @@
import * as React from 'react';
import { Loader, Title, Error, Frame, Button } from 'Component';
import { I, UtilCommon, UtilRouter, UtilObject, keyboard, translate } from 'Lib';
import { I, C, UtilCommon, UtilRouter, UtilObject, keyboard, translate } from 'Lib';
import { popupStore } from 'Store';
import Constant from 'json/constant.json';
@ -14,6 +14,7 @@ class PageMainImport extends React.Component<I.PageComponent, State> {
error: '',
};
node = null;
refFrame = null;
render () {
const { error } = this.state;
@ -23,17 +24,15 @@ class PageMainImport extends React.Component<I.PageComponent, State> {
ref={ref => this.node = ref}
className="wrapper"
>
<Frame>
<Frame ref={ref => this.refFrame = ref}>
<Title text={translate('pageMainInviteTitle')} />
<Loader />
<Error text={error} />
{error ? (
<div className="buttons">
<Button text={translate('commonBack')} className="c28" onClick={() => keyboard.onBack()} />
</div>
) : ''}
) : <Loader />}
</Frame>
</div>
);
@ -41,13 +40,28 @@ class PageMainImport extends React.Component<I.PageComponent, State> {
componentDidMount (): void {
const data = this.getSearch();
const allowedStatuses = [ I.SpaceStatus.Deleted ];
if (!data.cid || !data.key) {
this.setState({ error: translate('pageMainInviteError') });
this.setState({ error: translate('pageMainInviteErrorData') });
} else {
UtilObject.openHome('route');
window.setTimeout(() => popupStore.open('inviteRequest', { data }), Constant.delay.popup);
C.SpaceInviteView(data.cid, data.key, (message: any) => {
if (message.error.code) {
this.setState({ error: message.error.description });
return;
};
const space = UtilObject.getSpaceviewBySpaceId(message.spaceId);
if (space && !allowedStatuses.includes(space.spaceAccountStatus)) {
this.setState({ error: UtilCommon.sprintf(translate('pageMainInviteErrorDuplicate'), space.name) });
return;
};
UtilObject.openHome('route');
window.setTimeout(() => popupStore.open('inviteRequest', { data: { invite: message, ...data } }), Constant.delay.popup);
});
};
this.resize();
};
@ -64,13 +78,13 @@ class PageMainImport extends React.Component<I.PageComponent, State> {
const win = $(window);
const obj = UtilCommon.getPageContainer(isPopup);
const node = $(this.node);
const wrapper = obj.find('.wrapper');
const oh = obj.height();
const header = node.find('#header');
const hh = header.height();
const wh = isPopup ? oh - hh : win.height();
wrapper.css({ height: wh, paddingTop: isPopup ? 0 : hh });
node.css({ height: wh, paddingTop: isPopup ? 0 : hh });
this.refFrame.resize();
};
};

View file

@ -19,7 +19,6 @@ enum View {
const cmd = keyboard.cmdSymbol();
const alt = keyboard.altSymbol();
const PageMainStore = observer(class PageMainStore extends React.Component<I.PageComponent, State> {
state = {
@ -59,6 +58,7 @@ const PageMainStore = observer(class PageMainStore extends React.Component<I.Pag
return null;
};
const canWrite = UtilObject.canParticipantWrite();
const { isPopup } = this.props;
const views = this.getViews();
const items = this.getItems();
@ -132,7 +132,7 @@ const PageMainStore = observer(class PageMainStore extends React.Component<I.Pag
);
const Item = (item: any) => {
const allowedDelete = blockStore.isAllowed(item.restrictions, [ I.RestrictionObject.Delete ]);
const allowedDelete = canWrite && blockStore.isAllowed(item.restrictions, [ I.RestrictionObject.Delete ]);
const cn = [ 'item', (item.isHidden ? 'isHidden' : '') ];
const icons: any[] = [];
const buttons: any[] = [];
@ -555,6 +555,7 @@ const PageMainStore = observer(class PageMainStore extends React.Component<I.Pag
getViews (): any[] {
const views: any[] = [];
const canWrite = UtilObject.canParticipantWrite();
switch (this.tab) {
case I.StoreTab.Type:
@ -566,7 +567,9 @@ const PageMainStore = observer(class PageMainStore extends React.Component<I.Pag
break;
};
views.push({ id: View.Marketplace, name: translate('commonAnytypeLibrary') });
if (canWrite) {
views.push({ id: View.Marketplace, name: translate('commonAnytypeLibrary') });
};
return views;
};
@ -599,6 +602,7 @@ const PageMainStore = observer(class PageMainStore extends React.Component<I.Pag
if (blockStore.isAllowed(item.restrictions, [ I.RestrictionObject.Delete ])) {
Action.uninstall(item, true);
analytics.event('ObjectUninstall', { route: 'Library' });
};
};

View file

@ -54,6 +54,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC
const object = detailStore.get(rootId, rootId);
const subIdTemplate = this.getSubIdTemplate();
const templates = dbStore.getRecords(subIdTemplate, '');
const canWrite = UtilObject.canParticipantWrite();
const layout: any = UtilMenu.getLayouts().find(it => it.id == object.recommendedLayout) || {};
const showTemplates = !UtilObject.getLayoutsWithoutTemplates().includes(object.recommendedLayout);
@ -62,7 +63,7 @@ const PageMainType = observer(class PageMainType extends React.Component<I.PageC
const allowedObject = object.isInstalled && UtilObject.getPageLayouts().includes(object.recommendedLayout);
const allowedDetails = object.isInstalled && blockStore.checkFlags(rootId, rootId, [ I.RestrictionObject.Details ]);
const allowedRelation = object.isInstalled && blockStore.checkFlags(rootId, rootId, [ I.RestrictionObject.Relation ]);
const allowedTemplate = object.isInstalled && allowedObject && showTemplates;
const allowedTemplate = object.isInstalled && allowedObject && showTemplates && canWrite;
const allowedLayout = object.recommendedLayout != I.ObjectLayout.Bookmark;
const subIdObject = this.getSubIdObject();

View file

@ -187,6 +187,7 @@ const PopupExport = observer(class PopupExport extends React.Component<I.Popup>
};
onConfirm (e: any) {
const { space } = commonStore;
const { param, close } = this.props;
const { data } = param;
const { objectIds, route } = data;
@ -196,7 +197,7 @@ const PopupExport = observer(class PopupExport extends React.Component<I.Popup>
switch (format) {
default:
Action.export(objectIds, format, { ...this.data, route });
Action.export(space, objectIds, format, { ...this.data, route });
close();
break;

View file

@ -13,11 +13,8 @@ const PopupInviteRequest = observer(class PopupInviteRequest extends React.Compo
state = {
error: '',
};
invite = {
spaceName: '',
creatorName: '',
spaceId: '',
};
refButton = null;
constructor (props: I.Popup) {
super(props);
@ -27,6 +24,9 @@ const PopupInviteRequest = observer(class PopupInviteRequest extends React.Compo
render() {
const { error } = this.state;
const { param } = this.props;
const { data } = param;
const { invite } = data;
return (
<React.Fragment>
@ -36,10 +36,10 @@ const PopupInviteRequest = observer(class PopupInviteRequest extends React.Compo
<Icon />
</div>
<Label className="invitation" text={UtilCommon.sprintf(translate('popupInviteRequestText'), this.invite.spaceName, this.invite.creatorName)} />
<Label className="invitation" text={UtilCommon.sprintf(translate('popupInviteRequestText'), invite.spaceName, invite.creatorName)} />
<div className="buttons">
<Button onClick={this.onRequest} text={translate('popupInviteRequestRequestToJoin')} className="c36" />
<Button ref={ref => this.refButton = ref} onClick={this.onRequest} text={translate('popupInviteRequestRequestToJoin')} className="c36" />
</div>
<div className="note">{translate('popupInviteRequestNote')}</div>
@ -49,33 +49,21 @@ const PopupInviteRequest = observer(class PopupInviteRequest extends React.Compo
);
};
componentDidMount (): void {
const { param } = this.props;
const { data } = param;
const { cid, key } = data;
C.SpaceInviteView(cid, key, (message: any) => {
if (message.error.code) {
this.setState({ error: message.error.description });
return;
};
this.invite = message;
this.forceUpdate();
});
};
onRequest () {
const { param, close } = this.props;
const { data } = param;
const { cid, key } = data;
const { account } = authStore;
const { data } = param;
const { invite, cid, key } = data;
if (!account) {
if (!account || this.refButton.state.isLoading) {
return;
};
C.SpaceJoin(account.info.networkId, this.invite.spaceId, cid, key, (message: any) => {
this.refButton?.setLoading(true);
C.SpaceJoin(account.info.networkId, invite.spaceId, cid, key, (message: any) => {
this.refButton?.setLoading(false);
if (message.error.code) {
this.setState({ error: message.error.description });
return;

View file

@ -1,6 +1,6 @@
import * as React from 'react';
import { Title, Label, IconObject, ObjectName, Button } from 'Component';
import { analytics, C, UtilFile, I, translate, UtilCommon } from 'Lib';
import { analytics, C, UtilFile, I, translate, UtilCommon, UtilData } from 'Lib';
import { observer } from 'mobx-react';
import { commonStore, popupStore } from 'Store';
@ -25,7 +25,7 @@ const PopupSettingsPageDataManagement = observer(class PopupSettingsPageStorageI
return (
<React.Fragment>
<Title text={translate('popupSettingsDataManagementTitle')} />
<Label className="description" text={translate('popupSettingsDataManagementLocalStorageText')} />
<Label className="description" text={translate(`popupSettingsDataManagementLocalStorageText${suffix}`)} />
<div className="actionItems">
<div className="item storageUsage">
@ -38,7 +38,7 @@ const PopupSettingsPageDataManagement = observer(class PopupSettingsPageStorageI
</div>
</div>
<div className="side right">
<Button color="blank" className="c28" text={translate('popupSettingsDataManagementOffloadFiles')} onClick={this.onOffload} />
<Button color="blank" className="c28" text={translate(`popupSettingsDataManagementOffloadFiles${suffix}`)} onClick={this.onOffload} />
</div>
</div>
</div>
@ -52,14 +52,17 @@ const PopupSettingsPageDataManagement = observer(class PopupSettingsPageStorageI
onOffload (e: any) {
const { setLoading } = this.props;
const localOnly = UtilData.isLocalOnly();
analytics.event('ScreenFileOffloadWarning');
popupStore.open('confirm',{
data: {
title: translate('popupSettingsDataOffloadWarningTitle'),
text: translate('popupSettingsDataOffloadWarningText'),
textConfirm: translate('commonYes'),
text: translate(`popupSettingsDataOffloadWarningText${localOnly ? 'LocalOnly' : ''}`),
textConfirm: localOnly ? translate('popupSettingsDataKeepFiles') : translate('commonYes'),
canCancel: localOnly,
textCancel: translate('popupSettingsDataRemoveFiles'),
onConfirm: () => {
setLoading(true);
analytics.event('SettingsStorageOffload');

View file

@ -23,6 +23,7 @@ const PopupSettingsPageLogout = observer(class PopupSettingsPageLogout extends R
this.onCopy = this.onCopy.bind(this);
this.onLogout = this.onLogout.bind(this);
this.onToggle = this.onToggle.bind(this);
};
render () {
@ -36,7 +37,6 @@ const PopupSettingsPageLogout = observer(class PopupSettingsPageLogout extends R
<div className="inputs" onClick={this.onCopy}>
<Phrase
ref={ref => this.refPhrase = ref}
value={authStore.phrase}
readonly={true}
isHidden={true}
checkPin={true}
@ -53,20 +53,27 @@ const PopupSettingsPageLogout = observer(class PopupSettingsPageLogout extends R
};
componentDidMount () {
const { phrase } = authStore;
const { account } = authStore;
if (phrase) {
C.WalletConvert(phrase, '', (message: any) => {
this.setState({ entropy: message.entropy });
});
if (!account) {
return;
};
Renderer.send('keytarGet', account.id).then((value: string) => {
C.WalletConvert(value, '', (message: any) => {
if (!message.error.code) {
this.refPhrase.setValue(value);
this.setState({ entropy: message.entropy });
};
});
});
analytics.event('ScreenKeychain', { type: 'BeforeLogout' });
};
onToggle (isHidden: boolean): void {
if (!isHidden) {
UtilCommon.copyToast(translate('commonPhrase'), authStore.phrase);
UtilCommon.copyToast(translate('commonPhrase'), this.refPhrase.getValue());
analytics.event('KeychainCopy', { type: 'BeforeLogout' });
};
};

View file

@ -2,7 +2,7 @@ import * as React from 'react';
import { observer } from 'mobx-react';
import QRCode from 'qrcode.react';
import { Title, Label, Phrase } from 'Component';
import { I, C, translate, analytics, UtilCommon, Storage } from 'Lib';
import { I, C, translate, analytics, UtilCommon, Storage, Renderer } from 'Lib';
import { commonStore, authStore, popupStore } from 'Store';
import Theme from 'json/theme.json';
@ -42,7 +42,6 @@ const PopupSettingsPagePhrase = observer(class PopupSettingsPagePhrase extends R
<div className="inputs" onClick={this.onCopy}>
<Phrase
ref={ref => this.refPhrase = ref}
value={authStore.phrase}
readonly={true}
isHidden={true}
checkPin={true}
@ -63,20 +62,27 @@ const PopupSettingsPagePhrase = observer(class PopupSettingsPagePhrase extends R
};
componentDidMount () {
const { phrase } = authStore;
const { account } = authStore;
if (phrase) {
C.WalletConvert(phrase, '', (message: any) => {
this.setState({ entropy: message.entropy });
});
if (!account) {
return;
};
Renderer.send('keytarGet', account.id).then((value: string) => {
C.WalletConvert(value, '', (message: any) => {
if (!message.error.code) {
this.refPhrase.setValue(value);
this.setState({ entropy: message.entropy });
};
});
});
analytics.event('ScreenKeychain', { type: 'ScreenSettings' });
};
onToggle (isHidden: boolean): void {
if (!isHidden) {
UtilCommon.copyToast(translate('commonPhrase'), authStore.phrase);
UtilCommon.copyToast(translate('commonPhrase'), this.refPhrase.getValue());
analytics.event('KeychainCopy', { type: 'ScreenSettings' });
};
};

View file

@ -132,36 +132,37 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R
</div>
<div className="sections">
<div className="section sectionSpaceManager">
<Title text={translate(`popupSettingsSpaceIndexManageSpaceTitle`)} />
<div className="sectionContent">
<div className={usageCn.join(' ')}>
<div className="sides alignTop">
<div className="side left">
<Title text={translate(`popupSettingsSpaceIndexRemoteStorageTitle`)} />
<div className="storageLabel">
<Label text={UtilCommon.sprintf(translate(`popupSettingsSpaceIndexStorageText`), UtilFile.size(bytesLimit))} />
&nbsp;
{extend}
{canWrite ? (
<div className="section sectionSpaceManager">
<Title text={translate(`popupSettingsSpaceIndexManageSpaceTitle`)} />
<div className="sectionContent">
<div className={usageCn.join(' ')}>
<div className="sides alignTop">
<div className="side left">
<Title text={translate(`popupSettingsSpaceIndexRemoteStorageTitle`)} />
<div className="storageLabel">
<Label text={UtilCommon.sprintf(translate(`popupSettingsSpaceIndexStorageText`), UtilFile.size(bytesLimit))} />
&nbsp;
{extend}
</div>
</div>
<div className="side right">
{canWrite ? (
<Button
onClick={() => onPage('spaceStorageManager')}
text={translate('popupSettingsSpaceIndexStorageManageFiles')}
color="blank"
className="c28"
/>
) : ''}
</div>
</div>
<div className="side right">
{canWrite ? (
<Button
onClick={() => onPage('spaceStorageManager')}
text={translate('popupSettingsSpaceIndexStorageManageFiles')}
color="blank"
className="c28"
/>
) : ''}
</div>
<ProgressBar segments={progressSegments} current={UtilFile.size(bytesUsed)} max={UtilFile.size(bytesLimit)} />
</div>
<ProgressBar segments={progressSegments} current={UtilFile.size(bytesUsed)} max={UtilFile.size(bytesLimit)} />
</div>
{canWrite ? (
<div className="item">
<div className="sides">
<div className="side left">
@ -179,28 +180,28 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R
</div>
</div>
</div>
) : ''}
<div className="item">
<div className="sides">
<div className="side left">
<Title text={translate('popupSettingsPersonalDefaultObjectType')} />
<Label text={translate('popupSettingsPersonalDefaultObjectTypeDescription')} />
</div>
<div className="item">
<div className="sides">
<div className="side left">
<Title text={translate('popupSettingsPersonalDefaultObjectType')} />
<Label text={translate('popupSettingsPersonalDefaultObjectTypeDescription')} />
</div>
<div className="side right">
<div id="defaultType" className="select" onClick={this.onType}>
<div className="item">
<div className="name">{type?.name || translate('commonSelect')}</div>
<div className="side right">
<div id="defaultType" className="select" onClick={this.onType}>
<div className="item">
<div className="name">{type?.name || translate('commonSelect')}</div>
</div>
<Icon className="arrow black" />
</div>
<Icon className="arrow black" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
) : ''}
<div className="section sectionIntegrations">
<Title text={translate(`popupSettingsSpaceIndexIntegrations`)} />
@ -291,7 +292,7 @@ const PopupSettingsSpaceIndex = observer(class PopupSettingsSpaceIndex extends R
{canDelete ? (
<div className="buttons">
<Button text={translate('commonDelete')} color="red c36" onClick={this.onDelete} />
<Button text={isOwner ? translate('commonDelete') : translate('commonLeaveSpace')} color="red c36" onClick={this.onDelete} />
</div>
) : ''}

View file

@ -2,38 +2,36 @@ import * as React from 'react';
import $ from 'jquery';
import { observer } from 'mobx-react';
import { Title, IconObject, ObjectName, Icon } from 'Component';
import { I, UtilObject, UtilRouter, translate, Action } from 'Lib';
import { authStore, dbStore, detailStore, menuStore } from 'Store';
import { I, C, UtilObject, UtilRouter, translate, Action, UtilMenu } from 'Lib';
import { popupStore, dbStore, detailStore, menuStore, authStore } from 'Store';
import Constant from 'json/constant.json';
const PopupSettingsPageSpacesList = observer(class PopupSettingsPageSpacesList extends React.Component<{}, {}> {
const PopupSettingsPageSpacesList = observer(class PopupSettingsPageSpacesList extends React.Component<I.PopupSettings> {
constructor (props) {
super(props);
};
render () {
const { account, accountSpaceId } = authStore;
const spaces = dbStore.getSpaces();
const { accountSpaceId } = authStore;
const spaces = this.getItems();
const Row = (space: any) => {
const creator = detailStore.get(Constant.subId.space, space.creator);
const participant = detailStore.get(Constant.subId.myParticipant, UtilObject.getParticipantId(space.targetSpaceId, account.id));
const participant = UtilObject.getMyParticipant(space.targetSpaceId);
const isOwner = participant && (participant.permissions == I.ParticipantPermissions.Owner);
const permissions = participant ? translate(`participantPermissions${participant.permissions}`) : '';
const hasMenu = space.targetSpaceId != accountSpaceId;
return (
<tr>
<td className="columnSpace">
<div
className="spaceNameWrapper"
onClick={() => UtilRouter.switchSpace(space.targetSpaceId)}
>
<div className="spaceNameWrapper" onClick={() => this.onClick(space)}>
<IconObject object={space} size={40} />
<div className="info">
<ObjectName object={space} />
{!isOwner ? (
{!isOwner && !creator._empty_ ? (
<div className="creatorNameWrapper">
<IconObject object={creator} size={16} />
<ObjectName object={creator} />
@ -42,12 +40,12 @@ const PopupSettingsPageSpacesList = observer(class PopupSettingsPageSpacesList e
</div>
</div>
</td>
<td>{translate(`participantPermissions${participant.permissions}`)}</td>
<td>{permissions}</td>
<td>{translate(`spaceStatus${space.spaceAccountStatus}`)}</td>
<td className="columnMore">
{hasMenu ? (
<div id={`icon-more-${space.id}`} onClick={e => this.onSpaceMore(e, space)} className="iconWrap">
<div id={`icon-more-${space.id}`} onClick={() => this.onMore(space)} className="iconWrap">
<Icon className="more" />
</div>
) : ''}
@ -71,9 +69,7 @@ const PopupSettingsPageSpacesList = observer(class PopupSettingsPageSpacesList e
</tr>
</thead>
<tbody>
{spaces.map((item: any, i: number) => (
<Row key={i} {...item} />
))}
{spaces.map((item: any, i: number) => <Row key={i} {...item} />)}
</tbody>
</table>
</div>
@ -81,29 +77,30 @@ const PopupSettingsPageSpacesList = observer(class PopupSettingsPageSpacesList e
);
};
onSpaceMore (e: React.MouseEvent, space: any) {
const element = $(`#icon-more-${space.id}`);
const options: any[] = [
{ id: 'remove', color: 'red', name: translate('commonDelete') },
];
getItems () {
const subId = Constant.subId.space;
const items = dbStore.getRecords(subId, '').map(id => detailStore.get(subId, id));
menuStore.open('select', {
return items.filter(it => ![ I.SpaceStatus.Deleted, I.SpaceStatus.Removing ].includes(it.spaceAccountStatus));
};
onClick (space: any) {
if (space.spaceAccountStatus != I.SpaceStatus.Joining) {
UtilRouter.switchSpace(space.targetSpaceId);
};
};
onMore (space: any) {
const { getId } = this.props;
const element = $(`#${getId()} #icon-more-${space.id}`);
UtilMenu.spaceContext(space, {
element,
vertical: I.MenuDirection.Bottom,
horizontal: I.MenuDirection.Right,
offsetY: 4,
onOpen: () => element.addClass('active'),
onClose: () => element.removeClass('active'),
data: {
options,
onSelect: (e: any, item: any) => {
switch (item.id) {
case 'remove':
Action.removeSpace(space.targetSpaceId, 'ScreenSettings');
break;
};
}
}
});
};

View file

@ -1,7 +1,7 @@
import * as React from 'react';
import $ from 'jquery';
import { Title, Label, IconObject, ObjectName } from 'Component';
import { I, UtilObject, translate } from 'Lib';
import { I, UtilObject, UtilData, translate } from 'Lib';
import { observer } from 'mobx-react';
import { dbStore, detailStore } from 'Store';
import { AutoSizer, WindowScroller, CellMeasurer, CellMeasurerCache, List } from 'react-virtualized';
@ -131,17 +131,7 @@ const PopupSettingsSpaceMembers = observer(class PopupSettingsSpaceMembers exten
const subId = Constant.subId.participant;
const records = dbStore.getRecords(subId, '').map(id => detailStore.get(subId, id)).filter(it => statuses.includes(it.status));
records.sort((c1, c2) => {
const isOwner1 = c1.permissions == I.ParticipantPermissions.Owner;
const isOwner2 = c2.permissions == I.ParticipantPermissions.Owner;
if (isOwner1 && !isOwner2) return -1;
if (!isOwner1 && isOwner2) return 1;
return 0;
});
return records;
return records.sort(UtilData.sortByOwner);
};
resize () {

View file

@ -1,7 +1,7 @@
import * as React from 'react';
import $ from 'jquery';
import { Title, Label, Icon, Input, Button, IconObject, ObjectName, Select, Tag, Error } from 'Component';
import { I, C, translate, UtilCommon } from 'Lib';
import { I, C, translate, UtilCommon, UtilData } from 'Lib';
import { observer } from 'mobx-react';
import { dbStore, detailStore, popupStore, commonStore } from 'Store';
import { AutoSizer, WindowScroller, CellMeasurer, CellMeasurerCache, List } from 'react-virtualized';
@ -236,17 +236,7 @@ const PopupSettingsSpaceShare = observer(class PopupSettingsSpaceShare extends R
const subId = Constant.subId.participant;
const records = dbStore.getRecords(subId, '').map(id => detailStore.get(subId, id)).filter(it => statuses.includes(it.status));
records.sort((c1, c2) => {
const isOwner1 = c1.permissions == I.ParticipantPermissions.Owner;
const isOwner2 = c2.permissions == I.ParticipantPermissions.Owner;
if (isOwner1 && !isOwner2) return -1;
if (!isOwner1 && isOwner2) return 1;
return 0;
});
return records;
return records.sort(UtilData.sortByOwner);
};
getLink () {

View file

@ -1,7 +1,7 @@
import * as React from 'react';
import $ from 'jquery';
import { Title, Label, Button, Tag, Icon, Loader, Error } from 'Component';
import { I, C, UtilCommon, UtilFile, UtilDate, translate, Renderer, analytics } from 'Lib';
import { I, C, UtilCommon, UtilFile, UtilDate, translate, UtilObject, analytics } from 'Lib';
import { menuStore, dbStore } from 'Store';
import { Swiper, SwiperSlide } from 'swiper/react';
import Constant from 'json/constant.json';
@ -170,11 +170,18 @@ class PopupUsecasePageItem extends React.Component<I.PopupUsecase, State> {
};
getSpaceOptions (): any[] {
const list: any[] = dbStore.getSpaces().map(it => ({ ...it, iconSize: 48, object: it }));
let list: any[] = [
{ name: translate('popupUsecaseMenuLabel'), isSection: true }
];
if (list.length < Constant.limit.space) {
list.unshift({ id: 'add', icon: 'add', name: translate('popupUsecaseSpaceCreate') });
list.push({ id: 'add', icon: 'add', name: translate('popupUsecaseSpaceCreate') });
};
list.unshift({ name: translate('popupUsecaseMenuLabel'), isSection: true });
list = list.concat(dbStore.getSpaces()
.filter(it => UtilObject.canParticipantWrite(it.targetSpaceId))
.map(it => ({ ...it, iconSize: 48, object: it })));
return list;
};

View file

@ -413,6 +413,7 @@ const PopupSearch = observer(class PopupSearch extends React.Component<I.Popup,
const hasRelations = keyboard.isMainEditor() || keyboard.isMainSet();
const filter = this.getFilter();
const lang = Constant.default.interfaceLang;
const canWrite = UtilObject.canParticipantWrite();
let name = '';
if (filter) {
@ -441,24 +442,34 @@ const PopupSearch = observer(class PopupSearch extends React.Component<I.Popup,
if (filter) {
const reg = new RegExp(UtilCommon.regexEscape(filter), 'gi');
const itemsImport: any[] = ([
{ id: 'importHtml', icon: 'import-html', name: translate('popupSettingsImportHtmlTitle'), format: I.ImportType.Html },
{ id: 'importText', icon: 'import-text', name: translate('popupSettingsImportTextTitle'), format: I.ImportType.Text },
{ id: 'importProtobuf', icon: 'import-protobuf', name: translate('popupSettingsImportProtobufTitle'), format: I.ImportType.Protobuf },
{ id: 'importMarkdown', icon: 'import-markdown', name: translate('popupSettingsImportMarkdownTitle'), format: I.ImportType.Markdown },
] as any[]).map(it => ({ ...it, isImport: true }));
let itemsImport: any[] = [];
const settingsSpace: any[] = ([
if (canWrite) {
([
{ id: 'importHtml', icon: 'import-html', name: translate('popupSettingsImportHtmlTitle'), format: I.ImportType.Html },
{ id: 'importText', icon: 'import-text', name: translate('popupSettingsImportTextTitle'), format: I.ImportType.Text },
{ id: 'importProtobuf', icon: 'import-protobuf', name: translate('popupSettingsImportProtobufTitle'), format: I.ImportType.Protobuf },
{ id: 'importMarkdown', icon: 'import-markdown', name: translate('popupSettingsImportMarkdownTitle'), format: I.ImportType.Markdown },
] as any[]).map(it => ({ ...it, isImport: true }));
};
let settingsSpace: any[] = [
{ id: 'spaceIndex', name: translate('popupSettingsSpaceTitle') },
{ id: 'importIndex', icon: 'settings-import', name: translate('popupSettingsImportTitle') },
{ id: 'importNotion', icon: 'import-notion', name: translate('popupSettingsImportNotionTitle') },
{ id: 'importCsv', icon: 'import-csv', name: translate('popupSettingsImportCsvTitle') },
{ id: 'exportIndex', icon: 'settings-export', name: translate('popupSettingsExportTitle') },
{ id: 'exportProtobuf', icon: 'import-protobuf', name: translate('popupSettingsExportProtobufTitle') },
{ id: 'exportMarkdown', icon: 'import-markdown', name: translate('popupSettingsExportMarkdownTitle') },
] as any).map(it => ({ ...it, isSpace: true, className: 'isSpace' }));
];
if (canWrite) {
settingsSpace = settingsSpace.concat([
{ id: 'importIndex', icon: 'settings-import', name: translate('popupSettingsImportTitle') },
{ id: 'importNotion', icon: 'import-notion', name: translate('popupSettingsImportNotionTitle') },
{ id: 'importCsv', icon: 'import-csv', name: translate('popupSettingsImportCsvTitle') },
]);
};
settingsSpace = settingsSpace.map(it => ({ ...it, isSpace: true, className: 'isSpace' }));
const settingsAccount: any[] = [
{ id: 'account', name: translate('popupSettingsProfileTitle') },
@ -508,10 +519,12 @@ const PopupSearch = observer(class PopupSearch extends React.Component<I.Popup,
};
};
items.push({ id: 'add', name, icon: 'plus', shortcut: [ cmd, 'N' ] });
if (canWrite) {
items.push({ id: 'add', name, icon: 'plus', shortcut: [ cmd, 'N' ] });
if (hasRelations) {
items.push({ id: 'relation', name: translate('popupSearchAddRelation'), icon: 'relation', shortcut: [ cmd, 'Shift', 'R' ] });
if (hasRelations) {
items.push({ id: 'relation', name: translate('popupSearchAddRelation'), icon: 'relation', shortcut: [ cmd, 'Shift', 'R' ] });
};
};
return items.map(it => {

View file

@ -3,7 +3,7 @@ import $ from 'jquery';
import { observer } from 'mobx-react';
import { Loader, IconObject, Icon, Label } from 'Component';
import { I, UtilCommon, UtilObject, analytics, Action, keyboard, translate, Preview } from 'Lib';
import { popupStore } from 'Store';
import { popupStore, commonStore } from 'Store';
import PageAccount from './page/settings/account';
import PageDataManagement from './page/settings/data';
@ -317,7 +317,7 @@ const PopupSettings = observer(class PopupSettings extends React.Component<I.Pop
onExport (type: I.ExportType, param: any) {
analytics.event('ClickExport', { type, route: 'Settings' });
Action.export([], type, { ...param, route: 'Settings' }, () => this.props.close());
Action.export(commonStore.space, [], type, { ...param, route: 'Settings' }, () => this.props.close());
};
onKeyDown (e: any) {

View file

@ -27,16 +27,19 @@ const WidgetList = observer(class WidgetList extends React.Component<Props, Stat
node = null;
refSelect = null;
refList = null;
state = {
isLoading: false,
};
cache: any = null;
top = 0;
constructor (props: Props) {
super(props);
this.onSortStart = this.onSortStart.bind(this);
this.onSortEnd = this.onSortEnd.bind(this);
this.onScroll = this.onScroll.bind(this);
};
render (): React.ReactNode {
@ -94,6 +97,7 @@ const WidgetList = observer(class WidgetList extends React.Component<Props, Stat
<AutoSizer className="scrollArea">
{({ width, height }) => (
<VList
ref={ref => this.refList = ref}
width={width}
height={height}
deferredMeasurmentCache={this.cache}
@ -103,6 +107,7 @@ const WidgetList = observer(class WidgetList extends React.Component<Props, Stat
onRowsRendered={onRowsRendered}
overscanRowCount={LIMIT}
scrollToAlignment="center"
onScroll={this.onScroll}
/>
)}
</AutoSizer>
@ -225,6 +230,10 @@ const WidgetList = observer(class WidgetList extends React.Component<Props, Stat
this.load(viewId);
};
if (this.refList) {
this.refList.scrollToPosition(this.top);
};
this.initCache();
this.resize();
};
@ -451,6 +460,12 @@ const WidgetList = observer(class WidgetList extends React.Component<Props, Stat
return this.props.isCompact ? HEIGHT_COMPACT : HEIGHT_LIST;
};
onScroll ({ scrollTop }) {
if (scrollTop) {
this.top = scrollTop;
};
};
});
export default WidgetList;

View file

@ -25,11 +25,12 @@ const WidgetTree = observer(class WidgetTree extends React.Component<I.WidgetCom
state = {
loading: false,
};
scrollTop: number = 0;
id: string = '';
top = 0;
id = '';
cache: CellMeasurerCache = null;
subscriptionHashes: { [key: string]: string } = {};
subscriptionHashes: { [ key: string ]: string } = {};
branches: string[] = [];
refList = null;
constructor (props: I.WidgetComponent) {
super(props);
@ -98,6 +99,7 @@ const WidgetTree = observer(class WidgetTree extends React.Component<I.WidgetCom
<AutoSizer className="scrollArea">
{({ width, height }) => (
<List
ref={ref => this.refList = ref}
width={width}
height={height}
deferredMeasurmentCache={this.cache}
@ -162,6 +164,10 @@ const WidgetTree = observer(class WidgetTree extends React.Component<I.WidgetCom
componentDidUpdate () {
this.resize();
if (this.refList) {
this.refList.scrollToPosition(this.top);
};
};
componentWillUnmount () {
@ -363,7 +369,7 @@ const WidgetTree = observer(class WidgetTree extends React.Component<I.WidgetCom
const { dragProvider } = dataset || {};
if (scrollTop) {
this.scrollTop = scrollTop;
this.top = scrollTop;
};
if (dragProvider) {

View file

@ -1,4 +1,4 @@
import { I, Onboarding, keyboard, translate } from 'Lib';
import { I, Onboarding, keyboard, translate, UtilObject } from 'Lib';
export default {
mainGraph: () => ({
@ -175,54 +175,58 @@ export default {
},
}),
dashboard: () => ({
category: translate('onboardingDashboard'),
showConfetti: true,
onComplete: (force: boolean) => {
if (!$('#navigationPanel').hasClass('hide')) {
Onboarding.start('space', 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('onboardingDashboard41')}</p>
<p>${translate('onboardingDashboard42')}</p>
`,
video: './img/help/onboarding/sidebar.mp4',
},
{
description: `
<p>${translate('onboardingDashboard51')}</p>
<p>${translate('onboardingDashboard52')}</p>
<p>${translate('onboardingDashboard53')}</p>
`,
buttons: [
{ text: translate('commonImport'), action: 'import' }
]
}
],
dashboard: () => {
const canWrite = UtilObject.canParticipantWrite();
param: {
element: '#page.isFull #footer #button-help',
classNameWrap: 'fixed',
className: 'wizard',
vertical: I.MenuDirection.Top,
horizontal: I.MenuDirection.Right,
noArrow: true,
noClose: true,
passThrough: true,
offsetY: -4,
},
}),
return {
category: translate('onboardingDashboard'),
showConfetti: true,
onComplete: (force: boolean) => {
if (!$('#navigationPanel').hasClass('hide')) {
Onboarding.start('space', 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('onboardingDashboard41')}</p>
<p>${translate('onboardingDashboard42')}</p>
`,
video: './img/help/onboarding/sidebar.mp4',
},
{
description: `
<p>${translate('onboardingDashboard51')}</p>
<p>${translate('onboardingDashboard52')}</p>
<p>${translate('onboardingDashboard53')}</p>
`,
buttons: [
canWrite ? { text: translate('commonImport'), action: 'import' } : null
]
}
],
param: {
element: '#page.isFull #footer #button-help',
classNameWrap: 'fixed',
className: 'wizard',
vertical: I.MenuDirection.Top,
horizontal: I.MenuDirection.Right,
noArrow: true,
noClose: true,
passThrough: true,
offsetY: -4,
},
};
},
editor: () => ({
category: translate('onboardingEditor'),
@ -412,8 +416,13 @@ export default {
}
),
quickCapture: () => (
{
quickCapture: () => {
const canWrite = UtilObject.canParticipantWrite();
if (!canWrite) {
return;
};
return {
items: [
{
name: translate('onboardingQuickCaptureTitle'),
@ -431,7 +440,7 @@ export default {
offsetY: -24,
noButton: true,
},
}
),
};
},
};

View file

@ -64,8 +64,8 @@ export default [
h3(`Graph and Flow Added to Global Search`),
text(`You can now use the global search menu to navigate to your Graph and Flow tabs.`),
h3(`Czech Added to Interface Languages`),
text(`Thank you to everyone whos contributed to Czech translation, we now have 20 languages available for Desktop!`),
h3(`Czech, Lithuanian, and Korean Added to Interface Languages`),
text(`Thanks to everyone whos contributed to these three new translations, we now have 22 languages available on Desktop!`),
h2(`💻 Tech:`),
bullet(`Electron updated to 0.28.2`),

View file

@ -145,7 +145,7 @@ export interface ViewComponent {
onSourceTypeSelect?(element: any): void;
onViewSettings?(): void;
getSearchIds?(): string[];
canCellEdit?(relationKey: string, recordId: string): boolean;
canCellEdit?(relation: any, record: any): boolean;
};
export interface ViewEmpty {

View file

@ -2,6 +2,7 @@ import { RouteComponentProps } from 'react-router';
import { I } from 'Lib';
export enum Platform {
None = '',
Windows = 'Windows',
Mac = 'Mac',
Linux = 'Linux',

View file

@ -1,13 +1,14 @@
export enum RestrictionObject {
None = 0,
Delete = 1,
Relation = 2,
Block = 3,
Details = 4,
Type = 5,
Layout = 6,
Template = 7,
Duplicate = 8,
None = 0,
Delete = 1,
Relation = 2,
Block = 3,
Details = 4,
Type = 5,
Layout = 6,
Template = 7,
Duplicate = 8,
CreateObjectOfThisType = 9,
};
export enum RestrictionDataview {

View file

@ -457,7 +457,7 @@ class Action {
});
};
export (ids: string[], type: I.ExportType, param: any, onSelectPath?: () => void, callBack?: (message: any) => void): void {
export (spaceId: string, ids: string[], type: I.ExportType, param: any, onSelectPath?: () => void, callBack?: (message: any) => void): void {
const { zip, nested, files, archived, json, route } = param;
this.openDir({ buttonLabel: translate('commonExport') }, paths => {
@ -465,7 +465,7 @@ class Action {
onSelectPath();
};
C.ObjectListExport(commonStore.space, paths[0], ids, type, zip, nested, files, archived, json, (message: any) => {
C.ObjectListExport(spaceId, paths[0], ids, type, zip, nested, files, archived, json, (message: any) => {
if (message.error.code) {
return;
};

View file

@ -28,29 +28,17 @@ class Analytics {
return !(config.sudo || [ 'alpha', 'beta' ].includes(config.channel) || !UtilCommon.getElectron().isPackaged) || this.debug();
};
init () {
init (options?: any) {
if (this.instance) {
return;
};
const { config, interfaceLang } = commonStore;
const { interfaceLang } = commonStore;
const electron = UtilCommon.getElectron();
const platform = UtilCommon.getPlatform();
let version = String(UtilCommon.getElectron().version.app || '').split('-');
if (version.length) {
version = [ version[0] ];
};
if (config.sudo || !UtilCommon.getElectron().isPackaged || [ 'alpha' ].includes(config.channel)) {
version.push('dev');
} else
if ([ 'beta' ].includes(config.channel)) {
version.push(config.channel);
};
C.MetricsSetParameters(platform, version.join('-'));
this.instance = amplitude.getInstance();
this.instance.init(Constant.amplitude, null, {
this.instance.init(Constant.amplitude, null, Object.assign({
apiEndpoint: URL,
batchEvents: true,
saveEvents: true,
@ -60,20 +48,51 @@ class Analytics {
trackingOptions: {
ipAddress: false,
},
});
}, options || {}));
this.instance.setVersionName(UtilCommon.getElectron().version.app);
this.instance.setUserProperties({
const props: any = {
deviceType: 'Desktop',
platform,
osVersion: UtilCommon.getElectron().version.os,
interfaceLang,
});
};
if (electron.version) {
props.osVersion = electron.version.os;
this.instance.setVersionName(electron.version.app);
};
this.instance.setUserProperties(props);
this.removeContext();
this.setVersion();
this.log('[Analytics].init');
};
setVersion () {
const { config } = commonStore;
const platform = UtilCommon.getPlatform();
const electron = UtilCommon.getElectron();
const { version, isPackaged } = electron;
if (!version) {
return;
};
let ret = String(version.app || '').split('-')
if (ret.length) {
ret = [ ret[0] ];
};
if (config.sudo || !isPackaged || [ 'alpha' ].includes(config.channel)) {
ret.push('dev');
} else
if ([ 'beta' ].includes(config.channel)) {
ret.push(config.channel);
};
C.MetricsSetParameters(platform, ret.join('-'));
};
profile (id: string, networkId: string) {
if (!this.instance || !this.isAllowed()) {
return;

View file

@ -1838,6 +1838,12 @@ export const DebugStackGoroutines = (path: string, callBack?: (message: any) =>
dispatcher.request(DebugStackGoroutines.name, request, callBack);
};
export const DebugStat = (callBack?: (message: any) => void) => {
const request = new Rpc.Debug.Stat.Request();
dispatcher.request(DebugStat.name, request, callBack);
};
// ---------------------- NOTIFICATION ---------------------- //
export const NotificationList = (includeRead: boolean, limit: number, callBack?: (message: any) => void) => {
@ -1912,12 +1918,10 @@ export const SpaceJoin = (networkId: string, spaceId: string, cid: string, key:
dispatcher.request(SpaceJoin.name, request, callBack);
};
export const SpaceJoinCancel = (spaceId: string, cid: string, key: string, callBack?: (message: any) => void) => {
export const SpaceJoinCancel = (spaceId: string, callBack?: (message: any) => void) => {
const request = new Rpc.Space.JoinCancel.Request();
request.setSpaceid(spaceId);
request.setInvitecid(cid);
request.setInvitefilekey(key);
dispatcher.request(SpaceJoinCancel.name, request, callBack);
};

View file

@ -196,6 +196,7 @@ class Dispatcher {
let subId = '';
let afterId = '';
let content: any = {};
let updateParents = false;
messages.sort((c1: any, c2: any) => this.sort(c1, c2));
@ -313,6 +314,8 @@ class Dispatcher {
blockStore.add(rootId, new M.Block(block));
blockStore.updateStructure(rootId, block.id, block.childrenIds);
};
updateParents = true;
break;
};
@ -331,6 +334,8 @@ class Dispatcher {
blockStore.delete(rootId, blockId);
};
updateParents = true;
break;
};
@ -342,6 +347,8 @@ class Dispatcher {
if (id == rootId) {
blockStore.checkTypeSelect(rootId);
};
updateParents = true;
break;
};
@ -988,6 +995,12 @@ class Dispatcher {
if (electron.focus) {
electron.focus();
};
analytics.event('CreateObject', {
route: 'Webclipper',
objectType: payload.object.type,
layout: payload.object.layout,
});
break;
};
};
@ -1038,6 +1051,10 @@ class Dispatcher {
log(rootId, type, data, message.getValueCase());
};
};
if (updateParents) {
blockStore.updateStructureParents(rootId);
};
window.clearTimeout(this.timeoutEvent[rootId]);
this.timeoutEvent[rootId] = window.setTimeout(() => {
@ -1165,6 +1182,7 @@ class Dispatcher {
blockStore.set(contextId, blocks);
blockStore.setStructure(contextId, structure);
blockStore.updateStructureParents(contextId);
blockStore.updateNumbers(contextId);
blockStore.updateMarkup(contextId);
blockStore.checkTypeSelect(contextId);

View file

@ -50,6 +50,12 @@ export const DebugSpaceSummary = (response: Rpc.Debug.SpaceSummary.Response) =>
return response.toObject();
};
export const DebugStat = (response: Rpc.Debug.Stat.Response) => {
let res = {};
try { res = JSON.parse(response.getJsonstat()); } catch (e) { /**/ };
return res;
};
export const Export = (response: any) => {
return {
path: response.getPath(),
@ -120,6 +126,7 @@ export const WalletCreateSession = (response: Rpc.Wallet.CreateSession.Response)
return {
token: response.getToken(),
appToken: response.getApptoken(),
accountId: response.getAccountid(),
};
};

View file

@ -579,6 +579,16 @@ class Keyboard {
break;
};
case 'debugStat': {
C.DebugStat((message: any) => {
if (!message.error.code) {
UtilCommon.getElectron().fileWrite('debug-stat.json', JSON.stringify(message, null, 5), { encoding: 'utf8' });
Renderer.send('pathOpen', tmpPath);
};
});
break;
};
case 'debugTree': {
C.DebugTree(rootId, logPath, (message: any) => {
if (!message.error.code) {
@ -674,6 +684,7 @@ class Keyboard {
if (message.blockId && message.range) {
focus.set(message.blockId, message.range);
focus.apply();
focus.scroll(this.isPopup(), message.blockId);
};
if (callBack) {
@ -693,6 +704,7 @@ class Keyboard {
if (message.blockId && message.range) {
focus.set(message.blockId, message.range);
focus.apply();
focus.scroll(this.isPopup(), message.blockId);
};
if (callBack) {
@ -794,23 +806,32 @@ class Keyboard {
});
};
onSpaceMenu (shortcut: boolean) {
popupStore.close('search', () => {
menuStore.closeAll([ 'quickCapture' ], () => {
menuStore.open('space', {
element: '#navigationPanel',
className: 'fixed',
classNameWrap: 'fromNavigation',
type: I.MenuType.Horizontal,
horizontal: I.MenuDirection.Center,
vertical: I.MenuDirection.Top,
offsetY: -12,
data: {
shortcut,
}
menuFromNavigation (id: string, param: Partial<I.MenuParam>, data: any) {
const menuParam = Object.assign({
element: '#navigationPanel',
className: 'fixed',
classNameWrap: 'fromNavigation',
type: I.MenuType.Horizontal,
horizontal: I.MenuDirection.Center,
vertical: I.MenuDirection.Top,
noFlipY: true,
offsetY: -12,
data,
}, param);
if (menuStore.isOpen(id)) {
menuStore.open(id, menuParam);
} else {
popupStore.close('search', () => {
menuStore.closeAll(Constant.menuIds.navigation, () => {
menuStore.open(id, menuParam);
});
});
});
};
};
onSpaceMenu (shortcut: boolean) {
this.menuFromNavigation('space', {}, { shortcut });
};
onQuickCapture () {
@ -819,24 +840,12 @@ class Keyboard {
return;
};
const element = '#button-navigation-plus';
const button = $('#button-navigation-plus');
popupStore.close('search', () => {
menuStore.closeAll([ 'quickCapture', 'space' ], () => {
menuStore.open('quickCapture', {
element,
className: 'fixed',
classNameWrap: 'fromNavigation',
type: I.MenuType.Horizontal,
vertical: I.MenuDirection.Top,
horizontal: I.MenuDirection.Center,
noFlipY: true,
offsetY: -20,
onOpen: () => $(element).addClass('active'),
onClose: () => $(element).removeClass('active'),
});
});
});
this.menuFromNavigation('quickCapture', {
onOpen: () => button.addClass('active'),
onClose: () => button.removeClass('active'),
}, {});
};
onLock (rootId: string, v: boolean, route?: string) {

Some files were not shown because too many files have changed in this diff Show more