added checkbox menu interaction and new opening mechanics
This commit is contained in:
parent
fd46496544
commit
e77a97e105
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"kafka": {
|
"kafka": {
|
||||||
"BootstrapServers": "localhost:9092"
|
"BootstrapServers": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import IconButton from "@appserver/components/icon-button";
|
import IconButton from "@appserver/components/icon-button";
|
||||||
import { isTablet, mobile, tablet } from "@appserver/components/utils/device";
|
import { isTablet, mobile, tablet } from "@appserver/components/utils/device";
|
||||||
|
import { set } from "mobx";
|
||||||
import { inject } from "mobx-react";
|
import { inject } from "mobx-react";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
@ -65,7 +66,10 @@ const StyledCloseButtonWrapper = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const InfoPanel = ({ children, isVisible, setIsVisible }) => {
|
const InfoPanel = ({ children, selectedItems, isVisible, setIsVisible }) => {
|
||||||
|
//if (selectedItems.length > 0) setIsVisible(true);
|
||||||
|
//else setIsVisible(false);
|
||||||
|
|
||||||
if (!isVisible) return null;
|
if (!isVisible) return null;
|
||||||
|
|
||||||
const closeInfoPanel = () => setIsVisible(false);
|
const closeInfoPanel = () => setIsVisible(false);
|
||||||
@ -108,7 +112,8 @@ InfoPanel.propTypes = {
|
|||||||
isVisible: PropTypes.bool,
|
isVisible: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default inject(({ infoPanelStore }) => {
|
export default inject(({ infoPanelStore, filesStore }) => {
|
||||||
|
let selectedItems = [];
|
||||||
let isVisible = false;
|
let isVisible = false;
|
||||||
let setIsVisible = () => {};
|
let setIsVisible = () => {};
|
||||||
|
|
||||||
@ -117,7 +122,12 @@ export default inject(({ infoPanelStore }) => {
|
|||||||
setIsVisible = infoPanelStore.setIsVisible;
|
setIsVisible = infoPanelStore.setIsVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (filesStore) {
|
||||||
|
selectedItems = JSON.parse(JSON.stringify(filesStore.selection));
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
selectedItems,
|
||||||
isVisible,
|
isVisible,
|
||||||
setIsVisible,
|
setIsVisible,
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,6 @@ const TableGroupMenu = (props) => {
|
|||||||
isChecked,
|
isChecked,
|
||||||
isIndeterminate,
|
isIndeterminate,
|
||||||
headerMenu,
|
headerMenu,
|
||||||
infoPanelToggle,
|
|
||||||
onChange,
|
onChange,
|
||||||
checkboxOptions,
|
checkboxOptions,
|
||||||
checkboxMargin,
|
checkboxMargin,
|
||||||
@ -55,7 +54,6 @@ const TableGroupMenu = (props) => {
|
|||||||
{headerMenu.map((item, index) => (
|
{headerMenu.map((item, index) => (
|
||||||
<GroupMenuItem key={index} item={item} />
|
<GroupMenuItem key={index} item={item} />
|
||||||
))}
|
))}
|
||||||
{infoPanelToggle}
|
|
||||||
</StyledScrollbar>
|
</StyledScrollbar>
|
||||||
</StyledTableGroupMenu>
|
</StyledTableGroupMenu>
|
||||||
</>
|
</>
|
||||||
|
@ -317,7 +317,7 @@ export default function withContextOptions(WrappedComponent) {
|
|||||||
case "show-info":
|
case "show-info":
|
||||||
return {
|
return {
|
||||||
key: option,
|
key: option,
|
||||||
label: t("Show info"),
|
label: t("InfoPanel:Info"),
|
||||||
icon: "images/info.react.svg",
|
icon: "images/info.react.svg",
|
||||||
onClick: this.onSetInfoPanelVisible,
|
onClick: this.onSetInfoPanelVisible,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import React from "react";
|
|
||||||
import { inject, observer } from "mobx-react";
|
|
||||||
import toastr from "@appserver/components/toast/toastr";
|
|
||||||
import { checkProtocol } from "../helpers/files-helpers";
|
|
||||||
import { AppServerConfig } from "@appserver/common/constants";
|
import { AppServerConfig } from "@appserver/common/constants";
|
||||||
import { combineUrl } from "@appserver/common/utils";
|
import { combineUrl } from "@appserver/common/utils";
|
||||||
import config from "../../package.json";
|
import toastr from "@appserver/components/toast/toastr";
|
||||||
|
import { inject, observer } from "mobx-react";
|
||||||
|
import React from "react";
|
||||||
import { isMobile } from "react-device-detect";
|
import { isMobile } from "react-device-detect";
|
||||||
|
|
||||||
|
import config from "../../package.json";
|
||||||
|
import { checkProtocol } from "../helpers/files-helpers";
|
||||||
|
|
||||||
export default function withFileActions(WrappedFileItem) {
|
export default function withFileActions(WrappedFileItem) {
|
||||||
class WithFileActions extends React.Component {
|
class WithFileActions extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -14,12 +15,19 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onContentFileSelect = (checked, file) => {
|
onContentFileSelect = (checked, file) => {
|
||||||
const { selectRowAction } = this.props;
|
const {
|
||||||
|
selectRowAction,
|
||||||
|
infoPanelIsVisible,
|
||||||
|
showInfoPanel,
|
||||||
|
} = this.props;
|
||||||
if (!file || file.id === -1) return;
|
if (!file || file.id === -1) return;
|
||||||
selectRowAction(checked, file);
|
selectRowAction(checked, file);
|
||||||
|
if (!infoPanelIsVisible) showInfoPanel();
|
||||||
};
|
};
|
||||||
|
|
||||||
fileContextClick = () => {
|
fileContextClick = () => {
|
||||||
|
if (!this.props.infoPanelIsVisible) this.props.showInfoPanel();
|
||||||
|
|
||||||
const { onSelectItem, item } = this.props;
|
const { onSelectItem, item } = this.props;
|
||||||
const { id, isFolder } = item;
|
const { id, isFolder } = item;
|
||||||
|
|
||||||
@ -94,6 +102,7 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
if (mouseButton || e.currentTarget.tagName !== "DIV" || label) {
|
if (mouseButton || e.currentTarget.tagName !== "DIV" || label) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setTooltipPosition(e.pageX, e.pageY);
|
setTooltipPosition(e.pageX, e.pageY);
|
||||||
!isFileName && setStartDrag(true);
|
!isFileName && setStartDrag(true);
|
||||||
@ -104,7 +113,12 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
this.props.markAsRead([], [`${id}`], this.props.item);
|
this.props.markAsRead([], [`${id}`], this.props.item);
|
||||||
|
|
||||||
onMouseClick = (e) => {
|
onMouseClick = (e) => {
|
||||||
const { viewAs, isItemsSelected } = this.props;
|
const {
|
||||||
|
viewAs,
|
||||||
|
isItemsSelected,
|
||||||
|
infoPanelIsVisible,
|
||||||
|
showInfoPanel,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
e.target.closest(".checkbox") ||
|
e.target.closest(".checkbox") ||
|
||||||
@ -119,13 +133,18 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (viewAs === "tile") {
|
if (viewAs === "tile") {
|
||||||
if (e.target.closest(".edit-button") || e.target.tagName === "IMG")
|
if (
|
||||||
|
e.target.closest(".edit-button") ||
|
||||||
|
e.target.tagName === "IMG"
|
||||||
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (e.detail === 1) this.fileContextClick();
|
if (e.detail === 1) this.fileContextClick();
|
||||||
} else {
|
} else {
|
||||||
this.fileContextClick();
|
this.fileContextClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!infoPanelIsVisible) showInfoPanel();
|
||||||
};
|
};
|
||||||
onFilesClick = (e) => {
|
onFilesClick = (e) => {
|
||||||
const {
|
const {
|
||||||
@ -160,7 +179,10 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
if (encrypted && isPrivacy) return checkProtocol(item.id, true);
|
if (encrypted && isPrivacy) return checkProtocol(item.id, true);
|
||||||
|
|
||||||
if (isTrashFolder) return;
|
if (isTrashFolder) return;
|
||||||
if ((e && e.target.tagName === "INPUT") || e.target.closest(".badges"))
|
if (
|
||||||
|
(e && e.target.tagName === "INPUT") ||
|
||||||
|
e.target.closest(".badges")
|
||||||
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -172,7 +194,9 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
fetchFiles(id, null, true, false)
|
fetchFiles(id, null, true, false)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
const pathParts = data.selectedFolder.pathParts;
|
const pathParts = data.selectedFolder.pathParts;
|
||||||
const newExpandedKeys = createNewExpandedKeys(pathParts);
|
const newExpandedKeys = createNewExpandedKeys(
|
||||||
|
pathParts
|
||||||
|
);
|
||||||
setExpandedKeys(newExpandedKeys);
|
setExpandedKeys(newExpandedKeys);
|
||||||
|
|
||||||
setNewBadgeCount(item);
|
setNewBadgeCount(item);
|
||||||
@ -238,9 +262,12 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
const { fileExst, access, id } = item;
|
const { fileExst, access, id } = item;
|
||||||
|
|
||||||
const isEdit =
|
const isEdit =
|
||||||
actionType !== null && actionId === id && fileExst === actionExtension;
|
actionType !== null &&
|
||||||
|
actionId === id &&
|
||||||
|
fileExst === actionExtension;
|
||||||
|
|
||||||
const isDragging = isFolder && access < 2 && !isTrashFolder && !isPrivacy;
|
const isDragging =
|
||||||
|
isFolder && access < 2 && !isTrashFolder && !isPrivacy;
|
||||||
|
|
||||||
let className = isDragging ? " droppable" : "";
|
let className = isDragging ? " droppable" : "";
|
||||||
if (draggable) className += " draggable";
|
if (draggable) className += " draggable";
|
||||||
@ -305,6 +332,7 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
uploadDataStore,
|
uploadDataStore,
|
||||||
formatsStore,
|
formatsStore,
|
||||||
mediaViewerDataStore,
|
mediaViewerDataStore,
|
||||||
|
infoPanelStore,
|
||||||
},
|
},
|
||||||
{ item, t, history }
|
{ item, t, history }
|
||||||
) => {
|
) => {
|
||||||
@ -342,10 +370,12 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
bufferSelection,
|
bufferSelection,
|
||||||
setBufferSelection,
|
setBufferSelection,
|
||||||
} = filesStore;
|
} = filesStore;
|
||||||
|
|
||||||
const { startUpload } = uploadDataStore;
|
const { startUpload } = uploadDataStore;
|
||||||
const { type, extension, id } = fileActionStore;
|
const { type, extension, id } = fileActionStore;
|
||||||
const { mediaViewersFormatsStore, docserviceStore } = formatsStore;
|
const { mediaViewersFormatsStore, docserviceStore } = formatsStore;
|
||||||
const { setMediaViewerData } = mediaViewerDataStore;
|
const { setMediaViewerData } = mediaViewerDataStore;
|
||||||
|
const { isVisible, setVisible } = infoPanelStore;
|
||||||
|
|
||||||
const selectedItem = selection.find(
|
const selectedItem = selection.find(
|
||||||
(x) => x.id === item.id && x.fileExst === item.fileExst
|
(x) => x.id === item.id && x.fileExst === item.fileExst
|
||||||
@ -354,7 +384,11 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
const draggable =
|
const draggable =
|
||||||
!isRecycleBinFolder && selectedItem && selectedItem.id !== id;
|
!isRecycleBinFolder && selectedItem && selectedItem.id !== id;
|
||||||
|
|
||||||
const isFolder = selectedItem ? false : !item.isFolder ? false : true;
|
const isFolder = selectedItem
|
||||||
|
? false
|
||||||
|
: !item.isFolder
|
||||||
|
? false
|
||||||
|
: true;
|
||||||
|
|
||||||
const isMediaOrImage = mediaViewersFormatsStore.isMediaOrImage(
|
const isMediaOrImage = mediaViewersFormatsStore.isMediaOrImage(
|
||||||
item.fileExst
|
item.fileExst
|
||||||
@ -415,6 +449,8 @@ export default function withFileActions(WrappedFileItem) {
|
|||||||
isActive,
|
isActive,
|
||||||
setBufferSelection,
|
setBufferSelection,
|
||||||
bufferSelection,
|
bufferSelection,
|
||||||
|
isInfoPanelVisible: isVisible,
|
||||||
|
showInfoPanel: setVisible,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)(observer(WithFileActions));
|
)(observer(WithFileActions));
|
||||||
|
@ -1,12 +1,3 @@
|
|||||||
import {
|
|
||||||
StyledAccess,
|
|
||||||
StyledAccessUser,
|
|
||||||
StyledOpenSharingPanel,
|
|
||||||
StyledProperties,
|
|
||||||
StyledSubtitle,
|
|
||||||
StyledThumbnail,
|
|
||||||
StyledTitle,
|
|
||||||
} from "./styles/styles.js";
|
|
||||||
import RectangleLoader from "@appserver/common/components/Loaders/RectangleLoader";
|
import RectangleLoader from "@appserver/common/components/Loaders/RectangleLoader";
|
||||||
import { FileType } from "@appserver/common/constants";
|
import { FileType } from "@appserver/common/constants";
|
||||||
import Link from "@appserver/components/link";
|
import Link from "@appserver/components/link";
|
||||||
@ -17,6 +8,16 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { withTranslation } from "react-i18next";
|
import { withTranslation } from "react-i18next";
|
||||||
import { ReactSVG } from "react-svg";
|
import { ReactSVG } from "react-svg";
|
||||||
|
|
||||||
|
import {
|
||||||
|
StyledAccess,
|
||||||
|
StyledAccessUser,
|
||||||
|
StyledOpenSharingPanel,
|
||||||
|
StyledProperties,
|
||||||
|
StyledSubtitle,
|
||||||
|
StyledThumbnail,
|
||||||
|
StyledTitle,
|
||||||
|
} from "./styles/styles.js";
|
||||||
|
|
||||||
const SingleItem = (props) => {
|
const SingleItem = (props) => {
|
||||||
const {
|
const {
|
||||||
t,
|
t,
|
||||||
@ -30,6 +31,7 @@ const SingleItem = (props) => {
|
|||||||
getShareUsers,
|
getShareUsers,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
let updateSubscription = true;
|
||||||
const [item, setItem] = useState({
|
const [item, setItem] = useState({
|
||||||
id: "",
|
id: "",
|
||||||
isFolder: false,
|
isFolder: false,
|
||||||
@ -45,7 +47,6 @@ const SingleItem = (props) => {
|
|||||||
others: [],
|
others: [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [isShowAllAccessUsers, setIsShowAllAccessUsers] = useState(false);
|
const [isShowAllAccessUsers, setIsShowAllAccessUsers] = useState(false);
|
||||||
|
|
||||||
const updateItemsInfo = async (selectedItem) => {
|
const updateItemsInfo = async (selectedItem) => {
|
||||||
@ -264,6 +265,7 @@ const SingleItem = (props) => {
|
|||||||
|
|
||||||
const access = await updateLoadedItemAccess(selectedItem);
|
const access = await updateLoadedItemAccess(selectedItem);
|
||||||
|
|
||||||
|
if (updateSubscription)
|
||||||
setItem({
|
setItem({
|
||||||
...displayedItem,
|
...displayedItem,
|
||||||
properties: properties,
|
properties: properties,
|
||||||
@ -283,7 +285,9 @@ const SingleItem = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedItem.id !== item.id) updateItemsInfo(selectedItem);
|
if (selectedItem.id !== item.id && updateSubscription)
|
||||||
|
updateItemsInfo(selectedItem);
|
||||||
|
return () => (updateSubscription = false);
|
||||||
}, [selectedItem]);
|
}, [selectedItem]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -19,15 +19,18 @@ const InfoPanelBodyContent = ({
|
|||||||
setSharingPanelVisible,
|
setSharingPanelVisible,
|
||||||
isRecycleBinFolder,
|
isRecycleBinFolder,
|
||||||
}) => {
|
}) => {
|
||||||
|
if (selectedItems.length) {
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledInfoRoomBody>
|
<StyledInfoRoomBody>
|
||||||
{selectedItems.length === 0 ? (
|
{selectedItems.length === 0 && !bufferSelectedItem ? (
|
||||||
<div className="no-item">
|
<div className="no-item">
|
||||||
<h4>{t("NoItemsSelected")}</h4>
|
<h4>{t("NoItemsSelected")}</h4>
|
||||||
</div>
|
</div>
|
||||||
) : selectedItems.length === 1 ? (
|
) : selectedItems.length === 1 || bufferSelectedItem ? (
|
||||||
<SingleItem
|
<SingleItem
|
||||||
selectedItem={selectedItems[0]}
|
selectedItem={selectedItems[0] || bufferSelectedItem}
|
||||||
isRecycleBinFolder={isRecycleBinFolder}
|
isRecycleBinFolder={isRecycleBinFolder}
|
||||||
onSelectItem={onSelectItem}
|
onSelectItem={onSelectItem}
|
||||||
setSharingPanelVisible={setSharingPanelVisible}
|
setSharingPanelVisible={setSharingPanelVisible}
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
import { makeAutoObservable } from "mobx";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
removeFiles,
|
checkFileConflicts,
|
||||||
deleteFile,
|
deleteFile,
|
||||||
deleteFolder,
|
deleteFolder,
|
||||||
finalizeVersion,
|
|
||||||
lockFile,
|
|
||||||
downloadFiles,
|
downloadFiles,
|
||||||
markAsRead,
|
|
||||||
checkFileConflicts,
|
|
||||||
removeShareFiles,
|
|
||||||
getSubfolders,
|
|
||||||
emptyTrash,
|
emptyTrash,
|
||||||
|
finalizeVersion,
|
||||||
|
getSubfolders,
|
||||||
|
lockFile,
|
||||||
|
markAsRead,
|
||||||
|
removeFiles,
|
||||||
|
removeShareFiles,
|
||||||
} from "@appserver/common/api/files";
|
} from "@appserver/common/api/files";
|
||||||
import { ConflictResolveType, FileAction } from "@appserver/common/constants";
|
import { ConflictResolveType, FileAction } from "@appserver/common/constants";
|
||||||
|
import { makeAutoObservable } from "mobx";
|
||||||
|
import toastr from "studio/toastr";
|
||||||
|
|
||||||
import { TIMEOUT } from "../helpers/constants";
|
import { TIMEOUT } from "../helpers/constants";
|
||||||
import { loopTreeFolders } from "../helpers/files-helpers";
|
import { loopTreeFolders } from "../helpers/files-helpers";
|
||||||
import toastr from "studio/toastr";
|
|
||||||
|
|
||||||
class FilesActionStore {
|
class FilesActionStore {
|
||||||
authStore;
|
authStore;
|
||||||
@ -27,6 +27,7 @@ class FilesActionStore {
|
|||||||
settingsStore;
|
settingsStore;
|
||||||
dialogsStore;
|
dialogsStore;
|
||||||
mediaViewerDataStore;
|
mediaViewerDataStore;
|
||||||
|
infoPanelStore;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
authStore,
|
authStore,
|
||||||
@ -36,7 +37,8 @@ class FilesActionStore {
|
|||||||
selectedFolderStore,
|
selectedFolderStore,
|
||||||
settingsStore,
|
settingsStore,
|
||||||
dialogsStore,
|
dialogsStore,
|
||||||
mediaViewerDataStore
|
mediaViewerDataStore,
|
||||||
|
infoPanelStore
|
||||||
) {
|
) {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
this.authStore = authStore;
|
this.authStore = authStore;
|
||||||
@ -46,11 +48,16 @@ class FilesActionStore {
|
|||||||
this.selectedFolderStore = selectedFolderStore;
|
this.selectedFolderStore = selectedFolderStore;
|
||||||
this.settingsStore = settingsStore;
|
this.settingsStore = settingsStore;
|
||||||
this.dialogsStore = dialogsStore;
|
this.dialogsStore = dialogsStore;
|
||||||
|
this.infoPanelStore = infoPanelStore;
|
||||||
this.mediaViewerDataStore = mediaViewerDataStore;
|
this.mediaViewerDataStore = mediaViewerDataStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
isMediaOpen = () => {
|
isMediaOpen = () => {
|
||||||
const { visible, setMediaViewerData, playlist } = this.mediaViewerDataStore;
|
const {
|
||||||
|
visible,
|
||||||
|
setMediaViewerData,
|
||||||
|
playlist,
|
||||||
|
} = this.mediaViewerDataStore;
|
||||||
if (visible && playlist.length === 1) {
|
if (visible && playlist.length === 1) {
|
||||||
setMediaViewerData({ visible: false, id: null });
|
setMediaViewerData({ visible: false, id: null });
|
||||||
}
|
}
|
||||||
@ -98,7 +105,9 @@ class FilesActionStore {
|
|||||||
) => {
|
) => {
|
||||||
const { isRecycleBinFolder, isPrivacyFolder } = this.treeFoldersStore;
|
const { isRecycleBinFolder, isPrivacyFolder } = this.treeFoldersStore;
|
||||||
|
|
||||||
const selection = newSelection ? newSelection : this.filesStore.selection;
|
const selection = newSelection
|
||||||
|
? newSelection
|
||||||
|
: this.filesStore.selection;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
setSecondaryProgressBarData,
|
setSecondaryProgressBarData,
|
||||||
@ -114,7 +123,8 @@ class FilesActionStore {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const deleteAfter = false; //Delete after finished TODO: get from settings
|
const deleteAfter = false; //Delete after finished TODO: get from settings
|
||||||
const immediately = isRecycleBinFolder || isPrivacyFolder ? true : false; //Don't move to the Recycle Bin
|
const immediately =
|
||||||
|
isRecycleBinFolder || isPrivacyFolder ? true : false; //Don't move to the Recycle Bin
|
||||||
|
|
||||||
let folderIds = [];
|
let folderIds = [];
|
||||||
let fileIds = [];
|
let fileIds = [];
|
||||||
@ -140,14 +150,21 @@ class FilesActionStore {
|
|||||||
this.isMediaOpen();
|
this.isMediaOpen();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await removeFiles(folderIds, fileIds, deleteAfter, immediately).then(
|
await removeFiles(
|
||||||
async (res) => {
|
folderIds,
|
||||||
|
fileIds,
|
||||||
|
deleteAfter,
|
||||||
|
immediately
|
||||||
|
).then(async (res) => {
|
||||||
const data = res[0] ? res[0] : null;
|
const data = res[0] ? res[0] : null;
|
||||||
const pbData = {
|
const pbData = {
|
||||||
icon: "trash",
|
icon: "trash",
|
||||||
label: translations.deleteOperation,
|
label: translations.deleteOperation,
|
||||||
};
|
};
|
||||||
await this.uploadDataStore.loopFilesOperations(data, pbData);
|
await this.uploadDataStore.loopFilesOperations(
|
||||||
|
data,
|
||||||
|
pbData
|
||||||
|
);
|
||||||
this.updateCurrentFolder(selection.length);
|
this.updateCurrentFolder(selection.length);
|
||||||
if (isRecycleBinFolder) {
|
if (isRecycleBinFolder) {
|
||||||
return toastr.success(translations.deleteFromTrash);
|
return toastr.success(translations.deleteFromTrash);
|
||||||
@ -160,8 +177,7 @@ class FilesActionStore {
|
|||||||
return toastr.success(translations.FileRemoved);
|
return toastr.success(translations.FileRemoved);
|
||||||
}
|
}
|
||||||
return toastr.success(translations.FolderRemoved);
|
return toastr.success(translations.FolderRemoved);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setSecondaryProgressBarData({
|
setSecondaryProgressBarData({
|
||||||
visible: true,
|
visible: true,
|
||||||
@ -233,7 +249,10 @@ class FilesActionStore {
|
|||||||
const item =
|
const item =
|
||||||
data?.finished && data?.url
|
data?.finished && data?.url
|
||||||
? data
|
? data
|
||||||
: await this.uploadDataStore.loopFilesOperations(data, pbData);
|
: await this.uploadDataStore.loopFilesOperations(
|
||||||
|
data,
|
||||||
|
pbData
|
||||||
|
);
|
||||||
|
|
||||||
if (item.url) {
|
if (item.url) {
|
||||||
window.location.href = item.url;
|
window.location.href = item.url;
|
||||||
@ -311,11 +330,16 @@ class FilesActionStore {
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
if (!isCancelled) {
|
if (!isCancelled) {
|
||||||
const data = await fetchFiles(this.selectedFolderStore.id, filter);
|
const data = await fetchFiles(
|
||||||
|
this.selectedFolderStore.id,
|
||||||
|
filter
|
||||||
|
);
|
||||||
const newItem = (item && item.id) === -1 ? null : item; //TODO: not add new folders?
|
const newItem = (item && item.id) === -1 ? null : item; //TODO: not add new folders?
|
||||||
if (!selectedItem.fileExst && !selectedItem.contentLength) {
|
if (!selectedItem.fileExst && !selectedItem.contentLength) {
|
||||||
const path = data.selectedFolder.pathParts;
|
const path = data.selectedFolder.pathParts;
|
||||||
const folders = await getSubfolders(this.selectedFolderStore.id);
|
const folders = await getSubfolders(
|
||||||
|
this.selectedFolderStore.id
|
||||||
|
);
|
||||||
loopTreeFolders(path, treeFolders, folders, null, newItem);
|
loopTreeFolders(path, treeFolders, folders, null, newItem);
|
||||||
setTreeFolders(treeFolders);
|
setTreeFolders(treeFolders);
|
||||||
}
|
}
|
||||||
@ -398,7 +422,10 @@ class FilesActionStore {
|
|||||||
return deleteFile(itemId)
|
return deleteFile(itemId)
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
const data = res[0] ? res[0] : null;
|
const data = res[0] ? res[0] : null;
|
||||||
await this.uploadDataStore.loopFilesOperations(data, pbData);
|
await this.uploadDataStore.loopFilesOperations(
|
||||||
|
data,
|
||||||
|
pbData
|
||||||
|
);
|
||||||
this.updateCurrentFolder(selectionFilesLength);
|
this.updateCurrentFolder(selectionFilesLength);
|
||||||
})
|
})
|
||||||
.then(() => toastr.success(translations.successRemoveFile));
|
.then(() => toastr.success(translations.successRemoveFile));
|
||||||
@ -406,7 +433,10 @@ class FilesActionStore {
|
|||||||
return deleteFolder(itemId)
|
return deleteFolder(itemId)
|
||||||
.then(async (res) => {
|
.then(async (res) => {
|
||||||
const data = res[0] ? res[0] : null;
|
const data = res[0] ? res[0] : null;
|
||||||
await this.uploadDataStore.loopFilesOperations(data, pbData);
|
await this.uploadDataStore.loopFilesOperations(
|
||||||
|
data,
|
||||||
|
pbData
|
||||||
|
);
|
||||||
this.updateCurrentFolder(selectionFilesLength);
|
this.updateCurrentFolder(selectionFilesLength);
|
||||||
})
|
})
|
||||||
.then(() => toastr.success(translations.successRemoveFolder));
|
.then(() => toastr.success(translations.successRemoveFolder));
|
||||||
@ -419,7 +449,9 @@ class FilesActionStore {
|
|||||||
|
|
||||||
return removeShareFiles(fileIds, folderIds)
|
return removeShareFiles(fileIds, folderIds)
|
||||||
.then(() => setUnsubscribe(false))
|
.then(() => setUnsubscribe(false))
|
||||||
.then(() => fetchFiles(this.selectedFolderStore.id, filter, true, true));
|
.then(() =>
|
||||||
|
fetchFiles(this.selectedFolderStore.id, filter, true, true)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
lockFileAction = (id, locked) => {
|
lockFileAction = (id, locked) => {
|
||||||
@ -514,7 +546,10 @@ class FilesActionStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
openLocationAction = (locationId, isFolder) => {
|
openLocationAction = (locationId, isFolder) => {
|
||||||
const { createNewExpandedKeys, setExpandedKeys } = this.treeFoldersStore;
|
const {
|
||||||
|
createNewExpandedKeys,
|
||||||
|
setExpandedKeys,
|
||||||
|
} = this.treeFoldersStore;
|
||||||
|
|
||||||
const locationFilter = isFolder ? this.filesStore.filter : null;
|
const locationFilter = isFolder ? this.filesStore.filter : null;
|
||||||
this.filesStore.setBufferSelection(null);
|
this.filesStore.setBufferSelection(null);
|
||||||
@ -578,7 +613,9 @@ class FilesActionStore {
|
|||||||
})
|
})
|
||||||
.then(() => item && this.setNewBadgeCount(item))
|
.then(() => item && this.setNewBadgeCount(item))
|
||||||
.catch((err) => toastr.error(err))
|
.catch((err) => toastr.error(err))
|
||||||
.finally(() => setTimeout(() => clearSecondaryProgressData(), TIMEOUT));
|
.finally(() =>
|
||||||
|
setTimeout(() => clearSecondaryProgressData(), TIMEOUT)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
moveDragItems = (destFolderId, folderTitle, translations) => {
|
moveDragItems = (destFolderId, folderTitle, translations) => {
|
||||||
@ -645,7 +682,11 @@ class FilesActionStore {
|
|||||||
let conflicts;
|
let conflicts;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conflicts = await checkFileConflicts(destFolderId, folderIds, fileIds);
|
conflicts = await checkFileConflicts(
|
||||||
|
destFolderId,
|
||||||
|
folderIds,
|
||||||
|
fileIds
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setBufferSelection(null);
|
setBufferSelection(null);
|
||||||
return toastr.error(err.message ? err.message : err);
|
return toastr.error(err.message ? err.message : err);
|
||||||
@ -685,6 +726,7 @@ class FilesActionStore {
|
|||||||
switch (option) {
|
switch (option) {
|
||||||
case "share":
|
case "share":
|
||||||
return isAccessedSelected && !personal; //isFavoritesFolder ||isRecentFolder
|
return isAccessedSelected && !personal; //isFavoritesFolder ||isRecentFolder
|
||||||
|
case "showInfo":
|
||||||
case "copy":
|
case "copy":
|
||||||
case "download":
|
case "download":
|
||||||
return hasSelection;
|
return hasSelection;
|
||||||
@ -701,9 +743,13 @@ class FilesActionStore {
|
|||||||
|
|
||||||
case "delete":
|
case "delete":
|
||||||
const deleteCondition =
|
const deleteCondition =
|
||||||
!isThirdPartyRootSelection && hasSelection && isAccessedSelected;
|
!isThirdPartyRootSelection &&
|
||||||
|
hasSelection &&
|
||||||
|
isAccessedSelected;
|
||||||
|
|
||||||
return isCommonFolder ? userAccess && deleteCondition : deleteCondition;
|
return isCommonFolder
|
||||||
|
? userAccess && deleteCondition
|
||||||
|
: deleteCondition;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -726,6 +772,8 @@ class FilesActionStore {
|
|||||||
setDeleteDialogVisible,
|
setDeleteDialogVisible,
|
||||||
} = this.dialogsStore;
|
} = this.dialogsStore;
|
||||||
|
|
||||||
|
const { toggleIsVisible } = this.infoPanelStore;
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case "share":
|
case "share":
|
||||||
if (!this.isAvailableOption("share")) return null;
|
if (!this.isAvailableOption("share")) return null;
|
||||||
@ -776,6 +824,15 @@ class FilesActionStore {
|
|||||||
iconUrl: "/static/images/move.react.svg",
|
iconUrl: "/static/images/move.react.svg",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case "showInfo":
|
||||||
|
if (!this.isAvailableOption("showInfo")) return null;
|
||||||
|
else
|
||||||
|
return {
|
||||||
|
label: t("InfoPanel:Info"),
|
||||||
|
onClick: () => toggleIsVisible(),
|
||||||
|
iconUrl: "/static/images/info.outline.react.svg",
|
||||||
|
};
|
||||||
|
|
||||||
case "delete":
|
case "delete":
|
||||||
if (!this.isAvailableOption("delete")) return null;
|
if (!this.isAvailableOption("delete")) return null;
|
||||||
else
|
else
|
||||||
@ -786,9 +843,15 @@ class FilesActionStore {
|
|||||||
setDeleteDialogVisible(true);
|
setDeleteDialogVisible(true);
|
||||||
} else {
|
} else {
|
||||||
const translations = {
|
const translations = {
|
||||||
deleteOperation: t("Translations:DeleteOperation"),
|
deleteOperation: t(
|
||||||
deleteFromTrash: t("Translations:DeleteFromTrash"),
|
"Translations:DeleteOperation"
|
||||||
deleteSelectedElem: t("Translations:DeleteSelectedElem"),
|
),
|
||||||
|
deleteFromTrash: t(
|
||||||
|
"Translations:DeleteFromTrash"
|
||||||
|
),
|
||||||
|
deleteSelectedElem: t(
|
||||||
|
"Translations:DeleteSelectedElem"
|
||||||
|
),
|
||||||
FileRemoved: t("Home:FileRemoved"),
|
FileRemoved: t("Home:FileRemoved"),
|
||||||
FolderRemoved: t("Home:FolderRemoved"),
|
FolderRemoved: t("Home:FolderRemoved"),
|
||||||
};
|
};
|
||||||
@ -810,6 +873,7 @@ class FilesActionStore {
|
|||||||
const moveTo = this.getOption("moveTo", t);
|
const moveTo = this.getOption("moveTo", t);
|
||||||
const copy = this.getOption("copy", t);
|
const copy = this.getOption("copy", t);
|
||||||
const deleteOption = this.getOption("delete", t);
|
const deleteOption = this.getOption("delete", t);
|
||||||
|
const showInfo = this.getOption("showInfo", t);
|
||||||
|
|
||||||
itemsCollection
|
itemsCollection
|
||||||
.set("share", share)
|
.set("share", share)
|
||||||
@ -817,7 +881,8 @@ class FilesActionStore {
|
|||||||
.set("downloadAs", downloadAs)
|
.set("downloadAs", downloadAs)
|
||||||
.set("moveTo", moveTo)
|
.set("moveTo", moveTo)
|
||||||
.set("copy", copy)
|
.set("copy", copy)
|
||||||
.set("delete", deleteOption);
|
.set("delete", deleteOption)
|
||||||
|
.set("showInfo", showInfo);
|
||||||
|
|
||||||
return this.convertToArray(itemsCollection);
|
return this.convertToArray(itemsCollection);
|
||||||
};
|
};
|
||||||
@ -827,12 +892,15 @@ class FilesActionStore {
|
|||||||
const download = this.getOption("download", t);
|
const download = this.getOption("download", t);
|
||||||
const downloadAs = this.getOption("downloadAs", t);
|
const downloadAs = this.getOption("downloadAs", t);
|
||||||
const copy = this.getOption("copy", t);
|
const copy = this.getOption("copy", t);
|
||||||
|
const showInfo = this.getOption("showInfo", t);
|
||||||
|
|
||||||
itemsCollection
|
itemsCollection
|
||||||
.set("share", share)
|
.set("share", share)
|
||||||
.set("download", download)
|
.set("download", download)
|
||||||
.set("downloadAs", downloadAs)
|
.set("downloadAs", downloadAs)
|
||||||
.set("copy", copy);
|
.set("copy", copy)
|
||||||
|
.set("showInfo", showInfo);
|
||||||
|
|
||||||
return this.convertToArray(itemsCollection);
|
return this.convertToArray(itemsCollection);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -843,6 +911,7 @@ class FilesActionStore {
|
|||||||
const download = this.getOption("download", t);
|
const download = this.getOption("download", t);
|
||||||
const downloadAs = this.getOption("downloadAs", t);
|
const downloadAs = this.getOption("downloadAs", t);
|
||||||
const copy = this.getOption("copy", t);
|
const copy = this.getOption("copy", t);
|
||||||
|
const showInfo = this.getOption("showInfo", t);
|
||||||
|
|
||||||
itemsCollection
|
itemsCollection
|
||||||
.set("share", share)
|
.set("share", share)
|
||||||
@ -855,7 +924,9 @@ class FilesActionStore {
|
|||||||
setUnsubscribe(true);
|
setUnsubscribe(true);
|
||||||
setDeleteDialogVisible(true);
|
setDeleteDialogVisible(true);
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
.set("showInfo", showInfo);
|
||||||
|
|
||||||
return this.convertToArray(itemsCollection);
|
return this.convertToArray(itemsCollection);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -863,12 +934,15 @@ class FilesActionStore {
|
|||||||
const moveTo = this.getOption("moveTo", t);
|
const moveTo = this.getOption("moveTo", t);
|
||||||
const deleteOption = this.getOption("delete", t);
|
const deleteOption = this.getOption("delete", t);
|
||||||
const download = this.getOption("download", t);
|
const download = this.getOption("download", t);
|
||||||
|
const showInfo = this.getOption("showInfo", t);
|
||||||
|
|
||||||
itemsCollection
|
itemsCollection
|
||||||
.set("download", download)
|
.set("download", download)
|
||||||
.set("moveTo", moveTo)
|
.set("moveTo", moveTo)
|
||||||
|
|
||||||
.set("delete", deleteOption);
|
.set("delete", deleteOption)
|
||||||
|
.set("showInfo", showInfo);
|
||||||
|
|
||||||
return this.convertToArray(itemsCollection);
|
return this.convertToArray(itemsCollection);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -879,6 +953,7 @@ class FilesActionStore {
|
|||||||
const download = this.getOption("download", t);
|
const download = this.getOption("download", t);
|
||||||
const downloadAs = this.getOption("downloadAs", t);
|
const downloadAs = this.getOption("downloadAs", t);
|
||||||
const copy = this.getOption("copy", t);
|
const copy = this.getOption("copy", t);
|
||||||
|
const showInfo = this.getOption("showInfo", t);
|
||||||
|
|
||||||
itemsCollection
|
itemsCollection
|
||||||
.set("share", share)
|
.set("share", share)
|
||||||
@ -894,7 +969,9 @@ class FilesActionStore {
|
|||||||
.then(() => toastr.success(t("RemovedFromFavorites")))
|
.then(() => toastr.success(t("RemovedFromFavorites")))
|
||||||
.catch((err) => toastr.error(err));
|
.catch((err) => toastr.error(err));
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
.set("showInfo", showInfo);
|
||||||
|
|
||||||
return this.convertToArray(itemsCollection);
|
return this.convertToArray(itemsCollection);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -907,6 +984,7 @@ class FilesActionStore {
|
|||||||
const download = this.getOption("download", t);
|
const download = this.getOption("download", t);
|
||||||
const downloadAs = this.getOption("downloadAs", t);
|
const downloadAs = this.getOption("downloadAs", t);
|
||||||
const deleteOption = this.getOption("delete", t);
|
const deleteOption = this.getOption("delete", t);
|
||||||
|
const showInfo = this.getOption("showInfo", t);
|
||||||
|
|
||||||
itemsCollection
|
itemsCollection
|
||||||
.set("download", download)
|
.set("download", download)
|
||||||
@ -916,9 +994,12 @@ class FilesActionStore {
|
|||||||
onClick: () => setMoveToPanelVisible(true),
|
onClick: () => setMoveToPanelVisible(true),
|
||||||
iconUrl: "/static/images/move.react.svg",
|
iconUrl: "/static/images/move.react.svg",
|
||||||
})
|
})
|
||||||
.set("delete", deleteOption);
|
.set("delete", deleteOption)
|
||||||
|
.set("showInfo", showInfo);
|
||||||
|
|
||||||
return this.convertToArray(itemsCollection);
|
return this.convertToArray(itemsCollection);
|
||||||
};
|
};
|
||||||
|
|
||||||
getHeaderMenu = (t) => {
|
getHeaderMenu = (t) => {
|
||||||
const {
|
const {
|
||||||
isFavoritesFolder,
|
isFavoritesFolder,
|
||||||
@ -936,11 +1017,14 @@ class FilesActionStore {
|
|||||||
if (isFavoritesFolder)
|
if (isFavoritesFolder)
|
||||||
return this.getFavoritesFolderOptions(itemsCollection, t);
|
return this.getFavoritesFolderOptions(itemsCollection, t);
|
||||||
|
|
||||||
if (isPrivacyFolder) return this.getPrivacyFolderOption(itemsCollection, t);
|
if (isPrivacyFolder)
|
||||||
|
return this.getPrivacyFolderOption(itemsCollection, t);
|
||||||
|
|
||||||
if (isShareFolder) return this.getShareFolderOptions(itemsCollection, t);
|
if (isShareFolder)
|
||||||
|
return this.getShareFolderOptions(itemsCollection, t);
|
||||||
|
|
||||||
if (isRecentFolder) return this.getRecentFolderOptions(itemsCollection, t);
|
if (isRecentFolder)
|
||||||
|
return this.getRecentFolderOptions(itemsCollection, t);
|
||||||
|
|
||||||
return this.getAnotherFolderOptions(itemsCollection, t);
|
return this.getAnotherFolderOptions(itemsCollection, t);
|
||||||
};
|
};
|
||||||
|
@ -7,10 +7,10 @@ import FilesActionsStore from "./FilesActionsStore";
|
|||||||
import FilesStore from "./FilesStore";
|
import FilesStore from "./FilesStore";
|
||||||
import FormatsStore from "./FormatsStore";
|
import FormatsStore from "./FormatsStore";
|
||||||
import iconFormatsStore from "./IconFormatsStore";
|
import iconFormatsStore from "./IconFormatsStore";
|
||||||
|
import InfoPanelStore from "./InfoPanelStore";
|
||||||
import MediaViewerDataStore from "./MediaViewerDataStore";
|
import MediaViewerDataStore from "./MediaViewerDataStore";
|
||||||
import mediaViewersFormatsStore from "./MediaViewersFormatsStore";
|
import mediaViewersFormatsStore from "./MediaViewersFormatsStore";
|
||||||
import PrimaryProgressDataStore from "./PrimaryProgressDataStore";
|
import PrimaryProgressDataStore from "./PrimaryProgressDataStore";
|
||||||
import InfoPanelStore from "./InfoPanelStore";
|
|
||||||
import SecondaryProgressDataStore from "./SecondaryProgressDataStore";
|
import SecondaryProgressDataStore from "./SecondaryProgressDataStore";
|
||||||
import selectedFilesStore from "./SelectedFilesStore";
|
import selectedFilesStore from "./SelectedFilesStore";
|
||||||
import selectedFolderStore from "./SelectedFolderStore";
|
import selectedFolderStore from "./SelectedFolderStore";
|
||||||
@ -37,8 +37,7 @@ const filesStore = new FilesStore(
|
|||||||
selectedFolderStore,
|
selectedFolderStore,
|
||||||
treeFoldersStore,
|
treeFoldersStore,
|
||||||
formatsStore,
|
formatsStore,
|
||||||
settingsStore,
|
settingsStore
|
||||||
selectedFilesStore
|
|
||||||
);
|
);
|
||||||
const mediaViewerDataStore = new MediaViewerDataStore(filesStore, formatsStore);
|
const mediaViewerDataStore = new MediaViewerDataStore(filesStore, formatsStore);
|
||||||
|
|
||||||
@ -60,6 +59,9 @@ const uploadDataStore = new UploadDataStore(
|
|||||||
dialogsStore,
|
dialogsStore,
|
||||||
settingsStore
|
settingsStore
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const infoPanelStore = new InfoPanelStore();
|
||||||
|
|
||||||
const filesActionsStore = new FilesActionsStore(
|
const filesActionsStore = new FilesActionsStore(
|
||||||
store.auth,
|
store.auth,
|
||||||
uploadDataStore,
|
uploadDataStore,
|
||||||
@ -68,13 +70,12 @@ const filesActionsStore = new FilesActionsStore(
|
|||||||
selectedFolderStore,
|
selectedFolderStore,
|
||||||
settingsStore,
|
settingsStore,
|
||||||
dialogsStore,
|
dialogsStore,
|
||||||
mediaViewerDataStore
|
mediaViewerDataStore,
|
||||||
|
infoPanelStore
|
||||||
);
|
);
|
||||||
|
|
||||||
const versionHistoryStore = new VersionHistoryStore(filesStore);
|
const versionHistoryStore = new VersionHistoryStore(filesStore);
|
||||||
|
|
||||||
const infoPanelStore = new InfoPanelStore();
|
|
||||||
|
|
||||||
//const selectedFilesStore = new SelectedFilesStore(selectedFilesStore);
|
//const selectedFilesStore = new SelectedFilesStore(selectedFilesStore);
|
||||||
const stores = {
|
const stores = {
|
||||||
filesStore,
|
filesStore,
|
||||||
|
12
public/images/info.outline.react.svg
Normal file
12
public/images/info.outline.react.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_21120_56765)">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.5 2C5.18629 2 2.5 4.68629 2.5 8C2.5 11.3137 5.18629 14 8.5 14C11.8137 14 14.5 11.3137 14.5 8C14.5 4.68629 11.8137 2 8.5 2ZM0.5 8C0.5 3.58172 4.08172 0 8.5 0C12.9183 0 16.5 3.58172 16.5 8C16.5 12.4183 12.9183 16 8.5 16C4.08172 16 0.5 12.4183 0.5 8Z" fill="#333333"/>
|
||||||
|
<circle cx="8.5" cy="5" r="1" fill="#333333"/>
|
||||||
|
<rect x="7.5" y="7" width="2" height="5" rx="1" fill="#333333"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_21120_56765">
|
||||||
|
<rect width="16" height="16" fill="white" transform="translate(0.5)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 710 B |
Loading…
Reference in New Issue
Block a user