diff --git a/.github/codeql/config-codeql.yml b/.github/codeql/config-codeql.yml new file mode 100644 index 0000000000..33605d5189 --- /dev/null +++ b/.github/codeql/config-codeql.yml @@ -0,0 +1,3 @@ +--- +paths: + - ./** diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml new file mode 100644 index 0000000000..0acfe87efb --- /dev/null +++ b/.github/workflows/codeql.yaml @@ -0,0 +1,67 @@ +name: "CodeQL" + +on: + push: + branches: + - 'master' + - 'release/**' + - 'hotfix/**' + paths-ignore: + - '**/README.md' + - '**/LICENSE' + - '.github/**' + pull_request: + # The branches below must be a subset of the branches above + branches: + - 'master' + - 'release/**' + - 'hotfix/**' + paths-ignore: + - '**/README.md' + - '**/LICENSE' + - '.github/**' + schedule: + - cron: '45 3 * * 5' + +jobs: + analyze: + name: Analyze + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners + # Consider using larger runners for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] + # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout client + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + config-file: .github/codeql/config-codeql.yml + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/package.json b/package.json index 7d644cb792..ad45faac7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "docspace", - "version": "2.0.0", + "version": "2.0.1", "private": true, "workspaces": { "packages": [ diff --git a/packages/client/package.json b/packages/client/package.json index 5f6f88f15c..36d946ba11 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@docspace/client", - "version": "2.0.0", + "version": "2.0.1", "private": true, "homepage": "", "scripts": { diff --git a/packages/client/public/locales/ja-JP/Files.json b/packages/client/public/locales/ja-JP/Files.json index 4458a33195..da7dc159f4 100644 --- a/packages/client/public/locales/ja-JP/Files.json +++ b/packages/client/public/locales/ja-JP/Files.json @@ -1,6 +1,6 @@ { "AddedToClipboard": "項目は、クリップボードに追加されました", - "AdditionalLinks": "추가 링크", + "AdditionalLinks": "追加リンク", "AddMembersDescription": "新しいチームメンバーを手動で追加したり、リンクで招待したりすることができます。", "AddNewLink": "新しいリンクの追加", "All": "すべて", diff --git a/packages/client/src/HOCs/withContent.js b/packages/client/src/HOCs/withContent.js index 78dbaf5498..b92ef1ee20 100644 --- a/packages/client/src/HOCs/withContent.js +++ b/packages/client/src/HOCs/withContent.js @@ -35,7 +35,7 @@ export default function withContent(WrappedContent) { } getStatusByDate = (create) => { - const { culture, item, personal } = this.props; + const { culture, item } = this.props; const { created, updated } = item; const locale = getCookie(LANGUAGE) || culture; diff --git a/packages/client/src/HOCs/withHotkeys.js b/packages/client/src/HOCs/withHotkeys.js index cac7e5921c..b6e38ce1a7 100644 --- a/packages/client/src/HOCs/withHotkeys.js +++ b/packages/client/src/HOCs/withHotkeys.js @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import { useEffect, useState } from "react"; import { useHotkeys } from "react-hotkeys-hook"; import { observer, inject } from "mobx-react"; import { useNavigate } from "react-router-dom"; @@ -67,17 +67,24 @@ const withHotkeys = (Component) => { const navigate = useNavigate(); + const [isEnabled, setIsEnabled] = useState(true); + const hotkeysFilter = { filter: (ev) => ev.target?.type === "checkbox" || ev.target?.tagName !== "INPUT", filterPreventDefault: false, enableOnTags: ["INPUT"], - enabled: enabledHotkeys && !mediaViewerIsVisible && !filesIsLoading, + enabled: + enabledHotkeys && !mediaViewerIsVisible && !filesIsLoading && isEnabled, // keyup: true, // keydown: false, }; - const onKeyDown = (e) => activateHotkeys(e); + const onKeyDown = (e) => { + const someDialogIsOpen = checkDialogsOpen(); + setIsEnabled(!someDialogIsOpen); + activateHotkeys(e); + }; const folderWithNoAction = isFavoritesFolder || diff --git a/packages/client/src/Shell.jsx b/packages/client/src/Shell.jsx index 25cdbe71b2..3276d9650a 100644 --- a/packages/client/src/Shell.jsx +++ b/packages/client/src/Shell.jsx @@ -18,7 +18,7 @@ import { I18nextProvider, useTranslation } from "react-i18next"; import i18n from "./i18n"; import Snackbar from "@docspace/components/snackbar"; -import moment from "moment"; +import moment from "moment-timezone"; //import ReactSmartBanner from "./components/SmartBanner"; import { useThemeDetector } from "@docspace/common/utils/useThemeDetector"; import { isMobile, isIOS, isFirefox } from "react-device-detect"; @@ -54,7 +54,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => { standalone, userId, currentDeviceType, - + timezone, showArticleLoader, } = rest; @@ -484,11 +484,15 @@ const ThemeProviderWrapper = inject(({ auth, loginStore }) => { currentColorScheme = settingsStore.currentColorScheme || false; } + const { timezone } = settingsStore; + window.theme = theme; + window.timezone = timezone; return { theme: { ...theme, interfaceDirection: i18n.dir() }, currentColorScheme, + timezone, }; })(observer(ThemeProvider)); diff --git a/packages/client/src/components/Article/Body/Items.js b/packages/client/src/components/Article/Body/Items.js index 870ad4beac..835b6bb17d 100644 --- a/packages/client/src/components/Article/Body/Items.js +++ b/packages/client/src/components/Article/Body/Items.js @@ -139,7 +139,7 @@ const Item = ({ labelBadge={labelBadge} onClickBadge={onBadgeClick} iconBadge={iconBadge} - badgeTitle={t("RecycleBinAction")} + badgeTitle={labelBadge ? "" : t("RecycleBinAction")} /> ); diff --git a/packages/client/src/components/Badges.js b/packages/client/src/components/Badges.js index 31f45c41a7..a6c032b5f4 100644 --- a/packages/client/src/components/Badges.js +++ b/packages/client/src/components/Badges.js @@ -11,6 +11,8 @@ import Mute16ReactSvgUrl from "PUBLIC_DIR/images/icons/16/mute.react.svg?url"; import React, { useState } from "react"; import styled from "styled-components"; +import { isMobile as isMobileDevice } from "react-device-detect"; + import Badge from "@docspace/components/badge"; import IconButton from "@docspace/components/icon-button"; import commonIconsStyles from "@docspace/components/utils/common-icons-style"; @@ -23,7 +25,7 @@ import { import { Base } from "@docspace/components/themes"; import { ColorTheme, ThemeType } from "@docspace/components/ColorTheme"; -import { isTablet, isDesktop } from "@docspace/components/utils/device"; +import { isTablet, isDesktop, size } from "@docspace/components/utils/device"; import { classNames } from "@docspace/components/utils/classNames"; const StyledWrapper = styled.div` @@ -114,7 +116,10 @@ const Badges = ({ const contentNewItems = newItems > 999 ? "999+" : newItems; - const tabletViewBadge = !isTile && isTablet(); + const isLargeTabletDevice = + isMobileDevice && window.innerWidth >= size.desktop; + + const tabletViewBadge = !isTile && (isTablet() || isLargeTabletDevice); const desktopView = !isTile && isDesktop(); const sizeBadge = isTile || tabletViewBadge ? "medium" : "small"; diff --git a/packages/client/src/components/FilesSelector/FilesSelector.types.ts b/packages/client/src/components/FilesSelector/FilesSelector.types.ts index 22ad9b062d..0a9e2cc987 100644 --- a/packages/client/src/components/FilesSelector/FilesSelector.types.ts +++ b/packages/client/src/components/FilesSelector/FilesSelector.types.ts @@ -71,6 +71,7 @@ export type useRootHelperProps = { onSetBaseFolderPath?: ( value: number | string | undefined | BreadCrumb[] ) => void; + isUserOnly?: boolean; }; export type useRoomsHelperProps = { @@ -129,6 +130,7 @@ export type FilesSelectorProps = { isThirdParty: boolean; rootThirdPartyId?: string; isRoomsOnly: boolean; + isUserOnly: boolean; isRoomBackup: boolean; isEditorDialog: boolean; setMoveToPublicRoomVisible: (visible: boolean, operationData: object) => void; @@ -217,5 +219,6 @@ export type FilesSelectorProps = { embedded: boolean; withHeader: boolean; + withCancelButton: boolean; settings: any; }; diff --git a/packages/client/src/components/FilesSelector/helpers/useRootHelper.ts b/packages/client/src/components/FilesSelector/helpers/useRootHelper.ts index f51c745bb5..fa05fb9740 100644 --- a/packages/client/src/components/FilesSelector/helpers/useRootHelper.ts +++ b/packages/client/src/components/FilesSelector/helpers/useRootHelper.ts @@ -20,6 +20,7 @@ const useRootHelper = ({ setIsNextPageLoading, setTotal, setHasNextPage, + isUserOnly, }: useRootHelperProps) => { const [isRoot, setIsRoot] = React.useState(false); @@ -41,7 +42,7 @@ const useRootHelper = ({ const avatar = getCatalogIconUrlByType(folder.rootFolderType); if ( - folder.rootFolderType === FolderType.Rooms || + (!isUserOnly && folder.rootFolderType === FolderType.Rooms) || folder.rootFolderType === FolderType.USER ) { newItems.push({ diff --git a/packages/client/src/components/FilesSelector/index.tsx b/packages/client/src/components/FilesSelector/index.tsx index 3332680fd0..dbf9d8d765 100644 --- a/packages/client/src/components/FilesSelector/index.tsx +++ b/packages/client/src/components/FilesSelector/index.tsx @@ -38,6 +38,7 @@ const FilesSelector = ({ // withoutImmediatelyClose = false, isThirdParty = false, isRoomsOnly = false, + isUserOnly = false, isEditorDialog = false, rootThirdPartyId, @@ -100,6 +101,7 @@ const FilesSelector = ({ embedded, withHeader, + withCancelButton = true, getIcon, isRoomBackup, }: FilesSelectorProps) => { @@ -164,6 +166,7 @@ const FilesSelector = ({ setHasNextPage, setIsNextPageLoading, onSetBaseFolderPath, + isUserOnly, }); const { getRoomList } = useRoomsHelper({ @@ -523,7 +526,7 @@ const FilesSelector = ({ onSelect={onSelectAction} acceptButtonLabel={acceptButtonLabel} onAccept={onAcceptAction} - withCancelButton + withCancelButton={withCancelButton} cancelButtonLabel={t("Common:CancelButton")} onCancel={onCloseAction} emptyScreenImage={ @@ -567,7 +570,9 @@ const FilesSelector = ({ currentFooterInputValue={currentFooterInputValue} footerCheckboxLabel={footerCheckboxLabel} descriptionText={ - !filterParam ? "" : descriptionText ?? t("Common:SelectDOCXFormat") + !filterParam || filterParam === "ALL" + ? "" + : descriptionText ?? t("Common:SelectDOCXFormat") } acceptButtonId={ isMove || isCopy || isRestore ? "select-file-modal-submit" : "" diff --git a/packages/client/src/components/GlobalEvents/CreateRoomEvent.js b/packages/client/src/components/GlobalEvents/CreateRoomEvent.js index 6931e81413..84ad8511ba 100644 --- a/packages/client/src/components/GlobalEvents/CreateRoomEvent.js +++ b/packages/client/src/components/GlobalEvents/CreateRoomEvent.js @@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next"; import { CreateRoomDialog } from "../dialogs"; const CreateRoomEvent = ({ + title, visible, onClose, @@ -57,6 +58,7 @@ const CreateRoomEvent = ({ return ( { }); const [createRoomDialogProps, setCreateRoomDialogProps] = useState({ + title: "", visible: false, onClose: null, }); @@ -101,9 +102,10 @@ const GlobalEvents = ({ enablePlugins, eventListenerItemsList }) => { const onCreateRoom = useCallback((e) => { setCreateRoomDialogProps({ + title: e?.title, visible: true, onClose: () => - setCreateRoomDialogProps({ visible: false, onClose: null }), + setCreateRoomDialogProps({ title: "", visible: false, onClose: null }), }); }, []); diff --git a/packages/client/src/components/Layout/index.js b/packages/client/src/components/Layout/index.js index 7b3a84c3e4..5fb4b0a96b 100644 --- a/packages/client/src/components/Layout/index.js +++ b/packages/client/src/components/Layout/index.js @@ -107,6 +107,8 @@ const Layout = (props) => { }; const onScroll = (e) => { + if (window.innerHeight < window.innerWidth) return; + e.preventDefault(); e.stopPropagation(); window.scrollTo(0, 0); diff --git a/packages/client/src/components/Main/index.js b/packages/client/src/components/Main/index.js index f7209cbbe5..7192851cbb 100644 --- a/packages/client/src/components/Main/index.js +++ b/packages/client/src/components/Main/index.js @@ -33,7 +33,7 @@ const StyledMain = styled.main` `; const Main = (props) => { - const { mainBarVisible, isBannerVisible } = props; + const { mainBarVisible, isBannerVisible, isFrame } = props; //console.log("Main render"); const [mainHeight, setMainHeight] = React.useState(window.innerHeight); const updateSizeRef = React.useRef(null); @@ -51,7 +51,7 @@ const Main = (props) => { React.useEffect(() => { onResize(); - }, [mainBarVisible, isBannerVisible]); + }, [mainBarVisible, isBannerVisible, isFrame]); const onResize = React.useCallback( (e) => { @@ -89,13 +89,13 @@ const Main = (props) => { } // 48 - its nav menu with burger, logo and user avatar - if (isMobileUtils()) { + if (isMobileUtils() && !isFrame) { correctHeight -= 48; } setMainHeight(correctHeight); }, - [mainBarVisible, isBannerVisible] + [mainBarVisible, isBannerVisible, isFrame] ); return ; @@ -106,9 +106,10 @@ Main.displayName = "Main"; export default inject(({ auth }) => { const { isBannerVisible } = auth.bannerStore; - const { mainBarVisible } = auth.settingsStore; + const { mainBarVisible, isFrame } = auth.settingsStore; return { mainBarVisible, isBannerVisible, + isFrame, }; })(observer(Main)); diff --git a/packages/client/src/components/RoomSelector/index.js b/packages/client/src/components/RoomSelector/index.js index cd261b1520..86275a8bd3 100644 --- a/packages/client/src/components/RoomSelector/index.js +++ b/packages/client/src/components/RoomSelector/index.js @@ -43,7 +43,7 @@ const convertToItems = (folders) => { const icon = logo.medium ? logo.medium : getRoomLogo(roomType); const color = logo.color; - return { id, label: title, icon, color }; + return { id, label: title, icon, color, logo, roomType }; }); return items; diff --git a/packages/client/src/components/dialogs/CreateEditRoomDialog/CreateRoomDialog.js b/packages/client/src/components/dialogs/CreateEditRoomDialog/CreateRoomDialog.js index cf6aa2302d..fb88c838bd 100644 --- a/packages/client/src/components/dialogs/CreateEditRoomDialog/CreateRoomDialog.js +++ b/packages/client/src/components/dialogs/CreateEditRoomDialog/CreateRoomDialog.js @@ -35,6 +35,7 @@ const StyledModalDialog = styled(ModalDialog)` const CreateRoomDialog = ({ t, visible, + title, onClose, onCreate, @@ -59,7 +60,7 @@ const CreateRoomDialog = ({ const startRoomParams = { type: undefined, - title: "", + title: title, tags: [], isPrivate: false, storageLocation: { @@ -93,7 +94,7 @@ const CreateRoomDialog = ({ })); }; - const isRoomTitleChanged = roomParams.title.trim() !== "" ? false : true; + const isRoomTitleChanged = roomParams?.title?.trim() !== "" ? false : true; const onKeyUpHandler = (e) => { if (isWrongTitle) return; @@ -101,7 +102,7 @@ const CreateRoomDialog = ({ }; const onCreateRoom = async () => { - if (!roomParams.title.trim()) { + if (!roomParams?.title?.trim()) { setIsValidTitle(false); return; } diff --git a/packages/client/src/components/dialogs/DeleteLinkDialog/index.js b/packages/client/src/components/dialogs/DeleteLinkDialog/index.js index 115d9841a6..a1a726ef44 100644 --- a/packages/client/src/components/dialogs/DeleteLinkDialog/index.js +++ b/packages/client/src/components/dialogs/DeleteLinkDialog/index.js @@ -87,7 +87,11 @@ const DeleteLinkDialogComponent = (props) => {