1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-17 15:53:28 +00:00

upgrade react-dnd react-dnd-html5-backend

This commit is contained in:
zhouwenxuan
2025-04-21 11:02:49 +08:00
parent b43ad4132b
commit bba5014f6d
10 changed files with 320 additions and 332 deletions

View File

@@ -46,8 +46,8 @@
"react-app-polyfill": "^2.0.0", "react-app-polyfill": "^2.0.0",
"react-chartjs-2": "5.3.0", "react-chartjs-2": "5.3.0",
"react-cookies": "^0.1.0", "react-cookies": "^0.1.0",
"react-dnd": "^2.6.0", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^2.6.0", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-i18next": "^10.12.2", "react-i18next": "^10.12.2",
"react-mentions": "4.4.10", "react-mentions": "4.4.10",
@@ -3106,19 +3106,6 @@
} }
} }
}, },
"node_modules/@emotion/react/node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"dependencies": {
"react-is": "^16.7.0"
}
},
"node_modules/@emotion/react/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/@emotion/serialize": { "node_modules/@emotion/serialize": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz",
@@ -5391,6 +5378,21 @@
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
"integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==" "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="
}, },
"node_modules/@react-dnd/asap": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz",
"integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A=="
},
"node_modules/@react-dnd/invariant": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz",
"integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw=="
},
"node_modules/@react-dnd/shallowequal": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz",
"integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA=="
},
"node_modules/@replit/codemirror-lang-csharp": { "node_modules/@replit/codemirror-lang-csharp": {
"version": "6.2.0", "version": "6.2.0",
"resolved": "https://registry.npmmirror.com/@replit/codemirror-lang-csharp/-/codemirror-lang-csharp-6.2.0.tgz", "resolved": "https://registry.npmmirror.com/@replit/codemirror-lang-csharp/-/codemirror-lang-csharp-6.2.0.tgz",
@@ -11612,12 +11614,6 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/disposables": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/disposables/-/disposables-1.0.2.tgz",
"integrity": "sha512-q1XTvs/XGdfubRSemB2+QRhJjIX4PerKkSom+i8Nkw3hCv6xISNrgaN442n2BunyBI4x77Om4ZAzSlqmhM9pwA==",
"license": "Apache-2.0"
},
"node_modules/dlv": { "node_modules/dlv": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz", "resolved": "https://registry.npmmirror.com/dlv/-/dlv-1.1.3.tgz",
@@ -11626,15 +11622,13 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/dnd-core": { "node_modules/dnd-core": {
"version": "2.6.0", "version": "16.0.1",
"resolved": "https://registry.npmmirror.com/dnd-core/-/dnd-core-2.6.0.tgz", "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz",
"integrity": "sha512-5BfQHIp0XVd4ioF0q4GyUeHQQNCbqP+0SnUiP9TssoQ50wrP1NgSzDqZkjD5pFngsVz9txGin6rvTQD7w0qC3w==", "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==",
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"asap": "^2.0.6", "@react-dnd/asap": "^5.0.1",
"invariant": "^2.0.0", "@react-dnd/invariant": "^4.0.1",
"lodash": "^4.2.0", "redux": "^4.2.0"
"redux": "^3.7.1"
} }
}, },
"node_modules/dns-packet": { "node_modules/dns-packet": {
@@ -13510,7 +13504,6 @@
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-glob": { "node_modules/fast-glob": {
@@ -15283,10 +15276,17 @@
} }
}, },
"node_modules/hoist-non-react-statics": { "node_modules/hoist-non-react-statics": {
"version": "2.5.5", "version": "3.3.2",
"resolved": "https://registry.npmmirror.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"license": "BSD-3-Clause" "dependencies": {
"react-is": "^16.7.0"
}
},
"node_modules/hoist-non-react-statics/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
}, },
"node_modules/hoopy": { "node_modules/hoopy": {
"version": "0.1.4", "version": "0.1.4",
@@ -24069,29 +24069,40 @@
} }
}, },
"node_modules/react-dnd": { "node_modules/react-dnd": {
"version": "2.6.0", "version": "16.0.1",
"resolved": "https://registry.npmmirror.com/react-dnd/-/react-dnd-2.6.0.tgz", "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz",
"integrity": "sha512-2KHNpeg2SyaxXYq+xO1TM+tOtN9hViI41otJuiYiu6DRYGw+WMvDFDMP4aw7zIKRRm1xd0gizXuKWhb8iJYHBw==", "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==",
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"disposables": "^1.0.1", "@react-dnd/invariant": "^4.0.1",
"dnd-core": "^2.6.0", "@react-dnd/shallowequal": "^4.0.1",
"hoist-non-react-statics": "^2.1.0", "dnd-core": "^16.0.1",
"invariant": "^2.1.0", "fast-deep-equal": "^3.1.3",
"lodash": "^4.2.0", "hoist-non-react-statics": "^3.3.2"
"prop-types": "^15.5.10"
}, },
"peerDependencies": { "peerDependencies": {
"react": "*" "@types/hoist-non-react-statics": ">= 3.3.1",
"@types/node": ">= 12",
"@types/react": ">= 16",
"react": ">= 16.14"
},
"peerDependenciesMeta": {
"@types/hoist-non-react-statics": {
"optional": true
},
"@types/node": {
"optional": true
},
"@types/react": {
"optional": true
}
} }
}, },
"node_modules/react-dnd-html5-backend": { "node_modules/react-dnd-html5-backend": {
"version": "2.6.0", "version": "16.0.1",
"resolved": "https://registry.npmmirror.com/react-dnd-html5-backend/-/react-dnd-html5-backend-2.6.0.tgz", "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz",
"integrity": "sha512-8gOfBfqFikWmXvAGSZz1mgoctwkcsKdUC9POt/WGnMoZwGB4ivB0Ex5D6pwHTNjvAs0ixqqWdJKy57CzjDg5Sg==", "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==",
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"lodash": "^4.2.0" "dnd-core": "^16.0.1"
} }
}, },
"node_modules/react-dom": { "node_modules/react-dom": {
@@ -24436,15 +24447,11 @@
} }
}, },
"node_modules/redux": { "node_modules/redux": {
"version": "3.7.2", "version": "4.2.1",
"resolved": "https://registry.npmmirror.com/redux/-/redux-3.7.2.tgz", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
"license": "MIT",
"dependencies": { "dependencies": {
"lodash": "^4.2.1", "@babel/runtime": "^7.9.2"
"lodash-es": "^4.2.1",
"loose-envify": "^1.1.0",
"symbol-observable": "^1.0.3"
} }
}, },
"node_modules/reflect.getprototypeof": { "node_modules/reflect.getprototypeof": {
@@ -28510,15 +28517,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/symbol-tree": { "node_modules/symbol-tree": {
"version": "3.2.4", "version": "3.2.4",
"resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz", "resolved": "https://registry.npmmirror.com/symbol-tree/-/symbol-tree-3.2.4.tgz",

View File

@@ -41,8 +41,8 @@
"react-app-polyfill": "^2.0.0", "react-app-polyfill": "^2.0.0",
"react-chartjs-2": "5.3.0", "react-chartjs-2": "5.3.0",
"react-cookies": "^0.1.0", "react-cookies": "^0.1.0",
"react-dnd": "^2.6.0", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^2.6.0", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-i18next": "^10.12.2", "react-i18next": "^10.12.2",
"react-mentions": "4.4.10", "react-mentions": "4.4.10",

View File

@@ -3,6 +3,8 @@ import { createRoot } from 'react-dom/client';
import { Router, navigate, LocationProvider, globalHistory } from '@gatsbyjs/reach-router'; import { Router, navigate, LocationProvider, globalHistory } from '@gatsbyjs/reach-router';
import MediaQuery from 'react-responsive'; import MediaQuery from 'react-responsive';
import { Modal } from 'reactstrap'; import { Modal } from 'reactstrap';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { siteRoot, siteTitle, mediaUrl, faviconPath } from './utils/constants'; import { siteRoot, siteTitle, mediaUrl, faviconPath } from './utils/constants';
import { Utils, isMobile } from './utils/utils'; import { Utils, isMobile } from './utils/utils';
import SystemNotification from './components/system-notification'; import SystemNotification from './components/system-notification';
@@ -315,44 +317,46 @@ class App extends Component {
/> />
} }
<div className="main-panel" style={mainPanelStyle}> <div className="main-panel" style={mainPanelStyle}>
<Router className="reach-router"> <DndProvider backend={HTML5Backend}>
<Libraries path={siteRoot} /> <Router className="reach-router">
<Libraries path={siteRoot + 'libraries'} /> <Libraries path={siteRoot} />
<MyLibraries path={siteRoot + 'my-libs'} /> <Libraries path={siteRoot + 'libraries'} />
<MyLibDeleted path={siteRoot + 'my-libs/deleted/'} /> <MyLibraries path={siteRoot + 'my-libs'} />
<ShareAdminShareLinks path={siteRoot + 'share-admin-share-links'} /> <MyLibDeleted path={siteRoot + 'my-libs/deleted/'} />
<ShareAdminUploadLinks path={siteRoot + 'share-admin-upload-links'} /> <ShareAdminShareLinks path={siteRoot + 'share-admin-share-links'} />
<SharedWithAll path={siteRoot + 'org/'} /> <ShareAdminUploadLinks path={siteRoot + 'share-admin-upload-links'} />
<Wikis <SharedWithAll path={siteRoot + 'org/'} />
path={siteRoot + 'published'} <Wikis
sidePanelRate={sidePanelRate} path={siteRoot + 'published'}
isSidePanelFolded={isSidePanelFolded} sidePanelRate={sidePanelRate}
/> isSidePanelFolded={isSidePanelFolded}
<Starred path={siteRoot + 'starred'} /> />
<InvitationsView path={siteRoot + 'invitations/'} /> <Starred path={siteRoot + 'starred'} />
<FilesActivities path={siteRoot + 'dashboard'} /> <InvitationsView path={siteRoot + 'invitations/'} />
<MyFileActivities path={siteRoot + 'my-activities'} /> <FilesActivities path={siteRoot + 'dashboard'} />
<GroupView path={siteRoot + 'group/:groupID'} /> <MyFileActivities path={siteRoot + 'my-activities'} />
<LinkedDevices path={siteRoot + 'linked-devices'} /> <GroupView path={siteRoot + 'group/:groupID'} />
<ShareAdminLibraries path={siteRoot + 'share-admin-libs'} /> <LinkedDevices path={siteRoot + 'linked-devices'} />
<ShareAdminFolders path={siteRoot + 'share-admin-folders'} /> <ShareAdminLibraries path={siteRoot + 'share-admin-libs'} />
<SharedLibraries path={siteRoot + 'shared-libs'} /> <ShareAdminFolders path={siteRoot + 'share-admin-folders'} />
<ShareWithOCM path={siteRoot + 'shared-with-ocm'} /> <SharedLibraries path={siteRoot + 'shared-libs'} />
<OCMViaWebdav path={siteRoot + 'ocm-via-webdav'} /> <ShareWithOCM path={siteRoot + 'shared-with-ocm'} />
<OCMRepoDir <OCMViaWebdav path={siteRoot + 'ocm-via-webdav'} />
path={siteRoot + 'remote-library/:providerID/:repoID/*'} <OCMRepoDir
pathPrefix={this.state.pathPrefix} path={siteRoot + 'remote-library/:providerID/:repoID/*'}
onTabNavClick={this.tabItemClick} pathPrefix={this.state.pathPrefix}
/> onTabNavClick={this.tabItemClick}
<LibContentView />
path={siteRoot + 'library/:repoID/*'} <LibContentView
pathPrefix={this.state.pathPrefix} path={siteRoot + 'library/:repoID/*'}
isSidePanelFolded={isSidePanelFolded} pathPrefix={this.state.pathPrefix}
onTabNavClick={this.tabItemClick} isSidePanelFolded={isSidePanelFolded}
eventBus={this.eventBus} onTabNavClick={this.tabItemClick}
resetTitle={this.resetTitle} eventBus={this.eventBus}
/> resetTitle={this.resetTitle}
</Router> />
</Router>
</DndProvider>
</div> </div>
<MediaQuery query="(max-width: 767.8px)"> <MediaQuery query="(max-width: 767.8px)">
<Modal zIndex="1030" isOpen={!isSidePanelClosed} toggle={this.toggleSidePanel} contentClassName="d-none"></Modal> <Modal zIndex="1030" isOpen={!isSidePanelClosed} toggle={this.toggleSidePanel} contentClassName="d-none"></Modal>

View File

@@ -1,7 +1,7 @@
import React, { Fragment, useCallback, useMemo } from 'react'; import React, { Fragment, useCallback, useMemo, useRef } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import { DragSource, DropTarget } from 'react-dnd'; import { useDrag, useDrop } from 'react-dnd';
import CustomizeSelect from '../../../../../components/customize-select'; import CustomizeSelect from '../../../../../components/customize-select';
import Icon from '../../../../../components/icon'; import Icon from '../../../../../components/icon';
import { gettext } from '../../../../../utils/constants'; import { gettext } from '../../../../../utils/constants';
@@ -9,49 +9,6 @@ import { getColumnByKey } from '../../../../utils/column';
import { COLUMNS_ICON_CONFIG, SORT_TYPE, SORT_COLUMN_OPTIONS } from '../../../../constants'; import { COLUMNS_ICON_CONFIG, SORT_TYPE, SORT_COLUMN_OPTIONS } from '../../../../constants';
import { getGroupbyGranularityByColumn, isShowGroupCountType, getSelectedCountType, getDefaultCountType } from '../../../../utils/group'; import { getGroupbyGranularityByColumn, isShowGroupCountType, getSelectedCountType, getDefaultCountType } from '../../../../utils/group';
const dragSource = {
beginDrag: props => {
return { idx: props.index, data: props.groupby, mode: 'sfMetadataGroupbyItem' };
},
endDrag(props, monitor) {
const groupSource = monitor.getItem();
const didDrop = monitor.didDrop();
let groupTarget = {};
if (!didDrop) {
return { groupSource, groupTarget };
}
},
isDragging(props) {
const { index, dragged } = props;
const { idx } = dragged;
return idx > index;
}
};
const dropTarget = {
drop(props, monitor) {
const groupSource = monitor.getItem();
const { index: targetIdx } = props;
if (targetIdx !== groupSource.idx) {
let groupTarget = { idx: targetIdx, data: props.groupby };
props.onMove(groupSource, groupTarget);
}
}
};
const dragCollect = (connect, monitor) => ({
connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(),
isDragging: monitor.isDragging(),
});
const dropCollect = (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
dragged: monitor.getItem(),
});
/* /*
groupby: { groupby: {
column_key: 'xxx', column_key: 'xxx',
@@ -59,10 +16,39 @@ const dropCollect = (connect, monitor) => ({
sort_type: 'xxx', sort_type: 'xxx',
} }
*/ */
const GroupbyItem = ({ const GroupbyItem = ({ showDragBtn, index, readOnly, groupby, columns, onDelete, onUpdate, onMove }) => {
isOver, isDragging, canDrop, connectDragSource, connectDragPreview, connectDropTarget, const ref = useRef(null);
showDragBtn, index, readOnly, groupby, columns, onDelete, onUpdate
}) => { // drag and drop
const [{ isDragging }, drag] = useDrag({
type: 'sfMetadataGroupbyItem',
item: () => ({
idx: index,
data: groupby,
}),
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
const [{ isOver, canDrop }, drop] = useDrop({
accept: 'sfMetadataGroupbyItem',
hover: (item) => {
if (item.idx !== index) {
onMove(
{ idx: item.idx, data: item.data },
{ idx: index, data: groupby }
);
item.idx = index;
}
},
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
})
});
const dragDropRef = drag(drop(ref));
const column = useMemo(() => { const column = useMemo(() => {
return getColumnByKey(columns, groupby.column_key); return getColumnByKey(columns, groupby.column_key);
}, [groupby, columns]); }, [groupby, columns]);
@@ -165,59 +151,58 @@ const GroupbyItem = ({
onUpdate(newGroupby, index); onUpdate(newGroupby, index);
}, [groupby, index, onUpdate]); }, [groupby, index, onUpdate]);
return connectDropTarget( return (
connectDragPreview( <div
<div ref={dragDropRef}
className={classnames('groupby-item', className={classnames('groupby-item',
{ 'group-can-drop-top': isOver && canDrop && isDragging }, { 'group-can-drop-top': isOver && canDrop && isDragging },
{ 'group-can-drop': isOver && canDrop && !isDragging } { 'group-can-drop': isOver && canDrop && !isDragging }
)} )}
> >
{!readOnly && ( {!readOnly && (
<div className="delete-groupby" onClick={deleteGroupby} aria-label={gettext('Delete')}> <div className="delete-groupby" onClick={deleteGroupby} aria-label={gettext('Delete')}>
<Icon className="sf-metadata-icon" symbol="fork-number"/> <Icon className="sf-metadata-icon" symbol="fork-number"/>
</div> </div>
)} )}
<div className="condition"> <div className="condition">
<div className="groupby-column"> <div className="groupby-column">
<CustomizeSelect
readOnly={readOnly}
value={selectedColumn}
options={columnsOptions}
onSelectOption={selectColumn}
searchable={true}
searchPlaceholder={gettext('Search property')}
noOptionsPlaceholder={gettext('No results')}
/>
</div>
{isShowGroupCountType(column) && (
<div className="groupby-count-type">
<CustomizeSelect <CustomizeSelect
readOnly={readOnly} readOnly={readOnly}
value={selectedColumn} value={selectedCountType}
options={columnsOptions} onSelectOption={selectCountType}
onSelectOption={selectColumn} options={countTypeOptions}
searchable={true}
searchPlaceholder={gettext('Search property')}
noOptionsPlaceholder={gettext('No results')}
/> />
</div> </div>
{isShowGroupCountType(column) && (
<div className="groupby-count-type">
<CustomizeSelect
readOnly={readOnly}
value={selectedCountType}
onSelectOption={selectCountType}
options={countTypeOptions}
/>
</div>
)}
<div className="groupby-predicate">
{(!column.key || SORT_COLUMN_OPTIONS.includes(column.type)) && (
<CustomizeSelect
readOnly={readOnly}
value={selectedSortType}
options={sortOptions}
onSelectOption={selectSortType}
/>
)}
</div>
</div>
{!readOnly && showDragBtn && connectDragSource(
<div className="groupby-drag">
<Icon symbol="drag" />
</div>
)} )}
<div className="groupby-predicate">
{(!column.key || SORT_COLUMN_OPTIONS.includes(column.type)) && (
<CustomizeSelect
readOnly={readOnly}
value={selectedSortType}
options={sortOptions}
onSelectOption={selectSortType}
/>
)}
</div>
</div> </div>
) {!readOnly && showDragBtn && (
<div className="groupby-drag">
<Icon symbol="drag" />
</div>
)}
</div>
); );
}; };
@@ -229,16 +214,7 @@ GroupbyItem.propTypes = {
columns: PropTypes.array, columns: PropTypes.array,
onDelete: PropTypes.func, onDelete: PropTypes.func,
onUpdate: PropTypes.func, onUpdate: PropTypes.func,
onMove: PropTypes.func,
// drag
isDragging: PropTypes.bool,
isOver: PropTypes.bool,
canDrop: PropTypes.bool,
connectDropTarget: PropTypes.func,
connectDragSource: PropTypes.func,
connectDragPreview: PropTypes.func,
}; };
export default DropTarget('sfMetadataGroupbyItem', dropTarget, dropCollect)( export default GroupbyItem;
DragSource('sfMetadataGroupbyItem', dragSource, dragCollect)(GroupbyItem)
);

View File

@@ -1,8 +1,7 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import { DropTarget } from 'react-dnd'; import { useDrop } from 'react-dnd';
import html5DragDropContext from '../../../../../pages/wiki2/wiki-nav/html5DragDropContext';
import GroupbyItem from './groupby-item'; import GroupbyItem from './groupby-item';
import { gettext } from '../../../../../utils/constants'; import { gettext } from '../../../../../utils/constants';
@@ -17,8 +16,20 @@ const Groupbys = ({ readOnly, groupbys, columns, onDelete, onUpdate, onMove }) =
return groupbys.length > 1; return groupbys.length > 1;
}, [readOnly, groupbys]); }, [readOnly, groupbys]);
const [, drop] = useDrop({
accept: 'sfMetadataGroupbyItem',
drop: (item, monitor) => {
if (!monitor.didDrop()) {
onMove(item, { idx: groupbys.length });
}
},
collect: monitor => ({
isOver: monitor.isOver(),
}),
});
return ( return (
<div className={classnames('groupbys-list', { 'empty-groupbys-container': isEmpty })}> <div ref={drop} className={classnames('groupbys-list', { 'empty-groupbys-container': isEmpty })}>
{isEmpty && <div className="empty-groupbys-list">{gettext('No groupings applied to this view.')}</div>} {isEmpty && <div className="empty-groupbys-list">{gettext('No groupings applied to this view.')}</div>}
{!isEmpty && groupbys.map((groupby, index) => { {!isEmpty && groupbys.map((groupby, index) => {
return ( return (
@@ -47,8 +58,4 @@ Groupbys.propTypes = {
onMove: PropTypes.func, onMove: PropTypes.func,
}; };
const DndGroupbysContainer = DropTarget('sfMetadataGroupbyItem', {}, connect => ({ export default Groupbys;
connectDropTarget: connect.dropTarget()
}))(Groupbys);
export default html5DragDropContext(DndGroupbysContainer);

View File

@@ -1,6 +1,6 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { DragSource, DropTarget } from 'react-dnd'; import { useDrag, useDrop } from 'react-dnd';
import classnames from 'classnames'; import classnames from 'classnames';
import Icon from '../../../../../components/icon'; import Icon from '../../../../../components/icon';
import IconBtn from '../../../../../components/icon-btn'; import IconBtn from '../../../../../components/icon-btn';
@@ -9,56 +9,73 @@ import Name from './name';
import './index.css'; import './index.css';
const dragSource = { // const dragSource = {
beginDrag: props => { // beginDrag: props => {
return { idx: props.index, data: props.option, mode: 'sfMetadataSingleSelectOption' }; // return { idx: props.index, data: props.option, mode: 'sfMetadataSingleSelectOption' };
}, // },
endDrag(props, monitor) { // endDrag(props, monitor) {
const optionSource = monitor.getItem(); // const optionSource = monitor.getItem();
const didDrop = monitor.didDrop(); // const didDrop = monitor.didDrop();
let optionTarget = {}; // let optionTarget = {};
if (!didDrop) { // if (!didDrop) {
return { optionSource, optionTarget }; // return { optionSource, optionTarget };
} // }
}, // },
isDragging(props, monitor) { // isDragging(props, monitor) {
const { index, dragged } = props; // const { index, dragged } = props;
const { idx } = dragged; // const { idx } = dragged;
return idx > index; // return idx > index;
} // }
}; // };
const dragCollect = (connect, monitor) => ({ // const dragCollect = (connect, monitor) => ({
connectDragSource: connect.dragSource(), // connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(), // connectDragPreview: connect.dragPreview(),
isDragging: monitor.isDragging() // isDragging: monitor.isDragging()
}); // });
const dropTarget = { // const dropTarget = {
drop(props, monitor) { // drop(props, monitor) {
const optionSource = monitor.getItem(); // const optionSource = monitor.getItem();
const { index: targetIdx } = props; // const { index: targetIdx } = props;
if (targetIdx !== optionSource.idx) { // if (targetIdx !== optionSource.idx) {
const optionTarget = { idx: targetIdx, data: props.option }; // const optionTarget = { idx: targetIdx, data: props.option };
props.onMove(optionSource, optionTarget); // props.onMove(optionSource, optionTarget);
} // }
} // }
}; // };
const dropCollect = (connect, monitor) => ({ // const dropCollect = (connect, monitor) => ({
connectDropTarget: connect.dropTarget(), // connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(), // isOver: monitor.isOver(),
canDrop: monitor.canDrop(), // canDrop: monitor.canDrop(),
dragged: monitor.getItem() // dragged: monitor.getItem()
}); // });
const Option = ({ const Option = ({
isOver, isDragging, canDrop, connectDragSource, connectDragPreview, connectDropTarget,
isViewing, isDeleting, isEditing, isPredefined, isViewing, isDeleting, isEditing, isPredefined,
option, option,
onDelete: propsDelete, onUpdate, onDelete: propsDelete, onUpdate,
onMouseLeave, onMouseEnter: propsMouseEnter, onToggleFreeze, onOpenNameEditor, onCloseNameEditor, onMouseLeave, onMouseEnter: propsMouseEnter, onToggleFreeze, onOpenNameEditor, onCloseNameEditor,
}) => { }) => {
const [{ isDragging }, drag] = useDrag({
type: 'sfMetadataSingleSelectOption',
item: () => ({
idx: option.id,
data: option,
}),
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
});
const [{ isOver, canDrop }, drop] = useDrop({
accept: 'sfMetadataSingleSelectOption',
collect: (monitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
})
});
const onDelete = useCallback((event) => { const onDelete = useCallback((event) => {
event.nativeEvent.stopImmediatePropagation(); event.nativeEvent.stopImmediatePropagation();
@@ -69,44 +86,41 @@ const Option = ({
propsMouseEnter(option.id); propsMouseEnter(option.id);
}, [option, propsMouseEnter]); }, [option, propsMouseEnter]);
return connectDropTarget( return (
connectDragPreview( <div
<div ref={(node) => drag(drop(node))}
className={classnames('sf-metadata-edit-option-container', { className={classnames('sf-metadata-edit-option-container', {
'sf-metadata-edit-option-can-drop': isOver && canDrop && !isDragging, 'sf-metadata-edit-option-can-drop': isOver && canDrop && !isDragging,
'sf-metadata-edit-deleting-option': isDeleting, 'sf-metadata-edit-deleting-option': isDeleting,
'sf-metadata-edit-option-can-drop-top': isOver && canDrop && isDragging, 'sf-metadata-edit-option-can-drop-top': isOver && canDrop && isDragging,
'sf-metadata-edit-option-viewing': isViewing, 'sf-metadata-edit-option-viewing': isViewing,
'sf-metadata-edit-option-editing': isEditing, 'sf-metadata-edit-option-editing': isEditing,
'sf-metadata-edit-option-disabled': isPredefined, 'sf-metadata-edit-option-disabled': isPredefined,
})} })}
onMouseEnter={() => onMouseEnter()} onMouseEnter={() => onMouseEnter()}
onMouseLeave={onMouseLeave} onMouseLeave={onMouseLeave}
> >
{connectDragSource( <div className="sf-metadata-edit-option-drag-container">
<div className="sf-metadata-edit-option-drag-container"> <Icon symbol="drag" />
<Icon symbol="drag" />
</div>
)}
<div className="sf-metadata-edit-option-content">
<Color option={option} onChange={onUpdate} isViewing={isViewing} isPredefined={isPredefined} />
<Name
option={option}
isPredefined={isPredefined}
isEditing={isEditing}
onChange={onUpdate}
onToggleFreeze={onToggleFreeze}
onOpen={onOpenNameEditor}
onClose={onCloseNameEditor}
/>
</div>
<div id={`sf-metadata-edit-option-more-operation-${option.id}`} className="sf-metadata-edit-option-more-operations">
{(isViewing || isDeleting) && (
<IconBtn className="sf-metadata-edit-option-operation-item" onClick={onDelete} symbol="delete" />
)}
</div>
</div> </div>
) <div className="sf-metadata-edit-option-content">
<Color option={option} onChange={onUpdate} isViewing={isViewing} isPredefined={isPredefined} />
<Name
option={option}
isPredefined={isPredefined}
isEditing={isEditing}
onChange={onUpdate}
onToggleFreeze={onToggleFreeze}
onOpen={onOpenNameEditor}
onClose={onCloseNameEditor}
/>
</div>
<div id={`sf-metadata-edit-option-more-operation-${option.id}`} className="sf-metadata-edit-option-more-operations">
{(isViewing || isDeleting) && (
<IconBtn className="sf-metadata-edit-option-operation-item" onClick={onDelete} symbol="delete" />
)}
</div>
</div>
); );
}; };
@@ -127,15 +141,13 @@ Option.propTypes = {
onOpenNameEditor: PropTypes.func.isRequired, onOpenNameEditor: PropTypes.func.isRequired,
onCloseNameEditor: PropTypes.func.isRequired, onCloseNameEditor: PropTypes.func.isRequired,
// drag // // drag
isOver: PropTypes.bool, // isOver: PropTypes.bool,
canDrop: PropTypes.bool, // canDrop: PropTypes.bool,
dragged: PropTypes.object, // dragged: PropTypes.object,
connectDragSource: PropTypes.func.isRequired, // connectDragSource: PropTypes.func.isRequired,
connectDropTarget: PropTypes.func.isRequired, // connectDropTarget: PropTypes.func.isRequired,
connectDragPreview: PropTypes.func.isRequired, // connectDragPreview: PropTypes.func.isRequired,
}; };
export default DropTarget('sfMetadataSingleSelectOption', dropTarget, dropCollect)( export default Option;
DragSource('sfMetadataSingleSelectOption', dragSource, dragCollect)(Option)
);

View File

@@ -1,7 +1,5 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { DropTarget } from 'react-dnd';
import html5DragDropContext from '../../../../pages/wiki2/wiki-nav/html5DragDropContext';
const OptionsContainer = ({ inputRef, options }) => { const OptionsContainer = ({ inputRef, options }) => {
if (!Array.isArray(options) || options.length === 0) return null; if (!Array.isArray(options) || options.length === 0) return null;
@@ -17,8 +15,4 @@ OptionsContainer.propTypes = {
options: PropTypes.array options: PropTypes.array
}; };
const DndOptionsContainer = DropTarget('sfMetadataSingleSelectOption', {}, connect => ({ export default OptionsContainer;
connectDropTarget: connect.dropTarget()
}))(OptionsContainer);
export default html5DragDropContext(DndOptionsContainer);

View File

@@ -1,4 +1,4 @@
import { DragDropContext } from 'react-dnd'; // import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend'; // import HTML5Backend from 'react-dnd-html5-backend';
export default DragDropContext(HTML5Backend); // export default DragDropContext(HTML5Backend);

View File

@@ -1,4 +1,4 @@
import { DragSource, DropTarget } from 'react-dnd'; import { useDrag, useDrop } from 'react-dnd';
import PageItem from './page-item'; import PageItem from './page-item';
import wikiAPI from '../../../../utils/wiki-api'; import wikiAPI from '../../../../utils/wiki-api';
import { wikiId, gettext } from '../../../../utils/constants'; import { wikiId, gettext } from '../../../../utils/constants';
@@ -77,6 +77,4 @@ const dropCollect = (connect, monitor) => ({
draggedPage: monitor.getItem() draggedPage: monitor.getItem()
}); });
export default DropTarget('WikiNav', dropTarget, dropCollect)( export default PageItem;
DragSource('WikiNav', dragSource, dragCollect)(PageItem)
);

View File

@@ -2,8 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { UncontrolledTooltip } from 'reactstrap'; import { UncontrolledTooltip } from 'reactstrap';
import { DropTarget, DragLayer } from 'react-dnd'; import { useDragLayer, useDrop } from 'react-dnd';
import html5DragDropContext from './html5DragDropContext';
import DraggedPageItem from './pages/dragged-page-item'; import DraggedPageItem from './pages/dragged-page-item';
import { gettext, wikiPermission } from '../../../utils/constants'; import { gettext, wikiPermission } from '../../../utils/constants';
import { Utils } from '../../../utils/utils'; import { Utils } from '../../../utils/utils';
@@ -158,14 +157,14 @@ class WikiNav extends Component {
}; };
render() { render() {
const StructureBody = html5DragDropContext( // const StructureBody = html5DragDropContext(
DropTarget('WikiNav', {}, connect => ({ // DropTarget('WikiNav', {}, connect => ({
connectDropTarget: connect.dropTarget() // connectDropTarget: connect.dropTarget()
}))(DragLayer(this.collect)(this.renderStructureBody)) // }))(DragLayer(this.collect)(this.renderStructureBody))
); // );
return ( return (
<div className='wiki-nav'> <div className='wiki-nav'>
<StructureBody /> {this.renderStructureBody()}
</div> </div>
); );
} }