From 742888745c7edb72c6ca1c977505ef64f4d48011 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Wed, 13 Nov 2024 19:17:33 +0100 Subject: [PATCH 01/85] date layout --- .../component/page/elements/head/simple.tsx | 27 ++ src/ts/component/page/index.tsx | 2 + src/ts/component/page/main/date.tsx | 278 ++++++++++++++++++ src/ts/lib/api/command.ts | 9 + src/ts/lib/api/response.ts | 11 + src/ts/lib/util/object.ts | 2 +- 6 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 src/ts/component/page/main/date.tsx diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index d35382dc09..5ce34a0c47 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -45,6 +45,7 @@ const HeadSimple = observer(class Controls extends React.Component { const blockFeatured: any = new M.Block({ id: 'featuredRelations', type: I.BlockType.Featured, childrenIds: [], fields: {}, content: {} }); const isTypeOrRelation = U.Object.isTypeOrRelationLayout(object.layout); const isRelation = U.Object.isRelationLayout(object.layout); + const isDate = U.Object.isDateLayout(object.layout); const canEditIcon = allowDetails && !U.Object.isRelationLayout(object.layout); const cn = [ 'headSimple', check.className ]; const placeholder = { @@ -114,6 +115,12 @@ const HeadSimple = observer(class Controls extends React.Component { }; }; + if (isDate) { + button = ( +
this.onCalendar()}>123
+ ); + }; + if (!canWrite) { button = null; }; @@ -285,6 +292,26 @@ const HeadSimple = observer(class Controls extends React.Component { return sources.includes(rootId); }; + onCalendar () { + const { rootId } = this.props; + const object = S.Detail.get(rootId, rootId); + + S.Menu.open('dataviewCalendar', { + element: `#head-calendar-button`, + horizontal: I.MenuDirection.Center, + data: { + value: object.timestamp, + canEdit: true, + onChange: (value: number) => { + console.log('TIMESTAMP', value); + + // TODO: Get date id from timestamp and route to new date object + + }, + }, + }); + }; + }); export default HeadSimple; \ No newline at end of file diff --git a/src/ts/component/page/index.tsx b/src/ts/component/page/index.tsx index 24d16bdb3c..7ed6edabe5 100644 --- a/src/ts/component/page/index.tsx +++ b/src/ts/component/page/index.tsx @@ -31,6 +31,7 @@ import PageMainMembership from './main/membership'; import PageMainObject from './main/object'; import PageMainOnboarding from './main/onboarding'; import PageMainChat from './main/chat'; +import PageMainDate from './main/date'; const Components = { 'index/index': PageAuthSelect, @@ -61,6 +62,7 @@ const Components = { 'main/onboarding': PageMainOnboarding, 'main/chat': PageMainChat, 'main/void': PageMainVoid, + 'main/date': PageMainDate, }; const Page = observer(class Page extends React.Component { diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx new file mode 100644 index 0000000000..e8f663da7b --- /dev/null +++ b/src/ts/component/page/main/date.tsx @@ -0,0 +1,278 @@ +import * as React from 'react'; +import $ from 'jquery'; +import raf from 'raf'; +import { observer } from 'mobx-react'; +import { Header, Footer, Loader, Deleted, ListObject } from 'Component'; +import { I, C, S, U, J, Action, keyboard, translate } from 'Lib'; +import Controls from 'Component/page/elements/head/controls'; +import HeadSimple from 'Component/page/elements/head/simple'; + +interface State { + isLoading: boolean; + isDeleted: boolean; + relations: Item[]; +}; + +interface Item { + relationKey: string; + counter: number; +}; + +const SUB_ID = 'listObject'; + +const PageMainDate = observer(class PageMainDate extends React.Component { + + _isMounted = false; + node: any = null; + id = ''; + refHeader: any = null; + refHead: any = null; + refList: any = null; + refControls: any = null; + loading = false; + timeout = 0; + + state = { + isLoading: false, + isDeleted: false, + relations: [], + }; + + constructor (props: I.PageComponent) { + super(props); + + this.resize = this.resize.bind(this); + }; + + render () { + const { space } = S.Common; + const { isLoading, isDeleted, relations } = this.state; + const rootId = this.getRootId(); + const check = U.Data.checkDetails(rootId); + const object = S.Detail.get(rootId, rootId, [ 'timestamp' ]); + + if (isDeleted) { + return ; + }; + + console.log(object); + + const columns: any[] = [ + { + relationKey: 'lastModifiedDate', name: translate('commonUpdated'), + mapper: v => U.Date.dateWithFormat(I.DateFormat.MonthAbbrBeforeDay, v), + }, + //{ relationKey: object.relationKey, name: object.name, isCell: true } + ]; + + // TODO: get relationKey from state or use first one from relations + const filters: I.Filter[] = [ + { + relationKey: 'dueDate', + condition: I.FilterCondition.Equal, + value: object.timestamp, + format: I.RelationType.Date + }, + ]; + + let content = null; + + if (isLoading) { + content = ; + } else { + const object = S.Detail.get(rootId, rootId, [ 'layout' ], true); + const isCollection = U.Object.isCollectionLayout(object.layout); + const placeholder = isCollection ? translate('defaultNameCollection') : translate('defaultNameSet'); + + content = ( +
+ this.refControls = ref} key="editorControls" {...this.props} rootId={rootId} resize={this.resize} /> + this.refHead = ref} + placeholder={placeholder} + rootId={rootId} + readonly={this.isReadonly()} + /> + +
+ {relations.map(item => { + const relation = S.Record.getRelationByKey(item.relationKey); + + return ( +
+ {relation.name} +
+ ); + })} +
+ +
+ this.refList = ref} + {...this.props} + spaceId={space} + subId={SUB_ID} + rootId={rootId} + filters={filters} + columns={columns} + /> +
+
+ ); + }; + + return ( +
this.node = node}> +
this.refHeader = ref} + rootId={rootId} + /> + +
+
+ {content} +
+
+ +
+
+ ); + }; + + componentDidMount () { + this._isMounted = true; + this.open(); + this.rebind(); + }; + + componentDidUpdate () { + this.open(); + this.resize(); + this.checkDeleted(); + }; + + componentWillUnmount () { + this._isMounted = false; + this.close(); + this.unbind(); + }; + + unbind () { + }; + + rebind () { + this.unbind(); + }; + + checkDeleted () { + const { isDeleted } = this.state; + if (isDeleted) { + return; + }; + + const rootId = this.getRootId(); + const object = S.Detail.get(rootId, rootId, []); + + if (object.isDeleted) { + this.setState({ isDeleted: true }); + }; + }; + + open () { + const rootId = this.getRootId(); + + if (this.id == rootId) { + return; + }; + + this.close(); + this.id = rootId; + this.setState({ isDeleted: false, isLoading: true }); + + C.ObjectOpen(rootId, '', U.Router.getRouteSpaceId(), (message: any) => { + if (!U.Common.checkErrorOnOpen(rootId, message.error.code, this)) { + return; + }; + + const object = S.Detail.get(rootId, rootId, []); + if (object.isDeleted) { + this.setState({ isDeleted: true, isLoading: false }); + return; + }; + + this.refHeader?.forceUpdate(); + this.refHead?.forceUpdate(); + this.refControls?.forceUpdate(); + + this.setState({ isLoading: false }); + this.loadCategory(); + this.resize(); + }); + }; + + close () { + if (!this.id) { + return; + }; + + const { isPopup, match } = this.props; + + let close = true; + if (isPopup && (match.params.id == this.id)) { + close = false; + }; + if (close) { + Action.pageClose(this.id, true); + }; + }; + + loadCategory () { + const { space } = S.Common; + const rootId = this.getRootId(); + const object = S.Detail.get(rootId, rootId); + + console.log(object); + + C.RelationListWithValue(space, object.id, (message: any) => { + this.setState({ relations: message.relations }); + }); + }; + + getRootId () { + const { rootId, match } = this.props; + return rootId ? rootId : match.params.id; + }; + + isReadonly () { + const rootId = this.getRootId(); + const root = S.Block.getLeaf(rootId, rootId); + + if (root && root.isLocked()) { + return true; + }; + + return !U.Space.canMyParticipantWrite(); + }; + + resize () { + const { isLoading } = this.state; + const { isPopup } = this.props; + + if (!this._isMounted || isLoading) { + return; + }; + + raf(() => { + const win = $(window); + const container = U.Common.getPageContainer(isPopup); + + container.css({ minHeight: isPopup ? '' : win.height() }); + }); + }; + +}); + +export default PageMainDate; \ No newline at end of file diff --git a/src/ts/lib/api/command.ts b/src/ts/lib/api/command.ts index d67b73e220..8cc3425152 100644 --- a/src/ts/lib/api/command.ts +++ b/src/ts/lib/api/command.ts @@ -2232,3 +2232,12 @@ export const ChatGetMessagesByIds = (objectId: string, ids: string[], callBack?: dispatcher.request(ChatGetMessagesByIds.name, request, callBack); }; + +export const RelationListWithValue = (spaceId: string, value: any, callBack?: (message: any) => void) => { + const request = new Rpc.Relation.ListWithValue.Request(); + + request.setSpaceid(spaceId); + request.setValue(Encode.value(value)); + + dispatcher.request(RelationListWithValue.name, request, callBack); +}; \ No newline at end of file diff --git a/src/ts/lib/api/response.ts b/src/ts/lib/api/response.ts index 12ce7d565f..aa913d955c 100644 --- a/src/ts/lib/api/response.ts +++ b/src/ts/lib/api/response.ts @@ -586,4 +586,15 @@ export const ChatAddMessage = (response: Rpc.Chat.AddMessage.Response) => { return { messageId: response.getMessageid(), }; +}; + +export const RelationListWithValue = (response: Rpc.Relation.ListWithValue.Response) => { + return { + relations: (response.getListList() || []).map(it => { + return { + relationKey: it.getRelationkey(), + counter: it.getCounter(), + }; + }), + }; }; \ No newline at end of file diff --git a/src/ts/lib/util/object.ts b/src/ts/lib/util/object.ts index 1a2e046457..c63d1e468a 100644 --- a/src/ts/lib/util/object.ts +++ b/src/ts/lib/util/object.ts @@ -26,6 +26,7 @@ class UtilObject { case I.ObjectLayout.Empty: r = 'empty'; break; case I.ObjectLayout.Space: case I.ObjectLayout.Chat: r = 'chat'; break; + case I.ObjectLayout.Date: r = 'date'; break; }; return r; }; @@ -409,7 +410,6 @@ class UtilObject { return [ I.ObjectLayout.Set, I.ObjectLayout.Collection, - I.ObjectLayout.Date, ]; }; From d8b627691b76c1c4ae2fbeda7d772b814f023793 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Wed, 13 Nov 2024 19:25:33 +0100 Subject: [PATCH 02/85] date layout --- src/ts/component/menu/block/mention.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ts/component/menu/block/mention.tsx b/src/ts/component/menu/block/mention.tsx index ed4eaaa091..fc37f56bf0 100644 --- a/src/ts/component/menu/block/mention.tsx +++ b/src/ts/component/menu/block/mention.tsx @@ -191,6 +191,7 @@ const MenuBlockMention = observer(class MenuBlockMention extends React.Component const filter = this.getFilter(); const sections: any[] = []; const length = this.items.length; + const check = this.items.find(it => U.Object.isDateLayout(it.layout)); if (length) { sections.push({ id: I.MarkType.Object, name: translate('commonObjects'), children: this.items }); @@ -327,6 +328,9 @@ const MenuBlockMention = observer(class MenuBlockMention extends React.Component U.Object.create('', '', { name }, I.BlockPosition.Bottom, '', [ I.ObjectFlag.SelectType, I.ObjectFlag.SelectTemplate ], analytics.route.mention, (message: any) => { cb(message.details); }); + } else + if (item.id == 'selectDate') { + // TODO: Open calendar menu, call command that converts timestamp to date object and call callback } else { cb(item); }; From 91d0df2f1854879db5421debb23f911b11eaaf94 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Wed, 13 Nov 2024 19:30:25 +0100 Subject: [PATCH 03/85] update react router --- package-lock.json | 12 ++++++------ package.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 520143baed..d70216f931 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,7 @@ "react-dom": "^17.0.2", "react-minimal-pie-chart": "^8.3.0", "react-pdf": "^6.2.2", - "react-router-dom": "^5.2.0", + "react-router-dom": "^5.3.4", "react-sortable-hoc": "^2.0.0", "react-virtualized": "^9.22.3", "regedit": "^5.1.3", @@ -87,7 +87,7 @@ "@types/raf": "^3.4.0", "@types/react": "^16.14.31", "@types/react-dom": "^16.9.16", - "@types/react-router-dom": "^4.3.5", + "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "^6.18.1", "@typescript-eslint/parser": "^6.18.1", "cross-env": "^7.0.2", @@ -2398,12 +2398,12 @@ } }, "node_modules/@types/react-router-dom": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-4.3.5.tgz", - "integrity": "sha512-eFajSUASYbPHg2BDM1G8Btx+YqGgvROPIg6sBhl3O4kbDdYXdFdfrgQFf/pcBuQVObjfT9AL/dd15jilR5DIEA==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", "dev": true, "dependencies": { - "@types/history": "*", + "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router": "*" } diff --git a/package.json b/package.json index 9c5570a7eb..e1009e0e1a 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@types/raf": "^3.4.0", "@types/react": "^16.14.31", "@types/react-dom": "^16.9.16", - "@types/react-router-dom": "^4.3.5", + "@types/react-router-dom": "^5.3.3", "@typescript-eslint/eslint-plugin": "^6.18.1", "@typescript-eslint/parser": "^6.18.1", "cross-env": "^7.0.2", @@ -141,7 +141,7 @@ "react-dom": "^17.0.2", "react-minimal-pie-chart": "^8.3.0", "react-pdf": "^6.2.2", - "react-router-dom": "^5.2.0", + "react-router-dom": "^5.3.4", "react-sortable-hoc": "^2.0.0", "react-virtualized": "^9.22.3", "regedit": "^5.1.3", From 42dec43a9bbf5feea6455987993394ffaf5b480a Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Thu, 21 Nov 2024 13:05:03 +0100 Subject: [PATCH 04/85] Add date control icons --- src/img/arrow/dateSelectLight.svg | 3 +++ src/scss/page/main/date.scss | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/img/arrow/dateSelectLight.svg create mode 100644 src/scss/page/main/date.scss diff --git a/src/img/arrow/dateSelectLight.svg b/src/img/arrow/dateSelectLight.svg new file mode 100644 index 0000000000..7a51b0f8b2 --- /dev/null +++ b/src/img/arrow/dateSelectLight.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/scss/page/main/date.scss b/src/scss/page/main/date.scss new file mode 100644 index 0000000000..fb8b494e81 --- /dev/null +++ b/src/scss/page/main/date.scss @@ -0,0 +1,18 @@ +@import "~scss/_mixins"; + +.pageMainDate .side.right { + .icon.calendar { width: 24px; height: 24px; background-size: 20px; background-image: url('~img/icon/relation/date.svg'); border-radius: 4px; } + .icon.arrow { + width: 24px; height: 24px; background-size: 20px; background-image: url('~img/arrow/dateSelectLight.svg'); border-radius: 4px; + transition: $transitionAllCommon; + } + .icon.arrow.left { transform: rotateZ(180deg); } +} + +.pageMainDate .categories { display: flex; flex-direction: row; gap: 8px 8px; align-items: center; justify-content: flex-start; flex-wrap: wrap; } +.pageMainDate .separator { background-color: var(--color-shape-secondary); width: 1px; height: 24px; } + +.pageMainDate .mentionsSign { padding-right: 8px; font-size: 16px; color: var(--color-control-active); } + +.dateList .table { border-top-width: 0px !important; } +.dateList .table .isHead .cell > div { border-right-width: 0px !important; } \ No newline at end of file From 9ac88dac37415c51abea98366ed40e4c8209e757 Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Thu, 21 Nov 2024 13:08:05 +0100 Subject: [PATCH 05/85] Add working date page --- src/ts/component/page/main/date.tsx | 86 ++++++++++++++--------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index e8f663da7b..045d684e34 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -3,7 +3,7 @@ import $ from 'jquery'; import raf from 'raf'; import { observer } from 'mobx-react'; import { Header, Footer, Loader, Deleted, ListObject } from 'Component'; -import { I, C, S, U, J, Action, keyboard, translate } from 'Lib'; +import { I, M, C, S, U, J, Action, keyboard, translate } from 'Lib'; import Controls from 'Component/page/elements/head/controls'; import HeadSimple from 'Component/page/elements/head/simple'; @@ -11,12 +11,13 @@ interface State { isLoading: boolean; isDeleted: boolean; relations: Item[]; + selectedRelation: string; }; interface Item { relationKey: string; counter: number; -}; +} const SUB_ID = 'listObject'; @@ -32,10 +33,11 @@ const PageMainDate = observer(class PageMainDate extends React.Component; }; - console.log(object); - const columns: any[] = [ { relationKey: 'lastModifiedDate', name: translate('commonUpdated'), mapper: v => U.Date.dateWithFormat(I.DateFormat.MonthAbbrBeforeDay, v), }, - //{ relationKey: object.relationKey, name: object.name, isCell: true } + // { relationKey: object.relationKey, name: object.name, isCell: true } ]; - // TODO: get relationKey from state or use first one from relations + // TODO: relationKey from state or use first one from relations const filters: I.Filter[] = [ { - relationKey: 'dueDate', + relationKey: relations[0]?.relationKey || 'lastModifiedDate', condition: I.FilterCondition.Equal, value: object.timestamp, format: I.RelationType.Date @@ -80,45 +80,42 @@ const PageMainDate = observer(class PageMainDate extends React.Component; } else { - const object = S.Detail.get(rootId, rootId, [ 'layout' ], true); + + const isCollection = U.Object.isCollectionLayout(object.layout); const placeholder = isCollection ? translate('defaultNameCollection') : translate('defaultNameSet'); content = (
- this.refControls = ref} key="editorControls" {...this.props} rootId={rootId} resize={this.resize} /> - this.refHead = ref} - placeholder={placeholder} - rootId={rootId} - readonly={this.isReadonly()} - /> - -
- {relations.map(item => { - const relation = S.Record.getRelationByKey(item.relationKey); - - return ( -
- {relation.name} -
- ); - })} -
- -
- this.refList = ref} + this.refControls = ref} key="editorControls" {...this.props} rootId={rootId} resize={this.resize} /> + this.refHead = ref} + placeholder={placeholder} rootId={rootId} - filters={filters} - columns={columns} + readonly={this.isReadonly()} /> + +
+ {relations.map((item, index) => { + const relation = S.Record.getRelationByKey(item.relationKey); + + return (
{relation.name}
); + })} +
+
+ this.refList = ref} + {...this.props} + // sources={[rootId]} + spaceId={space} + subId={SUB_ID} + rootId={rootId} + columns={columns} + filters={filters} + /> +
-
); }; @@ -229,9 +226,10 @@ const PageMainDate = observer(class PageMainDate extends React.Component { this.setState({ relations: message.relations }); }); - }; + } getRootId () { const { rootId, match } = this.props; @@ -268,11 +266,11 @@ const PageMainDate = observer(class PageMainDate extends React.Component { const win = $(window); const container = U.Common.getPageContainer(isPopup); - + container.css({ minHeight: isPopup ? '' : win.height() }); }); }; }); -export default PageMainDate; \ No newline at end of file +export default PageMainDate; From 0fed45ec33ff2c36d5b04bfe7826fc751f24dd86 Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Wed, 20 Nov 2024 14:11:23 +0100 Subject: [PATCH 06/85] Update object list according to design --- src/ts/component/page/main/date.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index 045d684e34..0e44a1120f 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -57,12 +57,13 @@ const PageMainDate = observer(class PageMainDate extends React.Component; }; + const creatorRelation = S.Record.getRelationByKey('creator'); const columns: any[] = [ + + { relationKey: 'type', name: translate('commonObjectType'), isObject: true }, { - relationKey: 'lastModifiedDate', name: translate('commonUpdated'), - mapper: v => U.Date.dateWithFormat(I.DateFormat.MonthAbbrBeforeDay, v), + relationKey: creatorRelation.relationKey, name: creatorRelation.name, isObject: true, }, - // { relationKey: object.relationKey, name: object.name, isCell: true } ]; // TODO: relationKey from state or use first one from relations From 5c118ef9341571376cad5230048eaf2137d949bb Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Thu, 21 Nov 2024 13:10:27 +0100 Subject: [PATCH 07/85] Add date nav icons and a calendar menu --- src/scss/component/editor.scss | 13 ++-- src/scss/component/headSimple.scss | 2 +- src/scss/page/common.scss | 1 + .../component/page/elements/head/simple.tsx | 18 ++++-- src/ts/component/page/main/date.tsx | 62 +++++++++++++------ 5 files changed, 67 insertions(+), 29 deletions(-) diff --git a/src/scss/component/editor.scss b/src/scss/component/editor.scss index bafeb09294..5747ed5d0c 100644 --- a/src/scss/component/editor.scss +++ b/src/scss/component/editor.scss @@ -229,10 +229,6 @@ .block.blockDataview { padding: 0px; } .editorControls { height: 52px; width: 100%; margin-bottom: 8px; padding: 0px 14px; } - - .headSimple { - .side.right { display: none; } - } } .block.blockCover { @@ -240,6 +236,15 @@ } } +.editorWrapper.isSet, +.editorWrapper.isCollection { + .blocks { + .headSimple { + .side.right { display: none; } + } + } +} + .editorWrapper.isSet, .editorWrapper.isCollection { &.withIcon { diff --git a/src/scss/component/headSimple.scss b/src/scss/component/headSimple.scss index aa445cc06d..97c8f6e6ff 100644 --- a/src/scss/component/headSimple.scss +++ b/src/scss/component/headSimple.scss @@ -18,7 +18,7 @@ > .descr { @include text-paragraph; } } - .side.right { flex-shrink: 0; text-align: right; } + .side.right { text-align: right; display: flex; flex-direction: row; gap: 0px 8px; align-items: center; } .side.right { .button { white-space: nowrap; } } diff --git a/src/scss/page/common.scss b/src/scss/page/common.scss index 2e85b30323..469079d919 100644 --- a/src/scss/page/common.scss +++ b/src/scss/page/common.scss @@ -16,3 +16,4 @@ @import "./main/onboarding"; @import "./main/chat"; @import "./main/void"; +@import "./main/date"; \ No newline at end of file diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index 5ce34a0c47..37f8ae5c47 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -10,6 +10,8 @@ interface Props { readonly?: boolean; noIcon?: boolean; onCreate?: () => void; + rightSideStart?: React.ReactElement; + rightSideEnd?: React.ReactElement; }; const EDITORS = [ @@ -35,7 +37,7 @@ const HeadSimple = observer(class Controls extends React.Component { }; render (): any { - const { rootId, onCreate, isContextMenuDisabled, readonly, noIcon } = this.props; + const { rootId, onCreate, isContextMenuDisabled, readonly, noIcon, rightSideStart, rightSideEnd } = this.props; const check = U.Data.checkDetails(rootId); const object = S.Detail.get(rootId, rootId, [ 'featuredRelations' ]); const featuredRelations = Relation.getArrayValue(object.featuredRelations); @@ -44,10 +46,14 @@ const HeadSimple = observer(class Controls extends React.Component { const blockFeatured: any = new M.Block({ id: 'featuredRelations', type: I.BlockType.Featured, childrenIds: [], fields: {}, content: {} }); const isTypeOrRelation = U.Object.isTypeOrRelationLayout(object.layout); - const isRelation = U.Object.isRelationLayout(object.layout); const isDate = U.Object.isDateLayout(object.layout); + const isRelation = U.Object.isRelationLayout(object.layout); const canEditIcon = allowDetails && !U.Object.isRelationLayout(object.layout); const cn = [ 'headSimple', check.className ]; + if (isDate) { + cn.push('isDate'); + }; + const titleCn = [ 'title' ]; const placeholder = { title: this.props.placeholder, description: translate('placeholderBlockDescription'), @@ -71,11 +77,11 @@ const HeadSimple = observer(class Controls extends React.Component { /> ); - let button = null; + let button: React.ReactElement = null; let descr = null; let featured = null; - if (!isTypeOrRelation) { + if (!isTypeOrRelation && !isDate) { if (featuredRelations.includes('description')) { descr = ; }; @@ -145,8 +151,8 @@ const HeadSimple = observer(class Controls extends React.Component { {featured} - {button ? ( -
{button}
+ {button || rightSideStart || rightSideEnd ? ( +
{rightSideStart}{button}{rightSideEnd}
) : ''} ); diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index 0e44a1120f..ec0f09e600 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import $ from 'jquery'; import raf from 'raf'; import { observer } from 'mobx-react'; -import { Header, Footer, Loader, Deleted, ListObject } from 'Component'; +import { Header, Footer, Loader, Deleted, ListObject, Button, Icon } from 'Component'; import { I, M, C, S, U, J, Action, keyboard, translate } from 'Lib'; import Controls from 'Component/page/elements/head/controls'; import HeadSimple from 'Component/page/elements/head/simple'; @@ -19,7 +19,7 @@ interface Item { counter: number; } -const SUB_ID = 'listObject'; +const SUB_ID = 'dateListObject'; const PageMainDate = observer(class PageMainDate extends React.Component { @@ -29,6 +29,7 @@ const PageMainDate = observer(class PageMainDate extends React.Component; } else { - - const isCollection = U.Object.isCollectionLayout(object.layout); const placeholder = isCollection ? translate('defaultNameCollection') : translate('defaultNameSet'); + const calendarMenu = <> this.refCalIcon = ref} className="calendar" onClick={this.onCalendar}/>; content = (
this.refControls = ref} key="editorControls" {...this.props} rootId={rootId} resize={this.resize} /> this.refHead = ref} placeholder={placeholder} rootId={rootId} readonly={this.isReadonly()} + rightSideEnd={calendarMenu} />
+ {relations.map((item, index) => { const relation = S.Record.getRelationByKey(item.relationKey); - return (
{relation.name}
); + return (
this.refList = ref} {...this.props} - // sources={[rootId]} spaceId={space} subId={SUB_ID} rootId={rootId} @@ -122,13 +137,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component this.node = node}> -
this.refHeader = ref} - rootId={rootId} - /> -
{content} @@ -140,6 +148,25 @@ const PageMainDate = observer(class PageMainDate extends React.Component { + const node = $(this.refCalIcon.node); + const rootId = this.getRootId(); + const object = S.Detail.get(rootId, rootId, ['timestamp']); + + S.Menu.open('dataviewCalendar', { + element: node, + horizontal: I.MenuDirection.Center, + data: { + // rebind: this.rebind, + value: object.timestamp, + canEdit: true, + onChange: (value: number) => { + console.log('value', value); + }, + }, + }); + }; + componentDidMount () { this._isMounted = true; this.open(); @@ -271,7 +298,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component Date: Thu, 21 Nov 2024 10:55:36 +0100 Subject: [PATCH 08/85] Make it look more like designed in Figma --- src/json/text.json | 2 ++ src/scss/form/button.scss | 2 ++ src/ts/component/form/button.tsx | 19 ++++++++++++++----- src/ts/component/page/main/date.tsx | 20 +++++++++----------- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/json/text.json b/src/json/text.json index 44be367689..fd377d88d0 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -2196,6 +2196,8 @@ "participantPermissions2": "Owner", "participantPermissions3": "No access", + "relationMentions": "Mentioned in", + "spaceStatus0": "Active", "spaceStatus1": "Loading", "spaceStatus2": "Ok", diff --git a/src/scss/form/button.scss b/src/scss/form/button.scss index 6f10fde155..41f8646a1f 100644 --- a/src/scss/form/button.scss +++ b/src/scss/form/button.scss @@ -40,6 +40,8 @@ .button.blank:not(.disabled):hover, .button.blank:not(.disabled).hover { background: var(--color-shape-highlight-medium); } +.button.active { background: var(--color-shape-highlight-medium); } + .button.c36 { @include text-common; height: 36px; border-radius: 6px; padding: 0px 12px; } .button.c32 { @include text-small; height: 32px; border-radius: 6px; padding: 0px 10px; } .button.c28 { @include text-common; height: 28px; border-radius: 6px; padding: 0px 10px; } diff --git a/src/ts/component/form/button.tsx b/src/ts/component/form/button.tsx index 3ea06022f8..3ba54e85bb 100644 --- a/src/ts/component/form/button.tsx +++ b/src/ts/component/form/button.tsx @@ -10,6 +10,8 @@ interface ButtonProps { icon?: string; arrow?: boolean; text?: string; + content?: React.ReactElement; + active?: boolean; color?: string; className?: string; tooltip?: string; @@ -44,18 +46,24 @@ const Button = forwardRef(({ onMouseEnter, onMouseLeave, onMouseDown, - dataset + dataset, + content, + active, }, ref) => { const [ isLoading, setIsLoading ] = useState(false); const nodeRef = useRef(null); const cn = [ 'button', color, className ]; - let content = null; + let innerContent = null; if (isLoading) { cn.push('isLoading'); }; + if (active) { + cn.push('active'); + }; + const handleMouseEnter = (e: MouseEvent) => { if (tooltip) { Preview.tooltipShow({ text: tooltip, element: $(nodeRef.current), typeX: tooltipX, typeY: tooltipY }); @@ -95,7 +103,7 @@ const Button = forwardRef(({ switch (type) { case 'input': { - content = ( + innerContent = ( (({ }; default: { - content = ( + innerContent = (
(({ > {isLoading && } {icon && } + {content}
{arrow &&
}
@@ -132,7 +141,7 @@ const Button = forwardRef(({ }; }; - return content; + return innerContent; }); export default Button; \ No newline at end of file diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index ec0f09e600..71c4df710c 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -83,8 +83,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component; } else { - const isCollection = U.Object.isCollectionLayout(object.layout); - const placeholder = isCollection ? translate('defaultNameCollection') : translate('defaultNameSet'); const calendarMenu = <> this.refCalIcon = ref} className="calendar" onClick={this.onCalendar}/>; content = ( @@ -94,18 +92,17 @@ const PageMainDate = observer(class PageMainDate extends React.Component this.refHead = ref} - placeholder={placeholder} + placeholder={''} rootId={rootId} readonly={this.isReadonly()} rightSideEnd={calendarMenu} />
- - {relations.map((item, index) => { + {relations.sort((a,b) => a.relationKey === 'mentions' ? -1 : 1).map((item, index) => { const relation = S.Record.getRelationByKey(item.relationKey); - - return (
-
+
this.refList = ref} {...this.props} spaceId={space} subId={SUB_ID} - rootId={rootId} + rootId={rootId} columns={columns} filters={filters} /> From 1bc91613c9e2e9bac7070f6bc856a9ac4a8064df Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Thu, 21 Nov 2024 13:13:06 +0100 Subject: [PATCH 09/85] Add obsolete code --- src/ts/component/page/elements/head/simple.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index 37f8ae5c47..af211f8167 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -121,12 +121,6 @@ const HeadSimple = observer(class Controls extends React.Component { }; }; - if (isDate) { - button = ( -
this.onCalendar()}>123
- ); - }; - if (!canWrite) { button = null; }; From 0d193be036e89202f8dd856bcd0d10ba8f1ef0d1 Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Thu, 21 Nov 2024 13:56:29 +0100 Subject: [PATCH 10/85] Fix mentions filter --- src/ts/component/page/main/date.tsx | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index 71c4df710c..781763e3ea 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -69,12 +69,17 @@ const PageMainDate = observer(class PageMainDate extends React.Component Date: Thu, 21 Nov 2024 14:53:04 +0100 Subject: [PATCH 11/85] remove unused variable --- src/ts/lib/util/data.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ts/lib/util/data.ts b/src/ts/lib/util/data.ts index 09a88596ec..721922acec 100644 --- a/src/ts/lib/util/data.ts +++ b/src/ts/lib/util/data.ts @@ -1002,7 +1002,6 @@ class UtilData { }; graphFilters () { - const { space } = S.Common; const templateType = S.Record.getTemplateType(); const filters: any[] = [ { relationKey: 'isHidden', condition: I.FilterCondition.NotEqual, value: true }, From c7a07f2cdea636200e87689ba0fc603a14848110 Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Thu, 21 Nov 2024 15:31:20 +0100 Subject: [PATCH 12/85] Fix React missing key error --- src/ts/component/page/main/date.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index 781763e3ea..417502e025 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -104,9 +104,9 @@ const PageMainDate = observer(class PageMainDate extends React.Component
- {relations.sort((a,b) => a.relationKey === 'mentions' ? -1 : 1).map((item, index) => { + {relations.filter(r => r.relationKey !== 'links').sort((a,b) => a.relationKey === 'mentions' ? -1 : 1).flatMap((item, index) => { const relation = S.Record.getRelationByKey(item.relationKey); - return (<>
} text={index === 0 ? translate('relationMentions') : relation.name} - />{index === 0 && } + />, index === 0 && ] ); })}
From 9c188f7e2d1c43eb9d21139ca7ff2ac76e928adb Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Thu, 21 Nov 2024 15:33:07 +0100 Subject: [PATCH 13/85] JS-5794: default date icon --- dist/img/icon/default/date.svg | 11 +++++++++++ src/ts/component/util/iconObject.tsx | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 dist/img/icon/default/date.svg diff --git a/dist/img/icon/default/date.svg b/dist/img/icon/default/date.svg new file mode 100644 index 0000000000..3b7acf787d --- /dev/null +++ b/dist/img/icon/default/date.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/ts/component/util/iconObject.tsx b/src/ts/component/util/iconObject.tsx index 7f5fc0ba2e..fb20b9f888 100644 --- a/src/ts/component/util/iconObject.tsx +++ b/src/ts/component/util/iconObject.tsx @@ -92,7 +92,7 @@ const FontSize = { 96: 64, }; -const DefaultIcons = [ 'page', 'task', 'set', 'chat', 'bookmark', 'type' ]; +const DefaultIcons = [ 'page', 'task', 'set', 'chat', 'bookmark', 'type', 'date' ]; const Ghost = require('img/icon/ghost.svg'); const CheckboxTask = { @@ -183,6 +183,10 @@ const IconObject = observer(class IconObject extends React.Component { break; }; + case I.ObjectLayout.Date: + defaultIcon('date'); + break; + case I.ObjectLayout.Collection: case I.ObjectLayout.Set: { if (iconImage) { From c478767f4214103caeaaac6324137cd895121cac Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Thu, 21 Nov 2024 16:04:57 +0100 Subject: [PATCH 14/85] JS-5176: date mentions --- src/json/text.json | 1 + src/ts/component/menu/block/mention.tsx | 65 ++++++++++++++++++++++--- src/ts/lib/api/command.ts | 9 ++++ src/ts/lib/api/response.ts | 6 +++ 4 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/json/text.json b/src/json/text.json index fd377d88d0..1327252014 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -89,6 +89,7 @@ "commonComment": "Comment", "commonIcon": "Icon", "commonObjects": "Objects", + "commonDates": "Dates", "commonPreferences": "Preferences", "commonDuplicate": "Duplicate", "commonRemoveFromFavorites": "Remove from Favorites", diff --git a/src/ts/component/menu/block/mention.tsx b/src/ts/component/menu/block/mention.tsx index fc37f56bf0..493c4e9b9d 100644 --- a/src/ts/component/menu/block/mention.tsx +++ b/src/ts/component/menu/block/mention.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { observer } from 'mobx-react'; import $ from 'jquery'; import { MenuItemVertical, Loader, ObjectName, EmptySearch } from 'Component'; -import { I, S, U, J, keyboard, Mark, translate, analytics } from 'Lib'; +import { I, S, U, J, C, keyboard, Mark, translate, analytics } from 'Lib'; import { AutoSizer, CellMeasurer, InfiniteLoader, List, CellMeasurerCache } from 'react-virtualized'; interface State { @@ -31,6 +31,7 @@ const MenuBlockMention = observer(class MenuBlockMention extends React.Component constructor (props: I.Menu) { super(props); + this.rebind = this.rebind.bind(this); this.onClick = this.onClick.bind(this); this.loadMoreRows = this.loadMoreRows.bind(this); }; @@ -67,10 +68,15 @@ const MenuBlockMention = observer(class MenuBlockMention extends React.Component cn.push('isHidden'); }; + let object = null; + if (![ 'add', 'selectDate' ].includes(item.id)) { + object = item; + }; + content = ( } onMouseEnter={e => this.onOver(e, item)} @@ -190,11 +196,30 @@ const MenuBlockMention = observer(class MenuBlockMention extends React.Component const { canAdd } = data; const filter = this.getFilter(); const sections: any[] = []; - const length = this.items.length; - const check = this.items.find(it => U.Object.isDateLayout(it.layout)); + + + let items = U.Common.objectCopy(this.items); + + const dates = items.filter(it => U.Object.isDateLayout(it.layout)); + + items = items.filter(it => !U.Object.isDateLayout(it.layout)); + + const length = items.length; + + if (dates.length) { + sections.push({ + id: 'date', + name: translate('commonDates'), + children: [ + ...dates, + { id: 'selectDate', icon: 'relation c-date', name: translate(`placeholderCell${I.RelationType.Date}`) }, + { isDiv: true }, + ] + }); + }; if (length) { - sections.push({ id: I.MarkType.Object, name: translate('commonObjects'), children: this.items }); + sections.push({ id: I.MarkType.Object, name: translate('commonObjects'), children: items.filter(it => !U.Object.isDateLayout(it.layout)) }); }; if (filter && canAdd) { @@ -302,7 +327,8 @@ const MenuBlockMention = observer(class MenuBlockMention extends React.Component return; }; - const { param, close } = this.props; + const { space } = S.Common; + const { param, getId } = this.props; const { data } = param; const { onChange } = data; const { from } = S.Common.filter; @@ -322,6 +348,8 @@ const MenuBlockMention = observer(class MenuBlockMention extends React.Component onChange(object, name + ' ', marks, from, to + 1); }; + let close = true; + if (item.id == 'add') { const name = this.getFilter(); @@ -330,12 +358,33 @@ const MenuBlockMention = observer(class MenuBlockMention extends React.Component }); } else if (item.id == 'selectDate') { - // TODO: Open calendar menu, call command that converts timestamp to date object and call callback + close = false; + + S.Menu.open('dataviewCalendar', { + element: `#${getId()} #item-${item.id}`, + horizontal: I.MenuDirection.Center, + data: { + rebind: this.rebind, + canEdit: true, + value: U.Date.now(), + onChange: (value: number) => { + C.ObjectDateByTimestamp(space, value, (message: any) => { + if (!message.error.code) { + cb(message.details); + this.props.close(); + }; + }); + }, + }, + }); + } else { cb(item); }; - close(); + if (close) { + this.props.close(); + }; }; getRowHeight (item: any) { diff --git a/src/ts/lib/api/command.ts b/src/ts/lib/api/command.ts index 8cebb9747c..4632b192bc 100644 --- a/src/ts/lib/api/command.ts +++ b/src/ts/lib/api/command.ts @@ -1773,6 +1773,15 @@ export const ObjectChatAdd = (objectId: string, callBack?: (message: any) => voi dispatcher.request(ObjectChatAdd.name, request, callBack); }; +export const ObjectDateByTimestamp = (spaceId: string, timestamp: number, callBack?: (message: any) => void) => { + const request = new Rpc.Object.DateByTimestamp.Request(); + + request.setSpaceid(spaceId); + request.setTimestamp(timestamp); + + dispatcher.request(ObjectDateByTimestamp.name, request, callBack); +}; + // ---------------------- OBJECT LIST ---------------------- // export const ObjectListDuplicate = (ids: string[], callBack?: (message: any) => void) => { diff --git a/src/ts/lib/api/response.ts b/src/ts/lib/api/response.ts index aa913d955c..0a576b1066 100644 --- a/src/ts/lib/api/response.ts +++ b/src/ts/lib/api/response.ts @@ -304,6 +304,12 @@ export const ObjectChatAdd = (response: Rpc.Object.ChatAdd.Response) => { }; }; +export const ObjectDateByTimestamp = (response: Rpc.Object.DateByTimestamp.Response) => { + return { + details: Decode.struct(response.getDetails()), + }; +}; + export const BlockCreate = (response: Rpc.Block.Create.Response) => { return { blockId: response.getBlockid(), From 9b029022478ddfbd8fb850202a75eed94f2cb09c Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Thu, 21 Nov 2024 16:31:16 +0100 Subject: [PATCH 15/85] Make calendar date selection work --- src/ts/component/page/main/date.tsx | 14 ++++---------- src/ts/lib/api/command.ts | 9 +++++++++ src/ts/lib/api/response.ts | 6 ++++++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index 417502e025..b00c92e512 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -66,9 +66,7 @@ const PageMainDate = observer(class PageMainDate extends React.Component
+ {/* TODO: remove sort when relations are returned in the order corresponding to UI design */} {relations.filter(r => r.relationKey !== 'links').sort((a,b) => a.relationKey === 'mentions' ? -1 : 1).flatMap((item, index) => { const relation = S.Record.getRelationByKey(item.relationKey); return ([
-
this.setValue(null, true, true)}>{translate('commonClear')}
+ {canClear &&
this.setValue(null, true, true)}>{translate('commonClear')}
}
diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index b00c92e512..17d45e0b01 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -38,7 +38,7 @@ const PageMainDate = observer(class PageMainDate extends React.Component; } else { - const calendarMenu = <> this.refCalIcon = ref} className="calendar" onClick={this.onCalendar}/>; + const calendarMenu = this.refCalIcon = ref} className="calendar" onClick={this.onCalendar}/>; content = (
@@ -162,6 +162,7 @@ const PageMainDate = observer(class PageMainDate extends React.Component { C.ObjectDateByTimestamp(U.Router.getRouteSpaceId(), value, (message: any) => { U.Object.openAuto(message.details); From 76bb93f51eff8de954facfd167eabb4da1d40572 Mon Sep 17 00:00:00 2001 From: Andrew Simachev Date: Thu, 21 Nov 2024 16:52:32 +0100 Subject: [PATCH 18/85] JS-5822: review --- src/img/icon/mention.svg | 3 + src/scss/list/object.scss | 15 +- src/scss/page/main/date.scss | 32 +-- src/ts/component/form/button.tsx | 10 +- .../component/page/elements/head/simple.tsx | 1 - src/ts/component/page/main/date.tsx | 189 ++++++++---------- 6 files changed, 116 insertions(+), 134 deletions(-) create mode 100644 src/img/icon/mention.svg diff --git a/src/img/icon/mention.svg b/src/img/icon/mention.svg new file mode 100644 index 0000000000..2fe792b284 --- /dev/null +++ b/src/img/icon/mention.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/scss/list/object.scss b/src/scss/list/object.scss index 46213be0ab..3af92399ae 100644 --- a/src/scss/list/object.scss +++ b/src/scss/list/object.scss @@ -1,23 +1,18 @@ @import "~scss/_mixins"; .listObject { - .table { display: grid; border-color: var(--color-shape-secondary); border-style: solid; border-top-width: 1px; margin: 0px 0px 10px 0px; } + .table { display: grid; margin: 0px 0px 10px 0px; } .table { .selectionTarget { display: grid; grid-template-columns: minmax(0, 1fr) 20% 20%; } - .row.isHead { - display: grid; grid-template-columns: minmax(0, 1fr) 20% 20%; color: var(--color-text-secondary); - } + .row.isHead { display: grid; grid-template-columns: minmax(0, 1fr) 20% 20%; color: var(--color-control-active); } .row.isHead { .cell { - text-align: left; padding: 14px 0px 14px 14px; white-space: nowrap; font-weight: 400; line-height: 20px; position: relative; + text-align: left; padding: 9px 0px 9px 14px; white-space: nowrap; font-weight: 400; line-height: 20px; position: relative; @include text-overflow-nw; } .cell { - .name { - display: inline-block; line-height: 20px; height: 20px; vertical-align: top; width: 100%; @include text-overflow-nw; - border-right: 1px solid var(--color-shape-secondary); - } + .name { display: inline-block; line-height: 20px; height: 20px; vertical-align: top; width: 100%; @include text-overflow-nw; } } .cell:last-child { .name { border: 0px; } @@ -31,7 +26,7 @@ .row.isSelectionSelected { background-color: var(--color-system-selection); } .row { - .cell { padding: 14px; vertical-align: top; position: relative; word-break: break-word; } + .cell { padding: 9px 14px; vertical-align: top; position: relative; word-break: break-word; } .cellContent { width: 100%; overflow: hidden; height: 20px; line-height: 20px; } .cellContent { diff --git a/src/scss/page/main/date.scss b/src/scss/page/main/date.scss index fb8b494e81..5a825637a9 100644 --- a/src/scss/page/main/date.scss +++ b/src/scss/page/main/date.scss @@ -1,18 +1,22 @@ @import "~scss/_mixins"; -.pageMainDate .side.right { - .icon.calendar { width: 24px; height: 24px; background-size: 20px; background-image: url('~img/icon/relation/date.svg'); border-radius: 4px; } - .icon.arrow { - width: 24px; height: 24px; background-size: 20px; background-image: url('~img/arrow/dateSelectLight.svg'); border-radius: 4px; - transition: $transitionAllCommon; - } - .icon.arrow.left { transform: rotateZ(180deg); } -} +.pageMainDate { + .wrapper { width: 704px; margin: 0px auto; padding: 40px 0px 80px 0px; user-select: none; } -.pageMainDate .categories { display: flex; flex-direction: row; gap: 8px 8px; align-items: center; justify-content: flex-start; flex-wrap: wrap; } -.pageMainDate .separator { background-color: var(--color-shape-secondary); width: 1px; height: 24px; } + .headSimple { + .side.right { gap: 0px; } + .side.right { + .icon.calendar { background-image: url('~img/icon/relation/date.svg'); } + .icon.arrow { background-image: url('~img/arrow/dateSelectLight.svg'); } + .icon.arrow.left { transform: rotateZ(180deg); } + } + } -.pageMainDate .mentionsSign { padding-right: 8px; font-size: 16px; color: var(--color-control-active); } - -.dateList .table { border-top-width: 0px !important; } -.dateList .table .isHead .cell > div { border-right-width: 0px !important; } \ No newline at end of file + .categories { + display: flex; flex-direction: row; gap: 8px; margin: 0px 0px 12px 0px; align-items: center; justify-content: flex-start; flex-wrap: wrap; + } + .categories { + .icon.mention { width: 20px; height: 20px; margin: 0px 6px 0px 0px; background-image: url('~img/icon/mention.svg'); } + .separator { content: ''; background-color: var(--color-shape-secondary); width: 1px; height: 24px; } + } +} \ No newline at end of file diff --git a/src/ts/component/form/button.tsx b/src/ts/component/form/button.tsx index 3ba54e85bb..377729295c 100644 --- a/src/ts/component/form/button.tsx +++ b/src/ts/component/form/button.tsx @@ -47,14 +47,13 @@ const Button = forwardRef(({ onMouseLeave, onMouseDown, dataset, - content, active, }, ref) => { const [ isLoading, setIsLoading ] = useState(false); const nodeRef = useRef(null); const cn = [ 'button', color, className ]; - let innerContent = null; + let content = null; if (isLoading) { cn.push('isLoading'); @@ -103,7 +102,7 @@ const Button = forwardRef(({ switch (type) { case 'input': { - innerContent = ( + content = ( (({ }; default: { - innerContent = ( + content = (
(({ > {isLoading && } {icon && } - {content}
{arrow &&
}
@@ -141,7 +139,7 @@ const Button = forwardRef(({ }; }; - return innerContent; + return content; }); export default Button; \ No newline at end of file diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index af211f8167..f3902db079 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -53,7 +53,6 @@ const HeadSimple = observer(class Controls extends React.Component { if (isDate) { cn.push('isDate'); }; - const titleCn = [ 'title' ]; const placeholder = { title: this.props.placeholder, description: translate('placeholderBlockDescription'), diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index 71c4df710c..716f3484be 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -3,22 +3,17 @@ import $ from 'jquery'; import raf from 'raf'; import { observer } from 'mobx-react'; import { Header, Footer, Loader, Deleted, ListObject, Button, Icon } from 'Component'; -import { I, M, C, S, U, J, Action, keyboard, translate } from 'Lib'; +import { I, C, S, U, Action, translate } from 'Lib'; import Controls from 'Component/page/elements/head/controls'; import HeadSimple from 'Component/page/elements/head/simple'; interface State { isLoading: boolean; isDeleted: boolean; - relations: Item[]; + relations: any[]; selectedRelation: string; }; -interface Item { - relationKey: string; - counter: number; -} - const SUB_ID = 'dateListObject'; const PageMainDate = observer(class PageMainDate extends React.Component { @@ -30,7 +25,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component; } else { - const calendarMenu = <> this.refCalIcon = ref} className="calendar" onClick={this.onCalendar}/>; + const calendarMenu = ( + + + + + + ); content = (
- this.refControls = ref} key="editorControls" {...this.props} rootId={rootId} resize={this.resize} /> - this.refHead = ref} - placeholder={''} - rootId={rootId} - readonly={this.isReadonly()} - rightSideEnd={calendarMenu} - /> + this.refHead = ref} + rootId={rootId} + readonly={true} + rightSideEnd={calendarMenu} + /> -
- {relations.sort((a,b) => a.relationKey === 'mentions' ? -1 : 1).map((item, index) => { - const relation = S.Record.getRelationByKey(item.relationKey); - return (<>
-
- this.refList = ref} - {...this.props} - spaceId={space} - subId={SUB_ID} - rootId={rootId} - columns={columns} - filters={filters} - /> -
+
+ {relations.map((item) => { + const isMention = item.relationKey == 'mentions'; + const icon = isMention ? 'mention' : ''; + const separator = isMention ?
: ''; + + return ( + +
+ +
+ this.refList = ref} + {...this.props} + spaceId={space} + subId={SUB_ID} + rootId={rootId} + columns={columns} + filters={filters} + /> +
+
); }; return (
this.node = node}> -
-
- {content} -
-
+
this.refHeader = ref} + rootId={object.chatId} + /> + + {content}
@@ -147,15 +153,13 @@ const PageMainDate = observer(class PageMainDate extends React.Component { - const node = $(this.refCalIcon.node); const rootId = this.getRootId(); const object = S.Detail.get(rootId, rootId, ['timestamp']); S.Menu.open('dataviewCalendar', { - element: node, + element: '#calendar-icon', horizontal: I.MenuDirection.Center, data: { - // rebind: this.rebind, value: object.timestamp, canEdit: true, onChange: (value: number) => { @@ -168,26 +172,16 @@ const PageMainDate = observer(class PageMainDate extends React.Component { + const relations = (message.relations || []).map(it => S.Record.getRelationByKey(it.relationKey)).filter(it => { + if ([ 'mentions' ].includes(it.relationKey)) { + return true; + }; - console.log(object); + if ([ 'links', 'backlinks' ].includes(it.relationKey)) { + return false; + }; - C.RelationListWithValue(space, object.id, (message: any) => { - this.setState({ relations: message.relations }); + return config.debug.hidden ? true : !it.isHidden; + }); + + relations.sort((c1, c2) => { + const isMention1 = c1.relationKey == 'mentions'; + const isMention2 = c2.relationKey == 'mentions'; + + if (isMention1 && !isMention2) return -1; + if (!isMention1 && isMention2) return 1; + return 0; + }); + + this.setState({ relations }); }); } @@ -270,32 +279,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component { - const win = $(window); - const container = U.Common.getPageContainer(isPopup); - - container.css({ minHeight: isPopup ? '' : win.height() }); - }); - }; }); export default PageMainDate; From 2594372024af17a356c7c7969d1bc1234520ccc5 Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Thu, 21 Nov 2024 18:44:56 +0100 Subject: [PATCH 19/85] Clean up --- src/ts/component/page/main/date.tsx | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index 17d45e0b01..22c23534ca 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -1,6 +1,5 @@ import * as React from 'react'; import $ from 'jquery'; -import raf from 'raf'; import { observer } from 'mobx-react'; import { Header, Footer, Loader, Deleted, ListObject, Button, Icon } from 'Component'; import { I, M, C, S, U, J, Action, keyboard, translate } from 'Lib'; @@ -47,10 +46,27 @@ const PageMainDate = observer(class PageMainDate extends React.Component { + const rootId = this.getRootId(); + const object = S.Detail.get(rootId, rootId, ['timestamp']); + C.ObjectDateByTimestamp(U.Router.getRouteSpaceId(), object.timestamp - 24 * 60 * 60, (message: any) => { + U.Object.openAuto(message.details); + }); + }; + + nextDate = () => { + const rootId = this.getRootId(); + const object = S.Detail.get(rootId, rootId, ['timestamp']); + console.log(object.timestamp); + C.ObjectDateByTimestamp(U.Router.getRouteSpaceId(), object.timestamp + 24 * 60 * 60, (message: any) => { + U.Object.openAuto(message.details); + }); + }; + render () { const { space } = S.Common; const { isLoading, isDeleted, relations, selectedRelation } = this.state; - const rootId = this.getRootId(); + const rootId = this.getRootId(); const check = U.Data.checkDetails(rootId); const object = S.Detail.get(rootId, rootId, ['timestamp']); @@ -66,7 +82,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component; } else { - const calendarMenu = this.refCalIcon = ref} className="calendar" onClick={this.onCalendar}/>; + const calendarMenu = this.refCalIcon = ref} className="calendar withBackground" onClick={this.onCalendar}/>; content = (
@@ -102,7 +117,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component
- {/* TODO: remove sort when relations are returned in the order corresponding to UI design */} {relations.filter(r => r.relationKey !== 'links').sort((a,b) => a.relationKey === 'mentions' ? -1 : 1).flatMap((item, index) => { const relation = S.Record.getRelationByKey(item.relationKey); return ([
); @@ -291,26 +299,34 @@ const HeadSimple = observer(class Controls extends React.Component { return sources.includes(rootId); }; - onCalendar () { + onCalendar = () => { const { rootId } = this.props; - const object = S.Detail.get(rootId, rootId); + const object = S.Detail.get(rootId, rootId, ['timestamp']); S.Menu.open('dataviewCalendar', { - element: `#head-calendar-button`, + element: '#calendar-icon', horizontal: I.MenuDirection.Center, - data: { - value: object.timestamp, + data: { + value: object.timestamp, canEdit: true, + canClear: false, onChange: (value: number) => { - console.log('TIMESTAMP', value); - - // TODO: Get date id from timestamp and route to new date object - + C.ObjectDateByTimestamp(U.Router.getRouteSpaceId(), value, (message: any) => { + U.Object.openAuto(message.details); + }); }, }, }); }; + changeDate = (dir: number) => { + const { rootId } = this.props; + const object = S.Detail.get(rootId, rootId, ['timestamp']); + C.ObjectDateByTimestamp(U.Router.getRouteSpaceId(), object.timestamp + dir * 24 * 60 * 60, (message: any) => { + U.Object.openAuto(message.details); + }); + }; + }); export default HeadSimple; \ No newline at end of file diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index fcbd989550..300eb59cc7 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -68,14 +68,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component; } else { - const calendarMenu = ( - - this.changeDate(-1)} /> - this.changeDate(1)}/> - - - ); - content = (
this.refHead = ref} rootId={rootId} readonly={true} - rightSideEnd={calendarMenu} />
@@ -145,26 +136,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component { - const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId, ['timestamp']); - - S.Menu.open('dataviewCalendar', { - element: '#calendar-icon', - horizontal: I.MenuDirection.Center, - data: { - value: object.timestamp, - canEdit: true, - canClear: false, - onChange: (value: number) => { - C.ObjectDateByTimestamp(U.Router.getRouteSpaceId(), value, (message: any) => { - U.Object.openAuto(message.details); - }); - }, - }, - }); - }; - componentDidMount () { this._isMounted = true; this.open(); @@ -270,14 +241,6 @@ const PageMainDate = observer(class PageMainDate extends React.Component { - const rootId = this.getRootId(); - const object = S.Detail.get(rootId, rootId, ['timestamp']); - C.ObjectDateByTimestamp(U.Router.getRouteSpaceId(), object.timestamp + dir * 24 * 60 * 60, (message: any) => { - U.Object.openAuto(message.details); - }); - }; - getRootId () { const { rootId, match } = this.props; return rootId ? rootId : match.params.id; From ea26a9db8d0c938e22b409cc65a7b1e9d6f29c9e Mon Sep 17 00:00:00 2001 From: "Nikita Dudnik (nek)" Date: Fri, 22 Nov 2024 13:54:21 +0100 Subject: [PATCH 26/85] Code review fixes --- src/json/text.json | 4 +++- src/scss/component/editor.scss | 15 ++++++--------- src/scss/form/button.scss | 7 +++---- src/scss/page/main/date.scss | 6 +++++- src/ts/component/form/button.tsx | 1 - src/ts/component/page/elements/head/simple.tsx | 8 ++++++-- src/ts/component/page/main/date.tsx | 12 ++++++------ 7 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/json/text.json b/src/json/text.json index 1327252014..e0e8c6f953 100644 --- a/src/json/text.json +++ b/src/json/text.json @@ -2256,5 +2256,7 @@ "formulaCheckboxEmpty": "Count unchecked", "formulaCheckboxNotEmpty": "Count checked", "formulaCheckboxPercentEmpty": "Percentage unchecked", - "formulaCheckboxPercentNotEmpty": "Percentage checked" + "formulaCheckboxPercentNotEmpty": "Percentage checked", + + "creator": "Created by" } diff --git a/src/scss/component/editor.scss b/src/scss/component/editor.scss index 5747ed5d0c..d3b6f5a21b 100644 --- a/src/scss/component/editor.scss +++ b/src/scss/component/editor.scss @@ -236,15 +236,6 @@ } } -.editorWrapper.isSet, -.editorWrapper.isCollection { - .blocks { - .headSimple { - .side.right { display: none; } - } - } -} - .editorWrapper.isSet, .editorWrapper.isCollection { &.withIcon { @@ -264,6 +255,12 @@ &.withIconAndCover { .editorControls { display: none; } } + + .blocks { + .headSimple { + .side.right { display: none; } + } + } } .editorWrapper.isSet, diff --git a/src/scss/form/button.scss b/src/scss/form/button.scss index 5202301673..cd78128967 100644 --- a/src/scss/form/button.scss +++ b/src/scss/form/button.scss @@ -37,10 +37,9 @@ .button.dark:not(.disabled).hover { background: rgba(0,0,0,0.4); } .button.blank { background: none; border: solid 1px var(--color-shape-primary); font-weight: 400; } -.button.blank:not(.disabled):hover, -.button.blank:not(.disabled).hover { background: var(--color-shape-highlight-medium); } - -.pageMainDate .button.active { background: var(--color-shape-highlight-medium); } +.button.blank:not(.disabled) { + &:hover, &.hover, &.active { background: var(--color-shape-highlight-medium); } +} .button.c36 { @include text-common; height: 36px; border-radius: 6px; padding: 0px 12px; } .button.c32 { @include text-small; height: 32px; border-radius: 6px; padding: 0px 10px; } diff --git a/src/scss/page/main/date.scss b/src/scss/page/main/date.scss index 4b622b6e07..620a1ef6e4 100644 --- a/src/scss/page/main/date.scss +++ b/src/scss/page/main/date.scss @@ -6,6 +6,7 @@ .headSimple { .side.right { gap: 0px; } .side.right { + .icon { width: 24px !important; height: 24px !important; } .icon.calendar { background-image: url('~img/icon/relation/date.svg'); } .icon.arrow { background-image: url('~img/arrow/dateSelectLight.svg'); } .icon.arrow.left { transform: rotateZ(180deg); } @@ -19,5 +20,8 @@ .icon.mention { width: 20px; height: 20px; margin: 0px 6px 0px 0px; background-image: url('~img/icon/mention.svg'); } .separator { content: ''; background-color: var(--color-shape-secondary); width: 1px; height: 24px; } } - .cell.c-type { .iconObject { display: none; } } + + .cell.c-type { + .iconObject { display: none; } + } } \ No newline at end of file diff --git a/src/ts/component/form/button.tsx b/src/ts/component/form/button.tsx index 377729295c..2e56b1afa7 100644 --- a/src/ts/component/form/button.tsx +++ b/src/ts/component/form/button.tsx @@ -10,7 +10,6 @@ interface ButtonProps { icon?: string; arrow?: boolean; text?: string; - content?: React.ReactElement; active?: boolean; color?: string; className?: string; diff --git a/src/ts/component/page/elements/head/simple.tsx b/src/ts/component/page/elements/head/simple.tsx index be9a47cd47..2f1e4b2a41 100644 --- a/src/ts/component/page/elements/head/simple.tsx +++ b/src/ts/component/page/elements/head/simple.tsx @@ -47,10 +47,13 @@ const HeadSimple = observer(class Controls extends React.Component { const isDate = U.Object.isDateLayout(object.layout); const isRelation = U.Object.isRelationLayout(object.layout); const canEditIcon = allowDetails && !U.Object.isRelationLayout(object.layout); + const cn = [ 'headSimple', check.className ]; + if (isDate) { cn.push('isDate'); }; + const placeholder = { title: this.props.placeholder, description: translate('placeholderBlockDescription'), @@ -301,7 +304,8 @@ const HeadSimple = observer(class Controls extends React.Component { onCalendar = () => { const { rootId } = this.props; - const object = S.Detail.get(rootId, rootId, ['timestamp']); + const { space } = S.Common; + const object = S.Detail.get(rootId, rootId, [ 'timestamp' ]); S.Menu.open('dataviewCalendar', { element: '#calendar-icon', @@ -311,7 +315,7 @@ const HeadSimple = observer(class Controls extends React.Component { canEdit: true, canClear: false, onChange: (value: number) => { - C.ObjectDateByTimestamp(U.Router.getRouteSpaceId(), value, (message: any) => { + C.ObjectDateByTimestamp(space, value, (message: any) => { U.Object.openAuto(message.details); }); }, diff --git a/src/ts/component/page/main/date.tsx b/src/ts/component/page/main/date.tsx index 300eb59cc7..136f8b54ce 100644 --- a/src/ts/component/page/main/date.tsx +++ b/src/ts/component/page/main/date.tsx @@ -43,16 +43,15 @@ const PageMainDate = observer(class PageMainDate extends React.Component; }; - const creatorRelation = S.Record.getRelationByKey('creator'); const columns: any[] = [ { relationKey: 'type', name: translate('commonObjectType'), isObject: true }, - { relationKey: creatorRelation.relationKey, name: creatorRelation.name, isObject: true }, + { relationKey: 'creator', name: translate('creator'), isObject: true }, ]; const filters: I.Filter[] = []; @@ -84,6 +83,7 @@ const PageMainDate = observer(class PageMainDate extends React.Component : ''; + return (
+ +
+
-
+