├── .distignore ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .gitmodules ├── .npmrc ├── .nvmrc ├── .php-cs-fixer.php ├── .prettierignore ├── .prettierrc ├── .stylelintignore ├── .stylelintrc.json ├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── assets ├── fonts │ └── Outfit │ │ └── Outfit-VariableFont_wght.ttf ├── img │ ├── banner.png │ ├── logo.svg │ └── logo │ │ ├── assist.svg │ │ ├── form.svg │ │ └── integration.svg └── themes │ ├── bootstrap │ ├── bootstrap │ │ ├── bootstrap.json │ │ └── bootstrap.min.css │ └── img │ │ ├── libre-archive.svg │ │ ├── libre-arrow-left.svg │ │ ├── libre-arrow-right.svg │ │ ├── libre-caret-down.svg │ │ ├── libre-chevron-left.svg │ │ ├── libre-chevron-right.svg │ │ ├── libre-close.svg │ │ ├── libre-copy.svg │ │ ├── libre-crop.svg │ │ ├── libre-cut.svg │ │ ├── libre-download.svg │ │ ├── libre-edit.svg │ │ ├── libre-exclamation-circle.svg │ │ ├── libre-file-archive.svg │ │ ├── libre-file-audio.svg │ │ ├── libre-file-code.svg │ │ ├── libre-file-docs.svg │ │ ├── libre-file-image.svg │ │ ├── libre-file-pdf.svg │ │ ├── libre-file-text.svg │ │ ├── libre-file-video.svg │ │ ├── libre-file.svg │ │ ├── libre-film.svg │ │ ├── libre-folder-archive.svg │ │ ├── libre-folder-attachments.svg │ │ ├── libre-folder-backup.svg │ │ ├── libre-folder-document.svg │ │ ├── libre-folder-featured.svg │ │ ├── libre-folder-open.svg │ │ ├── libre-folder-orders.svg │ │ ├── libre-folder-picture.svg │ │ ├── libre-folder-users.svg │ │ ├── libre-folder-video.svg │ │ ├── libre-folder.svg │ │ ├── libre-help.svg │ │ ├── libre-home.svg │ │ ├── libre-layout-blocks.svg │ │ ├── libre-layout-list.svg │ │ ├── libre-level-up.svg │ │ ├── libre-paste.svg │ │ ├── libre-question-circle.svg │ │ ├── libre-refresh.svg │ │ ├── libre-resize-full.svg │ │ ├── libre-resize-small.svg │ │ ├── libre-search.svg │ │ ├── libre-server.svg │ │ ├── libre-sort-asc.svg │ │ ├── libre-sort-desc.svg │ │ ├── libre-sort.svg │ │ ├── libre-text-cursor.svg │ │ ├── libre-trash.svg │ │ ├── libre-upload.svg │ │ └── libre-view.svg │ └── material │ ├── font │ ├── material.eot │ ├── material.svg │ ├── material.ttf │ ├── material.woff │ └── material.woff2 │ ├── material-default │ ├── material-default.json │ └── material-default.min.css │ ├── material-gray │ ├── material-gray.json │ └── material-gray.min.css │ └── material-light │ ├── material-light.json │ └── material-light.min.css ├── backend ├── app │ ├── Config.php │ ├── Exception │ │ └── PreCommandException.php │ ├── Http │ │ ├── Controllers │ │ │ ├── FileManagerController.php │ │ │ ├── LogController.php │ │ │ ├── PermissionsController.php │ │ │ ├── SettingsController.php │ │ │ └── TelemetryPopupController.php │ │ ├── Middleware │ │ │ ├── CapCheckerMiddleware.php │ │ │ └── NonceCheckerMiddleware.php │ │ ├── Requests │ │ │ ├── Log │ │ │ │ └── DeleteLogRequest.php │ │ │ ├── Permissions │ │ │ │ ├── AddUserPermissionRequest.php │ │ │ │ ├── DeleteUserPermissionRequest.php │ │ │ │ ├── PermissionsGetRequest.php │ │ │ │ ├── PermissionsUpdateRequest.php │ │ │ │ └── SearchUserRequest.php │ │ │ ├── Settings │ │ │ │ ├── LangUpdateRequest.php │ │ │ │ ├── SettingsRequest.php │ │ │ │ ├── SettingsUpdateRequest.php │ │ │ │ ├── ThemeUpdateRequest.php │ │ │ │ └── ToggleViewRequest.php │ │ │ └── TryPluginRequest.php │ │ ├── Rules │ │ │ ├── ValidPathRule.php │ │ │ ├── ValidUIOptionRule.php │ │ │ ├── ValidateCommandsRule.php │ │ │ ├── ValidateLangRule.php │ │ │ ├── ValidateRolesRule.php │ │ │ ├── ValidateThemeRule.php │ │ │ └── ValidateUsersRule.php │ │ └── Services │ │ │ └── LogService.php │ ├── Model │ │ ├── Log.php │ │ └── User.php │ ├── Plugin.php │ ├── Providers │ │ ├── AccessControlProvider.php │ │ ├── FileEditValidator.php │ │ ├── FileManager │ │ │ ├── ClientOptions.php │ │ │ ├── FileManagerProvider.php │ │ │ ├── FileRoot.php │ │ │ ├── FinderConnector.php │ │ │ └── Options.php │ │ ├── HookProvider.php │ │ ├── InstallerProvider.php │ │ ├── Logger.php │ │ ├── MediaSynchronizer.php │ │ ├── MimeProvider.php │ │ ├── PermissionsProvider.php │ │ ├── PreferenceProvider.php │ │ └── VersionMigrationProvider.php │ └── Views │ │ ├── Admin.php │ │ └── Shortcode.php ├── bootstrap.php ├── config │ └── app.php ├── db │ └── Migrations │ │ ├── BFMLogsTableMigration.php │ │ └── BFMPluginOptions.php ├── functions │ ├── common.php │ └── global.php └── hooks │ ├── ajax.php │ └── api.php ├── composer.json ├── composer.lock ├── file-manager.php ├── frontend ├── finder-loader.js └── src │ ├── AppRoutes.tsx │ ├── changeLog.ts │ ├── common │ ├── globalStates │ │ ├── $appConfig.ts │ │ ├── $finder.ts │ │ ├── $navigate.ts │ │ ├── GlobalStates.d.ts │ │ └── index.ts │ ├── helpers │ │ ├── atomWithBroadcast.ts │ │ ├── generateData.ts │ │ ├── globalHelpers.ts │ │ ├── i18nwrap.ts │ │ └── request.ts │ └── hooks │ │ ├── useAsyncInterval.tsx │ │ ├── useCopyToClipboard.tsx │ │ ├── useDebounce.tsx │ │ ├── useEventListener.tsx │ │ ├── useInterval.tsx │ │ ├── useIsomorphicLayoutEffect.tsx │ │ └── useOnClickOutside.tsx │ ├── components │ └── utilities │ │ ├── AnimateHeight │ │ ├── AnimateHeight.tsx │ │ └── index.ts │ │ ├── ConfirmationModal │ │ ├── ConfirmationModal.module.css │ │ ├── ConfirmationModal.stories.mdx │ │ ├── ConfirmationModal.stories.tsx │ │ ├── ConfirmationModal.tsx │ │ ├── ConfirmationModalStory.tsx │ │ └── index.tsx │ │ ├── DotLoader │ │ ├── DotLoader.module.scss │ │ ├── DotLoader.tsx │ │ └── index.tsx │ │ ├── DropDown │ │ ├── DropDown.module.css │ │ ├── DropDown.stories.mdx │ │ ├── DropDown.stories.tsx │ │ ├── DropDown.tsx │ │ ├── index.tsx │ │ └── static │ │ │ └── TippyLightTheme.css │ │ ├── Fade │ │ ├── Fade.tsx │ │ └── index.tsx │ │ ├── IconBtn │ │ ├── IconBtn.module.css │ │ ├── IconBtn.stories.mdx │ │ ├── IconBtn.stories.tsx │ │ ├── IconBtn.test.tsx │ │ ├── IconBtn.tsx │ │ └── index.tsx │ │ ├── If.tsx │ │ ├── Input │ │ ├── Input.stories.mdx │ │ ├── Input.stories.tsx │ │ ├── Input.test.tsx │ │ ├── Input.tsx │ │ └── index.ts │ │ ├── InputCopyable │ │ ├── InputCopyable.tsx │ │ └── index.ts │ │ ├── InputGroup │ │ ├── InputGroup.module.css │ │ ├── InputGroup.stories.tsx │ │ ├── InputGroup.tsx │ │ └── index.tsx │ │ ├── Popover │ │ ├── Popover.tsx │ │ ├── PopoverContent.tsx │ │ ├── PopoverHeader.tsx │ │ ├── PopoverTrigger.tsx │ │ ├── index.tsx │ │ └── static │ │ │ └── TippyLightTheme.css │ │ ├── Segment │ │ ├── Segment.module.css │ │ ├── Segment.test.tsx │ │ ├── Segment.tsx │ │ ├── SegmentLabel.tsx │ │ ├── SegmentTab.tsx │ │ ├── SegmentTip.tsx │ │ └── index.tsx │ │ ├── Select │ │ ├── Select.tsx │ │ └── index.ts │ │ ├── SpinnerLoader │ │ ├── SpinnerLoader.module.css │ │ ├── SpinnerLoader.module.css.map │ │ ├── SpinnerLoader.module.scss │ │ ├── SpinnerLoader.test.tsx │ │ ├── SpinnerLoader.tsx │ │ └── index.ts │ │ ├── Tabs │ │ ├── TabPanel.tsx │ │ ├── Tabs.tsx │ │ └── index.tsx │ │ ├── TagFilter │ │ ├── TagFilter.module.css │ │ ├── TagFilter.test.tsx │ │ ├── TagFilter.tsx │ │ ├── TagFilterType.d.ts │ │ ├── TagListMenu.tsx │ │ └── index.tsx │ │ ├── TelemetryPopup │ │ ├── Index.ts │ │ ├── TelemetryPopup.module.css │ │ └── TelemetryPopup.tsx │ │ └── Tip │ │ ├── Tip.tsx │ │ ├── index.tsx │ │ └── static │ │ └── TipLightTheme.css │ ├── config │ ├── config.ts │ ├── devHotModule.js │ └── themes │ │ ├── common.ts │ │ ├── theme.dark.ts │ │ └── theme.light.ts │ ├── icons │ ├── AntIconWrapper.tsx │ ├── CheckCircle.tsx │ ├── ChevronDown.tsx │ ├── ChevronLeft.tsx │ ├── CloseIcn.tsx │ ├── CopyIcn.tsx │ ├── DashboardIcn.tsx │ ├── DataNotFound.tsx │ ├── DeleteIcon.tsx │ ├── Dots.tsx │ ├── DotsVertical.tsx │ ├── EditIcon.tsx │ ├── IconTypes.ts │ ├── Icons.module.css │ ├── Icons.tsx │ ├── LogoIcn.tsx │ ├── LogoText.tsx │ ├── LucideIcn.tsx │ ├── MoonIcn.tsx │ ├── PinIcon.tsx │ ├── PinSolidIcon.tsx │ ├── Plus.tsx │ ├── RedoIcon.tsx │ ├── RouterIcn.tsx │ ├── SearchIcon.tsx │ ├── SettingIcon.tsx │ ├── SunIcn.tsx │ ├── SupportIcn.tsx │ ├── UndoIcon.tsx │ └── Wire.tsx │ ├── main.tsx │ ├── pages │ ├── Error404 │ │ ├── Error404.tsx │ │ └── index.ts │ ├── Layout │ │ ├── index.ts │ │ └── ui │ │ │ ├── Layout.module.css │ │ │ ├── Layout.tsx │ │ │ └── Navigation │ │ │ ├── Sidebar │ │ │ ├── Sidebar.module.css │ │ │ ├── Sidebar.tsx │ │ │ ├── SidebarNavItem.tsx │ │ │ ├── SidebarNavItemWithTooltip.tsx │ │ │ └── index.ts │ │ │ └── TopNavigation │ │ │ ├── TopNavigation.module.css │ │ │ ├── TopNavigation.tsx │ │ │ ├── data │ │ │ ├── useFetchLang.ts │ │ │ ├── useUpdateLang.ts │ │ │ └── useUpdateTheme.ts │ │ │ ├── index.ts │ │ │ └── static │ │ │ └── MenuItems.tsx │ ├── Logs │ │ ├── data │ │ │ ├── useDeleteLog.ts │ │ │ └── useFetchLogs.ts │ │ ├── index.ts │ │ └── ui │ │ │ └── Logs.tsx │ ├── Permissions │ │ ├── PermissionsSettingsTypes.d.ts │ │ ├── data │ │ │ ├── useAddUserPermission.ts │ │ │ ├── useDeleteUserPermission.ts │ │ │ ├── useFetchPermissionsSettings.ts │ │ │ ├── useFetchUserByUsername.ts │ │ │ ├── useUpdatePermissionsSettings.ts │ │ │ └── useUpdateUserPermission.ts │ │ ├── index.ts │ │ └── ui │ │ │ ├── AddUserPermissionModal.tsx │ │ │ └── Permissions.tsx │ ├── Settings │ │ ├── data │ │ │ ├── useFetchSettings.ts │ │ │ ├── useUpdateSettings.ts │ │ │ └── useUpdateViewType.ts │ │ ├── index.ts │ │ ├── settingsTypes.d.ts │ │ └── ui │ │ │ └── Settings.tsx │ ├── Support │ │ ├── index.ts │ │ └── ui │ │ │ └── Support.tsx │ ├── SystemInformation │ │ ├── index.ts │ │ └── ui │ │ │ └── SystemInformation.tsx │ └── root │ │ ├── Root.tsx │ │ └── helpers │ │ ├── configureElFinder.ts │ │ └── initThemeChangeHandler.ts │ ├── resource │ ├── globalCssInJs.ts │ ├── img │ │ ├── apps │ │ │ └── bit-form.svg │ │ ├── earlyBirdOffer.png │ │ ├── home.svg │ │ ├── logo.svg │ │ ├── nodata.svg │ │ └── space.svg │ ├── styles │ │ ├── global.css │ │ ├── plugin.css │ │ ├── utilities.sass │ │ ├── variables.css │ │ └── wp-css-reset.css │ └── utilsCssInJs.ts │ └── types │ ├── emotion.d.ts │ ├── finder.d.ts │ ├── global.d.ts │ ├── ts-reset.d.ts │ └── window.d.ts ├── gettext-parser.config.js ├── libs ├── elFinder │ ├── LICENSE.md │ ├── css │ │ ├── elfinder.full.css │ │ ├── elfinder.min.css │ │ └── theme.css │ ├── files │ │ ├── .gitignore │ │ └── .trash │ │ │ └── .gitignore │ ├── img │ │ ├── arrows-active.png │ │ ├── arrows-normal.png │ │ ├── crop.gif │ │ ├── dialogs.png │ │ ├── editor-icons.png │ │ ├── icons-big.png │ │ ├── icons-big.svg │ │ ├── icons-small.png │ │ ├── logo.png │ │ ├── progress.gif │ │ ├── quicklook-bg.png │ │ ├── quicklook-icons.png │ │ ├── resize.png │ │ ├── spinner-mini.gif │ │ ├── toolbar.png │ │ ├── trashmesh.png │ │ ├── ui-icons_ffffff_256x240.png │ │ ├── volume_icon_box.png │ │ ├── volume_icon_box.svg │ │ ├── volume_icon_dropbox.png │ │ ├── volume_icon_dropbox.svg │ │ ├── volume_icon_ftp.png │ │ ├── volume_icon_ftp.svg │ │ ├── volume_icon_googledrive.png │ │ ├── volume_icon_googledrive.svg │ │ ├── volume_icon_local.png │ │ ├── volume_icon_local.svg │ │ ├── volume_icon_network.png │ │ ├── volume_icon_network.svg │ │ ├── volume_icon_onedrive.png │ │ ├── volume_icon_onedrive.svg │ │ ├── volume_icon_sql.png │ │ ├── volume_icon_sql.svg │ │ ├── volume_icon_trash.png │ │ ├── volume_icon_trash.svg │ │ ├── volume_icon_zip.png │ │ └── volume_icon_zip.svg │ ├── js │ │ ├── cdn │ │ │ ├── ace.js │ │ │ ├── ace.min.js │ │ │ ├── amrnb.js │ │ │ ├── bzip2.js │ │ │ ├── ckeditor.js │ │ │ ├── ckeditor.min.js │ │ │ ├── ckeditor5.js │ │ │ ├── codemirror.js │ │ │ ├── codemirror.min.js │ │ │ ├── dash-all.js │ │ │ ├── dash.all.min.js │ │ │ ├── fabric-1.6.7.js │ │ │ ├── fabric-1.6.7.min.js │ │ │ ├── fabric.js │ │ │ ├── fabric.min.js │ │ │ ├── flv.js │ │ │ ├── flv.min.js │ │ │ ├── gunzip.js │ │ │ ├── gunzip.min.js │ │ │ ├── hls.js │ │ │ ├── hls.min.js │ │ │ ├── marked.js │ │ │ ├── marked.min.js │ │ │ ├── psd.js │ │ │ ├── psd.min.js │ │ │ ├── rar.js │ │ │ ├── rar.min.js │ │ │ ├── run_prettify.js │ │ │ ├── sha.js │ │ │ ├── sha.min.js │ │ │ ├── simplemde.js │ │ │ ├── simplemde.min.js │ │ │ ├── spark-md5.js │ │ │ ├── spark-md5.min.js │ │ │ ├── tiff.js │ │ │ ├── tiff.min.js │ │ │ ├── timymce.js │ │ │ ├── timymce.min.js │ │ │ ├── tui-code-snippet.min.js │ │ │ ├── tui.js │ │ │ ├── unzip.js │ │ │ ├── unzip.min.js │ │ │ ├── video.js │ │ │ └── video.min.js │ │ ├── elfinder.full.js │ │ ├── elfinder.min.js │ │ ├── extras │ │ │ ├── editors.default.js │ │ │ ├── editors.default.min.js │ │ │ ├── quicklook.googledocs.js │ │ │ └── quicklook.googledocs.min.js │ │ ├── i18n │ │ │ ├── elfinder.LANG.js │ │ │ ├── elfinder.ar.js │ │ │ ├── elfinder.bg.js │ │ │ ├── elfinder.ca.js │ │ │ ├── elfinder.cs.js │ │ │ ├── elfinder.da.js │ │ │ ├── elfinder.de.js │ │ │ ├── elfinder.el.js │ │ │ ├── elfinder.en.js │ │ │ ├── elfinder.es.js │ │ │ ├── elfinder.fa.js │ │ │ ├── elfinder.fallback.js │ │ │ ├── elfinder.fo.js │ │ │ ├── elfinder.fr.js │ │ │ ├── elfinder.fr_CA.js │ │ │ ├── elfinder.he.js │ │ │ ├── elfinder.hr.js │ │ │ ├── elfinder.hu.js │ │ │ ├── elfinder.id.js │ │ │ ├── elfinder.it.js │ │ │ ├── elfinder.ja.js │ │ │ ├── elfinder.ko.js │ │ │ ├── elfinder.nl.js │ │ │ ├── elfinder.no.js │ │ │ ├── elfinder.pl.js │ │ │ ├── elfinder.pt_BR.js │ │ │ ├── elfinder.ro.js │ │ │ ├── elfinder.ru.js │ │ │ ├── elfinder.si.js │ │ │ ├── elfinder.sk.js │ │ │ ├── elfinder.sl.js │ │ │ ├── elfinder.sr.js │ │ │ ├── elfinder.sv.js │ │ │ ├── elfinder.tr.js │ │ │ ├── elfinder.ug_CN.js │ │ │ ├── elfinder.uk.js │ │ │ ├── elfinder.vi.js │ │ │ ├── elfinder.zh_CN.js │ │ │ ├── elfinder.zh_TW.js │ │ │ └── help │ │ │ │ ├── cs.html.js │ │ │ │ ├── de.html.js │ │ │ │ ├── en.html.js │ │ │ │ ├── es.html.js │ │ │ │ ├── ja.html.js │ │ │ │ ├── ko.html.js │ │ │ │ ├── pl.html.js │ │ │ │ ├── ru.html.js │ │ │ │ ├── sk.html.js │ │ │ │ └── tr.html.js │ │ └── worker │ │ │ ├── calcfilehash.js │ │ │ ├── quicklook.tiff.js │ │ │ └── quicklook.unzip.js │ ├── php │ │ ├── .tmp │ │ │ └── .htaccess │ │ ├── autoload.php │ │ ├── editors │ │ │ ├── OnlineConvert │ │ │ │ └── editor.php │ │ │ ├── ZipArchive │ │ │ │ └── editor.php │ │ │ ├── ZohoOffice │ │ │ │ └── editor.php │ │ │ └── editor.php │ │ ├── elFinder.class.php │ │ ├── elFinderConnector.class.php │ │ ├── elFinderFlysystemGoogleDriveNetmount.php │ │ ├── elFinderPlugin.php │ │ ├── elFinderSession.php │ │ ├── elFinderSessionInterface.php │ │ ├── elFinderVolumeBox.class.php │ │ ├── elFinderVolumeDriver.class.php │ │ ├── elFinderVolumeDropbox2.class.php │ │ ├── elFinderVolumeFTP.class.php │ │ ├── elFinderVolumeGoogleDrive.class.php │ │ ├── elFinderVolumeGroup.class.php │ │ ├── elFinderVolumeLocalFileSystem.class.php │ │ ├── elFinderVolumeMySQL.class.php │ │ ├── elFinderVolumeOneDrive.class.php │ │ ├── elFinderVolumeSFTPphpseclib.class.php │ │ ├── elFinderVolumeTrash.class.php │ │ ├── elFinderVolumeTrashMySQL.class.php │ │ ├── libs │ │ │ └── GdBmp.php │ │ ├── mime.types │ │ ├── plugins │ │ │ ├── AutoResize │ │ │ │ └── plugin.php │ │ │ ├── AutoRotate │ │ │ │ └── plugin.php │ │ │ ├── Normalizer │ │ │ │ └── plugin.php │ │ │ ├── Sanitizer │ │ │ │ └── plugin.php │ │ │ ├── Watermark │ │ │ │ ├── logo.png │ │ │ │ └── plugin.php │ │ │ └── WinRemoveTailDots │ │ │ │ └── plugin.php │ │ └── resources │ │ │ ├── image.png │ │ │ └── video.png │ └── sounds │ │ └── rm.wav └── js │ └── jquery-ui │ ├── images │ ├── ui-icons_444444_256x240.png │ ├── ui-icons_555555_256x240.png │ ├── ui-icons_777620_256x240.png │ ├── ui-icons_777777_256x240.png │ ├── ui-icons_cc0000_256x240.png │ └── ui-icons_ffffff_256x240.png │ ├── jquery-ui.min.css │ └── jquery-ui.theme.min.css ├── package.json ├── phpcs.xml ├── pnpm-lock.yaml ├── readme.txt ├── svn-assets ├── banner-1544x500.png ├── banner-772x250.png ├── icon-1024x1024.png ├── icon-128x128.png ├── icon-256x256.png ├── icon-512x512.png ├── original │ ├── Library File Manager Banner.png │ ├── Plugin Logo (Dark).png │ ├── Plugin Logo (Light).png │ ├── Plugin Logo (1024 x1024).jpg │ ├── Plugin Logo (1024 x1024).png │ ├── Plugin Logo (128 x 128).jpg │ ├── Plugin Logo (128 x 128).png │ ├── Plugin Logo (256 x 256).jpg │ ├── Plugin Logo (256 x 256).png │ ├── Plugin Logo (512 x 512).jpg │ ├── Plugin Logo (512 x 512).png │ └── Plugin Logo (Transparent).png ├── screenshot-1.png ├── screenshot-10.png ├── screenshot-11.png ├── screenshot-12.png ├── screenshot-13.png ├── screenshot-2.png ├── screenshot-3.png ├── screenshot-4.png ├── screenshot-5.png ├── screenshot-6.png ├── screenshot-7.png ├── screenshot-8.png └── screenshot-9.png ├── testing ├── functions.php └── test.php ├── tools ├── build_copy.js ├── build_elfinder.sh ├── copy_themes.js ├── pot-to-php.mjs ├── themes.json └── zip_build.js ├── tsconfig.json ├── tsconfig.node.json ├── views ├── admin │ └── widget.php └── finder.php └── vite.config.mts /.distignore: -------------------------------------------------------------------------------- 1 | build 2 | composer.lock 3 | elFinder 4 | .eslintignore 5 | .eslintrc.js 6 | frontend 7 | gettext-parser.config.js 8 | .gitignore 9 | .gitmodules 10 | locale.pot 11 | node_modules 12 | .npmrc 13 | .nvmrc 14 | package.json* 15 | .php-cs-fixer.cache 16 | .php-cs-fixer.php 17 | phpcs.xml 18 | package-lock.json 19 | yarn.lock 20 | pnpm-lock.yaml 21 | .prettierignore 22 | .prettierrc 23 | .stylelintignore 24 | .stylelintrc.json 25 | sass 26 | submodule 27 | svn-assets 28 | testing 29 | tools 30 | tsconfig.json 31 | tsconfig.node.json 32 | vite.config.mts 33 | .vscode 34 | vendor/typisttech -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | coverage 4 | .eslintrc.js 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | .DS_Store 4 | node_modules 5 | elFinder 6 | css/style* 7 | build 8 | .wordpress-ripo 9 | .php-cs-fixer.cache 10 | dependencies 11 | assets/js 12 | locale.pot 13 | port 14 | languages -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodule/sources/elFinder"] 2 | path = submodule/sources/elFinder 3 | url = git@github.com:Bit-Apps-Pro/elFinder.git 4 | [submodule "submodule/sources/elFinder-Material-Theme"] 5 | path = submodule/sources/elFinder-Material-Theme 6 | url = git@github.com:RobiNN1/elFinder-Material-Theme.git 7 | [submodule "submodule/sources/LibreICONS"] 8 | path = submodule/sources/LibreICONS 9 | url = git@github.com:DiemenDesign/LibreICONS.git 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true 2 | shamefully-hoist=true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | coverage 4 | .eslintcache 5 | yarn.lock 6 | package-lock.json 7 | pnpm-lock.yaml -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["@trivago/prettier-plugin-sort-imports"], 3 | "semi": false, 4 | "bracketSpacing": true, 5 | "printWidth": 105, 6 | "useTabs": false, 7 | "tabWidth": 2, 8 | "singleQuote": true, 9 | "quoteProps": "as-needed", 10 | "jsxSingleQuote": false, 11 | "bracketSameLine": false, 12 | "endOfLine": "lf", 13 | "trailingComma": "none", 14 | "arrowParens": "avoid", 15 | "importOrder": ["^(^react$|@react|react)", "", "^@/(.*)$", "^[./]"], 16 | "importOrderSeparation": true, 17 | "importOrderSortSpecifiers": true 18 | } 19 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | # test reports 2 | coverage 3 | /coverage/ 4 | **/coverage/* 5 | 6 | # project files 7 | node_modules -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["stylelint-scss"], 3 | "extends": [ 4 | "stylelint-config-standard", 5 | "stylelint-config-css-modules", 6 | "stylelint-config-standard-scss" 7 | ], 8 | "rules": { 9 | "selector-class-pattern": "^(?:[A-Z][a-z0-9]*)+|(?:[a-z][a-z0-9]*)(?:-[a-z0-9]+)*", 10 | "no-missing-end-of-source-newline": null, 11 | "color-function-notation": "legacy", 12 | "selector-pseudo-class-no-unknown": [ 13 | true, 14 | { "ignorePseudoClasses": ["export", "import", "global", "local"] } 15 | ], 16 | "property-no-unknown": [true, { "ignoreProperties": ["composes", "compose-with"] }] 17 | }, 18 | "at-rule-no-unknown": [true, { "ignoreAtRules": ["keyframes", "value"] }], 19 | "scss/at-if-no-null": [true, { "ignoreAtRules": ["keyframes"] }] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "junstyle.php-cs-fixer", 4 | "bmewburn.vscode-intelephense-client", 5 | "mattpocock.ts-error-translator", 6 | "esbenp.prettier-vscode", 7 | "dbaeumer.vscode-eslint", 8 | "stylelint.vscode-stylelint", 9 | "sainoba.px-to-rem" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /assets/fonts/Outfit/Outfit-VariableFont_wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/assets/fonts/Outfit/Outfit-VariableFont_wght.ttf -------------------------------------------------------------------------------- /assets/img/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/assets/img/banner.png -------------------------------------------------------------------------------- /assets/themes/bootstrap/bootstrap/bootstrap.json: -------------------------------------------------------------------------------- 1 | {"name":"Bootstrap Default","cssurls":"./bootstrap.min.css","author":"DiemenDesign","license":"MIT","link":"https://github.com/DiemenDesign/LibreICONS/tree/master/themes/elFinder","image":"https://raw.githubusercontent.com/DiemenDesign/LibreICONS/master/themes/elFinder/elfinder-bootstrap-theme.png","description":"Bootstrap and LibreICONS theme for elFinder"} -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-archive.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-arrow-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-arrow-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-caret-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-chevron-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-chevron-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-crop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-exclamation-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-file-audio.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-file-docs.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-file-image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-file-text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-file-video.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-folder-open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-folder.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-help.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-layout-blocks.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-layout-list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-level-up.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-paste.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-resize-full.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-resize-small.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-search.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-server.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-sort-asc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-sort-desc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-sort.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-text-cursor.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-upload.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/bootstrap/img/libre-view.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/themes/material/font/material.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/assets/themes/material/font/material.eot -------------------------------------------------------------------------------- /assets/themes/material/font/material.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/assets/themes/material/font/material.ttf -------------------------------------------------------------------------------- /assets/themes/material/font/material.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/assets/themes/material/font/material.woff -------------------------------------------------------------------------------- /assets/themes/material/font/material.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/assets/themes/material/font/material.woff2 -------------------------------------------------------------------------------- /assets/themes/material/material-default/material-default.json: -------------------------------------------------------------------------------- 1 | {"name":"Material Default","cssurls":"./material-default.min.css","author":"Róbert Kelčák","license":"MIT","link":"https://github.com/RobiNN1/elFinder-Material-Theme","image":"https://raw.githubusercontent.com/RobiNN1/elFinder-Material-Theme/master/.github/img/preview-darkblue.png","description":"Material Theme for elFinder."} -------------------------------------------------------------------------------- /assets/themes/material/material-gray/material-gray.json: -------------------------------------------------------------------------------- 1 | {"name":"Material Gray","cssurls":"./material-gray.min.css","author":"Róbert Kelčák","license":"MIT","link":"https://github.com/RobiNN1/elFinder-Material-Theme","image":"https://raw.githubusercontent.com/RobiNN1/elFinder-Material-Theme/master/.github/img/preview-gray.png","description":"Material Theme for elFinder."} -------------------------------------------------------------------------------- /assets/themes/material/material-light/material-light.json: -------------------------------------------------------------------------------- 1 | {"name":"Material Light","cssurls":"./material-light.min.css","author":"Róbert Kelčák","license":"MIT","link":"https://github.com/RobiNN1/elFinder-Material-Theme","image":"https://raw.githubusercontent.com/RobiNN1/elFinder-Material-Theme/master/.github/img/preview-gray.png","description":"Material Theme for elFinder."} -------------------------------------------------------------------------------- /backend/app/Exception/PreCommandException.php: -------------------------------------------------------------------------------- 1 | true, 15 | 'results' => [ 16 | 'error' => $this->getMessage(), 17 | ] 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /backend/app/Http/Controllers/LogController.php: -------------------------------------------------------------------------------- 1 | logger = new LogService(); 18 | $currentTime = time(); 19 | $logDeletedAt = Config::getOption('log_deleted_at', ($currentTime - (DAY_IN_SECONDS * 30))); 20 | if ((abs($logDeletedAt - $currentTime) / DAY_IN_SECONDS) > 30) { 21 | $this->logger->deleteOlder(); 22 | } 23 | } 24 | 25 | public function all(Request $request) 26 | { 27 | $pageNo = \intval($request->pageNo) ?? 1; 28 | $limit = \intval($request->limit) ?? 14; 29 | 30 | return Response::success($this->logger->all((($pageNo - 1) * $limit), $limit)); 31 | } 32 | 33 | public function delete(DeleteLogRequest $request) 34 | { 35 | $validatedIds = array_map(function($id) { return intval($id);}, $request->ids); 36 | $status = $this->logger->delete($validatedIds); 37 | if ($status) { 38 | return Response::success([])->message('log deleted successfully'); 39 | } 40 | 41 | return Response::error([])->message('failed to delete log'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /backend/app/Http/Middleware/CapCheckerMiddleware.php: -------------------------------------------------------------------------------- 1 | __('You are not authorized to access this endpoint', 'file-manager'), 16 | 'code' => 'NOT_AUTHORIZED', 17 | 'status' => 'error', 18 | ] 19 | ); 20 | wp_die(); 21 | } 22 | 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /backend/app/Http/Middleware/NonceCheckerMiddleware.php: -------------------------------------------------------------------------------- 1 | has('nonce') 15 | || !( 16 | $request->has('nonce') 17 | && wp_verify_nonce(sanitize_key($request->nonce), $nonceKey) 18 | ) 19 | ) { 20 | $response = \in_array($request->getRoute()->getPath(), ['connector', 'connector_front']) 21 | ? wp_json_encode(['error' => __('Token expired. please reload the page', 'file-manager')]) 22 | : wp_json_encode( 23 | [ 24 | 'message' => __('Token expired. please reload the page', 'file-manager'), 25 | 'code' => 'INVALID_NONCE', 26 | 'status' => 'error', 27 | ] 28 | ); 29 | 30 | echo $response; 31 | wp_die(); 32 | } 33 | 34 | return true; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /backend/app/Http/Requests/Log/DeleteLogRequest.php: -------------------------------------------------------------------------------- 1 | ['required','array'] 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /backend/app/Http/Requests/Permissions/AddUserPermissionRequest.php: -------------------------------------------------------------------------------- 1 | ['sanitize:text', 'required','Integer'], 26 | 'path' => ['nullable', ValidPathRule::class], 27 | 'commands' => ['nullable', ValidateCommandsRule::class] 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /backend/app/Http/Requests/Permissions/DeleteUserPermissionRequest.php: -------------------------------------------------------------------------------- 1 | ['sanitize:text', 'required','Integer'] 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /backend/app/Http/Requests/Permissions/PermissionsGetRequest.php: -------------------------------------------------------------------------------- 1 | ['sanitize:text'], 24 | 'page' => ['sanitize:text', 'nullable','Integer'] 25 | ]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /backend/app/Http/Requests/Settings/LangUpdateRequest.php: -------------------------------------------------------------------------------- 1 | ['required','string', ValidateLangRule::class], 20 | ]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /backend/app/Http/Requests/Settings/SettingsRequest.php: -------------------------------------------------------------------------------- 1 | ['required','string', ValidateThemeRule::class], 20 | ]; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /backend/app/Http/Requests/Settings/ToggleViewRequest.php: -------------------------------------------------------------------------------- 1 | ['sanitize:text', 'required','string'], 19 | ]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /backend/app/Http/Requests/TryPluginRequest.php: -------------------------------------------------------------------------------- 1 | ['required','array'] 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /backend/app/Http/Rules/ValidPathRule.php: -------------------------------------------------------------------------------- 1 | preferences()->realPath($value); 15 | $isValid = false; 16 | if (strpos($path, trim(ABSPATH, '/\\')) === false) { 17 | $this->_message = __('Folder Path Must be within WordPress root directory', 'file-manager'); 18 | } elseif (!is_readable($path)) { 19 | $this->_message = __('Please provide a readable folder path', 'file-manager'); 20 | } else { 21 | $isValid = true; 22 | } 23 | 24 | return $isValid; 25 | } 26 | 27 | public function message() 28 | { 29 | return $this->_message; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /backend/app/Http/Rules/ValidUIOptionRule.php: -------------------------------------------------------------------------------- 1 | permissions()->allCommands(); 13 | 14 | if (!\is_array($value)) { 15 | return false; 16 | } 17 | 18 | $visited = []; 19 | foreach ($commands as $command) { 20 | $visited[$command] = 1; 21 | } 22 | 23 | foreach ($value as $key => $command) { 24 | if (!isset($visited[$command])) { 25 | return false; 26 | } 27 | } 28 | 29 | return true; 30 | } 31 | 32 | public function message() 33 | { 34 | return __('Folder Path Must be within WordPress root directory', 'file-manager'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /backend/app/Http/Rules/ValidateLangRule.php: -------------------------------------------------------------------------------- 1 | preferences()->availableLanguages(); 13 | 14 | return isset($languages[$value]) ? true : false; 15 | } 16 | 17 | public function message() 18 | { 19 | return __('Language code is not valid', 'file-manager'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /backend/app/Http/Rules/ValidateRolesRule.php: -------------------------------------------------------------------------------- 1 | permissions()->allRoles(); 13 | 14 | if (!\is_array($value)) { 15 | return false; 16 | } 17 | 18 | $visited = []; 19 | foreach ($roles as $role) { 20 | $visited[$role] = 1; 21 | } 22 | 23 | foreach ($value as $roleId => $permissions) { 24 | if (!isset($visited[$roleId])) { 25 | return false; 26 | } 27 | } 28 | 29 | return true; 30 | } 31 | 32 | public function message() 33 | { 34 | return __('Folder Path Must be within WordPress root directory', 'file-manager'); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /backend/app/Http/Rules/ValidateThemeRule.php: -------------------------------------------------------------------------------- 1 | preferences()->themes(); 13 | $themes['default'] = 'default'; 14 | 15 | return isset($themes[$value]) ? true : false; 16 | } 17 | 18 | public function message() 19 | { 20 | return __('Theme variant is not valid', 'file-manager'); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /backend/app/Http/Rules/ValidateUsersRule.php: -------------------------------------------------------------------------------- 1 | permissions()->mappedUsers(array_keys($value)); 13 | 14 | if (!\is_array($value)) { 15 | return false; 16 | } 17 | 18 | foreach ($value as $usrId => $permissions) { 19 | if (!isset($users[$usrId])) { 20 | return false; 21 | } 22 | } 23 | 24 | return true; 25 | } 26 | 27 | public function message() 28 | { 29 | return __('User is not valid', 'file-manager'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /backend/app/Model/Log.php: -------------------------------------------------------------------------------- 1 | 'object']; 23 | 24 | protected $fillable = [ 25 | 'user_id', 26 | 'command', 27 | 'details', 28 | 'created_at', 29 | ]; 30 | 31 | public function user() { 32 | return $this->hasOne(User::class, 'ID', 'user_id'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /backend/app/Model/User.php: -------------------------------------------------------------------------------- 1 | _finderOptions = $finderOptions; 23 | } 24 | 25 | public function getFinder() 26 | { 27 | $finder = new elFinder($this->_finderOptions->getOptions()); 28 | 29 | return new FinderConnector($finder); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /backend/app/Providers/MimeProvider.php: -------------------------------------------------------------------------------- 1 | _mimePath = $mimePath; 14 | } else { 15 | $this->_mimePath = BFM_FINDER_DIR . 'php' . DIRECTORY_SEPARATOR . 'mime.types'; 16 | } 17 | } 18 | 19 | public function getTypes() 20 | { 21 | $mimeList = []; 22 | $fp = fopen($this->_mimePath, 'r'); 23 | if ($fp) { 24 | while (($line = fgets($fp)) !== false) { 25 | if (strpos($line, '#') === 0) { 26 | continue; 27 | } 28 | 29 | $singleMime = explode('/', $line); 30 | $mimeType = trim($singleMime[0]); 31 | if (!\in_array($mimeType, $mimeList)) { 32 | $mimeList[] = $mimeType; 33 | } 34 | } 35 | } 36 | 37 | return $mimeList; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /backend/bootstrap.php: -------------------------------------------------------------------------------- 1 | create( 18 | 'logs', 19 | function (Blueprint $table) { 20 | $table->id(); 21 | $table->int('user_id', 11); 22 | $table->string('command')->length(32); 23 | $table->longtext('details'); 24 | $table->datetime('created_at'); 25 | } 26 | ); 27 | } 28 | 29 | public function down() 30 | { 31 | Schema::drop('logs'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /backend/db/Migrations/BFMPluginOptions.php: -------------------------------------------------------------------------------- 1 | middleware('nonce:admin'); 12 | 13 | Route::noAuth() 14 | ->match(['get', 'post'], 'connector_front', [FileManagerController::class, 'connector']) 15 | ->middleware('nonce:public'); 16 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bitapps/file-manager", 3 | "description": "A file management plugin for wordpress", 4 | "license": "gpl-2", 5 | "autoload": { 6 | "psr-4": { 7 | "BitApps\\FM\\": "./backend/app" 8 | } 9 | }, 10 | "scripts": { 11 | "lint": "./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php", 12 | "unused:variable": "phpcs -p --standard=VariableAnalysis backend", 13 | "compat": "./vendor/bin/phpcs -p ./backend --standard=PHPCompatibilityWP --runtime-set testVersion 5.6-" 14 | }, 15 | "require-dev": { 16 | "friendsofphp/php-cs-fixer": "^3.10", 17 | "sirbrillig/phpcs-variable-analysis": "*", 18 | "dealerdirect/phpcodesniffer-composer-installer": "^0.7", 19 | "phpcompatibility/phpcompatibility-wp": "*" 20 | }, 21 | "config": { 22 | "allow-plugins": { 23 | "dealerdirect/phpcodesniffer-composer-installer": true, 24 | "typisttech/imposter-plugin": true 25 | } 26 | }, 27 | "require": { 28 | "bitapps/wp-validator": "^1.1.0", 29 | "bitapps/wp-kit": "^1.7", 30 | "bitapps/wp-database": "^1.6", 31 | "bitapps/wp-telemetry": "^0.0.9", 32 | "typisttech/imposter-plugin": "^0.6.2" 33 | }, 34 | "extra": { 35 | "imposter": { 36 | "namespace": "BitApps\\FM\\Vendor\\" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /file-manager.php: -------------------------------------------------------------------------------- 1 | ({} as FinderInstance) 7 | export const $finderCurrentPath = atom([]) 8 | export const $finderViewType = atom('icons') 9 | 10 | export default $finder 11 | -------------------------------------------------------------------------------- /frontend/src/common/globalStates/$navigate.ts: -------------------------------------------------------------------------------- 1 | import { atom } from 'jotai' 2 | 3 | const $navigate = atom('') 4 | export default $navigate 5 | -------------------------------------------------------------------------------- /frontend/src/common/globalStates/GlobalStates.d.ts: -------------------------------------------------------------------------------- 1 | export interface BreadcrumbItemType { 2 | key?: React.Key 3 | /** 4 | * Different with `path`. Directly set the link of this item. 5 | */ 6 | href?: string 7 | /** 8 | * Different with `href`. It will concat all prev `path` to the current one. 9 | */ 10 | path?: string 11 | title?: React.ReactNode 12 | breadcrumbName?: string 13 | menu?: BreadcrumbItemProps['menu'] 14 | /** @deprecated Please use `menu` instead */ 15 | overlay?: React.ReactNode 16 | className?: string 17 | dropdownProps?: DropdownProps 18 | onClick?: React.MouseEventHandler 19 | /** @deprecated Please use `menu` instead */ 20 | children?: Omit[] 21 | } 22 | export interface BreadcrumbSeparatorType { 23 | type: 'separator' 24 | separator?: React.ReactNode 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/common/globalStates/index.ts: -------------------------------------------------------------------------------- 1 | import $appConfig from '@common/globalStates/$appConfig' 2 | 3 | export { $appConfig } 4 | -------------------------------------------------------------------------------- /frontend/src/common/helpers/atomWithBroadcast.ts: -------------------------------------------------------------------------------- 1 | import { atom } from 'jotai' 2 | 3 | export default function atomWithBroadcast(key: string, initialValue: T) { 4 | const baseAtom = atom(initialValue) 5 | const listeners = new Set<(event: MessageEvent) => void>() // eslint-disable-line @typescript-eslint/no-explicit-any 6 | const channel = new BroadcastChannel(key) 7 | channel.onmessage = event => { 8 | listeners.forEach(l => l(event)) 9 | } 10 | 11 | const broadcastAtom = atom T) }], void>( 12 | get => get(baseAtom), 13 | (get, set, update) => { 14 | set(baseAtom, update.value) 15 | 16 | if (!update.isEvent) { 17 | channel.postMessage(get(baseAtom)) 18 | } 19 | } 20 | ) 21 | 22 | broadcastAtom.onMount = setAtom => { 23 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 24 | const listener = (event: MessageEvent) => { 25 | setAtom({ isEvent: true, value: event.data }) 26 | } 27 | listeners.add(listener) 28 | return () => { 29 | listeners.delete(listener) 30 | } 31 | } 32 | 33 | const returnedAtom = atom T)], void>( 34 | get => get(broadcastAtom), 35 | (_get, set, update) => { 36 | set(broadcastAtom, { isEvent: false, value: update }) 37 | } 38 | ) 39 | 40 | return returnedAtom 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/common/helpers/generateData.ts: -------------------------------------------------------------------------------- 1 | export default function generateFlowsData(totalFlows: number) { 2 | const createFlows = [] 3 | 4 | for (let i = 1; i <= totalFlows; i += 1) { 5 | if (i % 5 === 0) { 6 | createFlows.push({ 7 | id: i, 8 | icon: 'icon link', 9 | title: `Group Title ${i}`, 10 | subtitle: 'Group', 11 | type: 'flow-group', 12 | flows: [ 13 | { 14 | id: '1', 15 | icon: 'icon link', 16 | title: 'Flow group Title 1', 17 | count: 20, 18 | type: 'flow' 19 | }, 20 | { 21 | id: '2', 22 | icon: 'icon link', 23 | title: 'Flow group Title 2', 24 | count: 20, 25 | type: 'flow' 26 | }, 27 | { 28 | id: '3', 29 | icon: 'icon link', 30 | title: 'Flow group Title 3', 31 | count: 20, 32 | type: 'flow' 33 | } 34 | ] 35 | }) 36 | } else { 37 | createFlows.push({ 38 | id: i, 39 | icon: 'icon link', 40 | title: `Flow Title ${i}`, 41 | count: 20, 42 | type: 'flow' 43 | }) 44 | } 45 | } 46 | return JSON.stringify(createFlows) 47 | } 48 | -------------------------------------------------------------------------------- /frontend/src/common/helpers/i18nwrap.ts: -------------------------------------------------------------------------------- 1 | import { getServerVariable } from '@config/config' 2 | 3 | // eslint-disable-next-line no-underscore-dangle 4 | const __ = (text: string) => { 5 | const translations = getServerVariable('translations', {}) 6 | if (text in translations) { 7 | return translations[text] 8 | } 9 | return text 10 | } 11 | 12 | const sprintf = (text: string, ...vars: any) => { 13 | const matches: RegExpMatchArray | null = text.match(/%[s d u c o x X bg G e E f F]/g) 14 | if (!matches) { 15 | return text 16 | } 17 | let str = text 18 | vars.map((val: string, idx: number) => { 19 | str = str.replace(matches[idx], val) 20 | }) 21 | return str 22 | } 23 | 24 | export { __, sprintf } 25 | -------------------------------------------------------------------------------- /frontend/src/common/hooks/useCopyToClipboard.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | 3 | export default function useCopyToClipboard() { 4 | const [copied, setCopied] = useState(false) 5 | 6 | const setCopiedAndReset = () => { 7 | setCopied(true) 8 | 9 | setTimeout(() => { 10 | setCopied(false) 11 | }, 2500) 12 | } 13 | 14 | const copy = (text: string) => { 15 | if (window.isSecureContext && navigator.clipboard) { 16 | navigator.clipboard.writeText(text) 17 | setCopiedAndReset() 18 | return 19 | } 20 | 21 | const textArea = document.createElement('textarea') 22 | textArea.value = text 23 | document.body.appendChild(textArea) 24 | textArea.focus() 25 | textArea.select() 26 | try { 27 | document.execCommand('copy') 28 | setCopiedAndReset() 29 | } catch (err) { 30 | console.error('Unable to copy to clipboard', err) 31 | } 32 | document.body.removeChild(textArea) 33 | } 34 | 35 | return { copied, copy } 36 | } 37 | -------------------------------------------------------------------------------- /frontend/src/common/hooks/useDebounce.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | 3 | function useDebounce(value: T, delay?: number): T { 4 | const [debouncedValue, setDebouncedValue] = useState(value) 5 | 6 | useEffect(() => { 7 | const timer = setTimeout(() => setDebouncedValue(value), delay || 500) 8 | 9 | return () => { 10 | clearTimeout(timer) 11 | } 12 | }, [value, delay]) 13 | 14 | return debouncedValue 15 | } 16 | 17 | export default useDebounce 18 | -------------------------------------------------------------------------------- /frontend/src/common/hooks/useInterval.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from 'react' 2 | 3 | type UseIntervalType = [boolean, () => void, () => void] 4 | 5 | export default function useInterval( 6 | callback: () => void, 7 | delay: number | null, 8 | immediate = false 9 | ): UseIntervalType { 10 | const [timer, setTimer] = useState(immediate ? delay : null) 11 | const intervalRef = useRef() 12 | const savedCallback = useRef(callback) 13 | const isRunning = timer !== null 14 | 15 | useEffect(() => { 16 | savedCallback.current = callback 17 | }, [callback]) 18 | 19 | useEffect(() => { 20 | if (typeof timer === 'number') { 21 | intervalRef.current = setInterval(savedCallback.current, timer) 22 | } 23 | return () => intervalRef.current && clearInterval(intervalRef.current) 24 | }, [timer]) 25 | 26 | const startInterval = () => setTimer(delay) 27 | const stopInterval = () => setTimer(null) 28 | 29 | return [isRunning, startInterval, stopInterval] 30 | } 31 | -------------------------------------------------------------------------------- /frontend/src/common/hooks/useIsomorphicLayoutEffect.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useLayoutEffect } from 'react' 2 | 3 | const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect 4 | 5 | export default useIsomorphicLayoutEffect 6 | -------------------------------------------------------------------------------- /frontend/src/common/hooks/useOnClickOutside.tsx: -------------------------------------------------------------------------------- 1 | import { type RefObject } from 'react' 2 | 3 | import useEventListener from './useEventListener' 4 | 5 | type Handler = (event: MouseEvent) => void 6 | 7 | function useOnClickOutside( 8 | ref: RefObject, 9 | handler: Handler, 10 | mouseEvent: 'mousedown' | 'mouseup' = 'mousedown' 11 | ): void { 12 | useEventListener(mouseEvent, event => { 13 | const el = ref?.current 14 | 15 | // Do nothing if clicking ref's element or descendent elements 16 | if (!el || el.contains(event.target as Node)) { 17 | return 18 | } 19 | 20 | handler(event) 21 | }) 22 | } 23 | export default useOnClickOutside 24 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/AnimateHeight/AnimateHeight.tsx: -------------------------------------------------------------------------------- 1 | import { motion } from 'framer-motion' 2 | 3 | type AnimateHeightPropsType = { 4 | children: React.ReactNode 5 | className?: string 6 | style?: React.CSSProperties 7 | } 8 | 9 | export default function AnimateHeight({ children, className, style }: AnimateHeightPropsType) { 10 | return ( 11 | 21 | {children} 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/AnimateHeight/index.ts: -------------------------------------------------------------------------------- 1 | import AnimateHeight from './AnimateHeight' 2 | 3 | export default AnimateHeight 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/ConfirmationModal/ConfirmationModal.stories.mdx: -------------------------------------------------------------------------------- 1 | import { ArgsTable, Meta, Source, Story } from '@storybook/addon-docs' 2 | 3 | import ConfirmationModal from './ConfirmationModal' 4 | import ConfirmationModalStory from './ConfirmationModalStory.tsx' 5 | 6 | 7 | 8 | export const Template = args => 9 | 10 | # ConfirmationModal 11 | 12 | --- 13 | 14 | {}, 20 | confirmDelete: () => {} 21 | }} 22 | > 23 | 24 | 25 | 31 | 32 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/ConfirmationModal/ConfirmationModal.stories.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/jsx-props-no-spreading */ 2 | 3 | /* eslint-disable import/no-extraneous-dependencies */ 4 | import { useState } from 'react' 5 | 6 | import { type Meta, type StoryFn } from '@storybook/react' 7 | import { Button } from 'antd' 8 | 9 | import ConfirmationModal from './ConfirmationModal' 10 | 11 | // eslint-disable-next-line react/function-component-definition 12 | const Template: StoryFn = () => { 13 | const [modalOpen, setModalOpen] = useState(false) 14 | return ( 15 | <> 16 | 17 | setModalOpen(false)} 21 | confirmDelete={() => setModalOpen(false)} 22 | /> 23 | 24 | ) 25 | } 26 | 27 | const Canvas = Template.bind({}) 28 | 29 | Canvas.args = { 30 | open: true 31 | } 32 | 33 | export { Canvas } 34 | 35 | export default { 36 | title: 'Component/ConfirmationModal', 37 | component: ConfirmationModal 38 | } as Meta 39 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/ConfirmationModal/ConfirmationModalStory.tsx: -------------------------------------------------------------------------------- 1 | import { Button } from 'antd' 2 | 3 | import ConfirmationModal, { type ConfirmationModalTypes } from './ConfirmationModal' 4 | 5 | export default function ConfirmationModalStory({ 6 | open, 7 | layoutId, 8 | closeModal, 9 | confirmDelete 10 | }: ConfirmationModalTypes) { 11 | return ( 12 | <> 13 | 14 | closeModal()} 18 | confirmDelete={() => confirmDelete()} 19 | /> 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/ConfirmationModal/index.tsx: -------------------------------------------------------------------------------- 1 | import ConfirmationModal from './ConfirmationModal' 2 | 3 | export default ConfirmationModal 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/DotLoader/DotLoader.module.scss: -------------------------------------------------------------------------------- 1 | .loadingDots { 2 | display: flex; 3 | } 4 | 5 | .dot { 6 | display: inline-block; 7 | border-radius: 0.625rem; 8 | height: 5px; 9 | width: 5px; 10 | margin-left: 4px; 11 | 12 | :global { 13 | animation: dot-keyframes 1.5s infinite ease-in-out; 14 | } 15 | } 16 | 17 | .dot:nth-child(2) { 18 | animation-delay: 0.4s; 19 | } 20 | 21 | .dot:nth-child(3) { 22 | animation-delay: 0.8s; 23 | } 24 | 25 | /* stylelint-disable-next-line csstree/validator, keyframes-name-pattern, scss/at-rule-no-unknown */ 26 | @keyframes:global (dot-keyframes) { 27 | 0% { 28 | opacity: 0.4; 29 | transform: scale(0.7); 30 | } 31 | 32 | 50% { 33 | opacity: 1; 34 | transform: scale(1.2); 35 | } 36 | 37 | 100% { 38 | opacity: 0.4; 39 | transform: scale(0.7); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/DotLoader/DotLoader.tsx: -------------------------------------------------------------------------------- 1 | import ut from '@resource/utilsCssInJs' 2 | 3 | import css from './DotLoader.module.scss' 4 | 5 | export default function DotLoader() { 6 | return ( 7 |
8 | 9 | 10 | 11 |
12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/DotLoader/index.tsx: -------------------------------------------------------------------------------- 1 | import DotLoader from './DotLoader' 2 | 3 | export default DotLoader 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/DropDown/DropDown.module.css: -------------------------------------------------------------------------------- 1 | .dropDownBtn { 2 | composes: flx ai-cen pointer m-0 p-0 from global; 3 | background: none; 4 | border: none; 5 | padding: 0.1875rem; 6 | transition: 0.5s all ease; 7 | border-radius: 50%; 8 | outline: none; 9 | } 10 | 11 | .dropDownBtn:hover { 12 | background-color: var(--bg-10); 13 | } 14 | 15 | .dropDownBtn:focus-within { 16 | box-shadow: var(--focus-shadow); 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/DropDown/DropDown.stories.mdx: -------------------------------------------------------------------------------- 1 | import DeleteIcon from '@icons/DeleteIcon' 2 | import DotsVertical from '@icons/DotsVertical' 3 | import { ArgsTable, Canvas, Meta, Source, Story } from '@storybook/addon-docs' 4 | 5 | import cls from '../../features/FlowItem/FlowItem.module.css' 6 | import DropDown from './DropDown' 7 | 8 | 9 | 10 | # DropDown 11 | 12 | --- 13 | 14 | **btnClassName?**: `Css Class` 15 | 16 | **Children**: `Html Element` 17 | 18 | ` ` 19 | 20 | 21 | 22 | 23 |
24 | 28 |
29 |
30 |
31 | 37 | 38 |
39 | 43 |
44 |
`} 45 | /> 46 | 47 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/DropDown/DropDown.stories.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/jsx-props-no-spreading */ 2 | 3 | /* eslint-disable import/no-extraneous-dependencies */ 4 | import cls from '@features/FlowItem/FlowItem.module.css' 5 | import DeleteIcon from '@icons/DeleteIcon' 6 | import DotsVertical from '@icons/DotsVertical' 7 | import { type Meta, type StoryFn } from '@storybook/react' 8 | 9 | import DropDown from './DropDown' 10 | 11 | export default { 12 | title: 'Component/DropDown', 13 | component: DropDown 14 | } as Meta 15 | 16 | // eslint-disable-next-line react/function-component-definition 17 | const Template: StoryFn = () => ( 18 | 19 | 20 |
21 | 25 |
26 |
27 | ) 28 | 29 | export const Canvas = Template.bind({}) 30 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/DropDown/index.tsx: -------------------------------------------------------------------------------- 1 | import DropDown from './DropDown' 2 | 3 | export default DropDown 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/DropDown/static/TippyLightTheme.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable */ 2 | .tippy-box[data-theme~='light'] { 3 | color: #26323d; 4 | box-shadow: 5 | 0 2.4041px 1.356px 0 hsla(0deg, 0%, 0%, 3%), 6 | 0 4.6704px 3.2585px 0 hsla(0deg, 0%, 0%, 5%), 7 | 0 6.7969px 6.1356px 0 hsla(0deg, 0%, 0%, 6%), 8 | 0 8.8363px 10.9448px 0 hsla(0deg, 0%, 0%, 7%), 9 | 0 11.2514px 20.471px 0 hsla(0deg, 0%, 0%, 9%), 10 | 0 24px 49px 0 hsla(0deg, 0%, 0%, 12%); 11 | background-color: var(--bg-90); 12 | border: 1px solid hsla(0deg, 0%, 93%, 100%); 13 | } 14 | 15 | .tippy-box[data-theme~='light'][data-placement^='top'] > .tippy-arrow::before { 16 | border-top-color: var(--bg-90); 17 | } 18 | 19 | .tippy-box[data-theme~='light'][data-placement^='bottom'] > .tippy-arrow::before { 20 | border-bottom-color: var(--bg-90); 21 | } 22 | 23 | .tippy-box[data-theme~='light'][data-placement^='left'] > .tippy-arrow::before { 24 | border-left-color: var(--bg-90); 25 | } 26 | 27 | .tippy-box[data-theme~='light'][data-placement^='right'] > .tippy-arrow::before { 28 | border-right-color: var(--bg-90); 29 | } 30 | 31 | .tippy-box[data-theme~='light'] > .tippy-backdrop { 32 | background-color: var(--bg-90); 33 | } 34 | 35 | .tippy-box[data-theme~='light'] > .tippy-svg-arrow { 36 | fill: var(--bg); 37 | } 38 | 39 | .tippy-box { 40 | border-radius: calc(var(--border-rad) - 2px); 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Fade/Fade.tsx: -------------------------------------------------------------------------------- 1 | import { AnimatePresence, motion } from 'framer-motion' 2 | 3 | interface PropsTypes { 4 | is: boolean 5 | children: JSX.Element | string 6 | duration?: number | undefined 7 | initialDelay?: number | undefined 8 | } 9 | 10 | export default function Fade({ is, children, duration = 0.3, initialDelay = 0 }: PropsTypes) { 11 | const variants = { 12 | hidden: { 13 | opacity: 0 14 | }, 15 | visible: { 16 | opacity: 1, 17 | transition: { 18 | delay: initialDelay 19 | } 20 | }, 21 | exit: { opacity: 0, transition: { duration } } 22 | } 23 | 24 | return ( 25 | 26 | {is && ( 27 | 36 | {children} 37 | 38 | )} 39 | 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Fade/index.tsx: -------------------------------------------------------------------------------- 1 | import Fade from './Fade' 2 | 3 | export default Fade 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/IconBtn/IconBtn.tsx: -------------------------------------------------------------------------------- 1 | import { type ComponentPropsWithRef } from 'react' 2 | import { forwardRef } from 'react' 3 | 4 | import cls from './IconBtn.module.css' 5 | 6 | export interface IconBtnPropsType extends ComponentPropsWithRef<'button'> { 7 | variant?: 'solid' | 'outline' | 'ghost' 8 | color?: 'default' | 'primary' 9 | type?: 'button' | 'submit' | 'reset' 10 | size?: 'xs' | 'sm' | 'md' | 'lg' 11 | round?: boolean 12 | } 13 | 14 | const IconBtn = forwardRef( 15 | ( 16 | { 17 | variant = 'solid', 18 | color = 'default', 19 | type = 'button', 20 | className, 21 | size = 'md', 22 | round = false, 23 | ...props 24 | }: IconBtnPropsType, 25 | ref 26 | ) => ( 27 | 34 | Copy Url 35 | 36 | 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/InputGroup/index.tsx: -------------------------------------------------------------------------------- 1 | import InputGroup from './InputGroup' 2 | 3 | export default InputGroup 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Popover/Popover.tsx: -------------------------------------------------------------------------------- 1 | import { type ReactElement } from 'react' 2 | 3 | import Tippy from '@tippyjs/react' 4 | import { roundArrow } from 'tippy.js' 5 | import 'tippy.js/animations/shift-away.css' 6 | import 'tippy.js/dist/svg-arrow.css' 7 | 8 | // import 'tippy.js/dist/tippy.css' 9 | // import './static/TippyLightTheme.css' 10 | 11 | interface PopoverPropsTypes { 12 | children: [ReactElement, ReactElement] 13 | isOpen: boolean 14 | // setIsOpen?: Dispatch> 15 | placement?: 'right' | 'left' | 'bottom' | 'top' 16 | onClickOutside?: () => void 17 | } 18 | 19 | export default function Popover({ 20 | children, 21 | isOpen, 22 | placement = 'right', 23 | onClickOutside 24 | }: PopoverPropsTypes): JSX.Element { 25 | return ( 26 | ({ 37 | backgroundColor: token.colorBgElevated, 38 | borderRadius: token.borderRadius + 1, 39 | boxShadow: token.boxShadowSecondary, 40 | '& .tippy-svg-arrow': { 41 | fill: token.colorBgContainer, 42 | stroke: token.controlOutline 43 | } 44 | })} 45 | appendTo="parent" 46 | onClickOutside={onClickOutside} 47 | > 48 |
{children[0]}
49 |
50 | ) 51 | } 52 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Popover/PopoverContent.tsx: -------------------------------------------------------------------------------- 1 | import { type CSSProperties, type ReactNode } from 'react' 2 | 3 | interface PopoverContentPropsType { 4 | children: ReactNode | ReactNode[] 5 | className?: string | undefined 6 | style?: CSSProperties | undefined 7 | } 8 | 9 | export default function PopoverContent({ children, className, style }: PopoverContentPropsType) { 10 | return ( 11 |
12 | {children} 13 |
14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Popover/PopoverHeader.tsx: -------------------------------------------------------------------------------- 1 | import CloseIcn from '@icons/CloseIcn' 2 | import { Button, Row, Typography } from 'antd' 3 | 4 | interface PopoverHeaderType { 5 | title: string 6 | onClose: () => void 7 | infoLink?: string 8 | } 9 | 10 | export default function PopoverHeader({ title, infoLink, onClose }: PopoverHeaderType) { 11 | return ( 12 | 13 | {title} 14 |
15 | {infoLink &&
18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Popover/PopoverTrigger.tsx: -------------------------------------------------------------------------------- 1 | import { type ReactElement } from 'react' 2 | import { Children } from 'react' 3 | 4 | interface PopoverTriggerPropsType { 5 | children: JSX.Element 6 | } 7 | 8 | export default function PopoverTrigger({ children }: PopoverTriggerPropsType): ReactElement { 9 | const singleChildren = Children.only(children) 10 | return singleChildren 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Popover/index.tsx: -------------------------------------------------------------------------------- 1 | import Popover from './Popover' 2 | 3 | export default Popover 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Popover/static/TippyLightTheme.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable */ 2 | .tippy-box[data-theme~='light'] { 3 | color: #26323d; 4 | box-shadow: 5 | 0 2.4041px 1.356px 0 hsla(0deg, 0%, 0%, 3%), 6 | 0 4.6704px 3.2585px 0 hsla(0deg, 0%, 0%, 5%), 7 | 0 6.7969px 6.1356px 0 hsla(0deg, 0%, 0%, 6%), 8 | 0 8.8363px 10.9448px 0 hsla(0deg, 0%, 0%, 7%), 9 | 0 11.2514px 20.471px 0 hsla(0deg, 0%, 0%, 9%), 10 | 0 24px 49px 0 hsla(0deg, 0%, 0%, 12%); 11 | background-color: var(--bg-90); 12 | border: 1px solid hsla(0deg, 0%, 93%, 100%); 13 | } 14 | 15 | .tippy-box[data-theme~='light'][data-placement^='top'] > .tippy-arrow::before { 16 | border-top-color: var(--bg-90); 17 | } 18 | 19 | .tippy-box[data-theme~='light'][data-placement^='bottom'] > .tippy-arrow::before { 20 | border-bottom-color: var(--bg-90); 21 | } 22 | 23 | .tippy-box[data-theme~='light'][data-placement^='left'] > .tippy-arrow::before { 24 | border-left-color: var(--bg-90); 25 | } 26 | 27 | .tippy-box[data-theme~='light'][data-placement^='right'] > .tippy-arrow::before { 28 | border-right-color: var(--bg-90); 29 | } 30 | 31 | .tippy-box[data-theme~='light'] > .tippy-backdrop { 32 | background-color: var(--bg-90); 33 | } 34 | 35 | .tippy-box[data-theme~='light'] > .tippy-svg-arrow { 36 | fill: var(--bg); 37 | } 38 | 39 | .tippy-box { 40 | border-radius: calc(var(--border-rad) - 2px); 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Segment/SegmentLabel.tsx: -------------------------------------------------------------------------------- 1 | export default function SegmentLabel() { 2 | return
SegmentLabel
3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Segment/SegmentTab.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/no-unused-prop-types */ 2 | import { type ReactNode } from 'react' 3 | 4 | import cls from './Segment.module.css' 5 | 6 | export interface SegmentTabPropType { 7 | children: ReactNode | ReactNode[] 8 | style?: React.CSSProperties | undefined 9 | value: string | number 10 | tip?: string | ReactNode 11 | disabled?: boolean 12 | } 13 | 14 | export default function SegmentTab({ children, style = undefined }: SegmentTabPropType) { 15 | return ( 16 |
17 | {children} 18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Segment/SegmentTip.tsx: -------------------------------------------------------------------------------- 1 | import { type ReactElement, type ReactNode } from 'react' 2 | 3 | import Tippy from '@tippyjs/react' 4 | import { type Placement } from 'tippy.js' 5 | import 'tippy.js/animations/shift-away.css' 6 | import 'tippy.js/dist/tippy.css' 7 | 8 | interface SegmentTipType { 9 | children: ReactElement 10 | content: ReactNode | string 11 | placement: Placement 12 | } 13 | export default function SegmentTip({ children, content, placement }: SegmentTipType) { 14 | if (content) { 15 | return ( 16 | 24 | {children} 25 | 26 | ) 27 | } 28 | return children 29 | } 30 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Segment/index.tsx: -------------------------------------------------------------------------------- 1 | import Segment from './Segment' 2 | 3 | export default Segment 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Select/index.ts: -------------------------------------------------------------------------------- 1 | import Select from './Select' 2 | 3 | export default Select 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/SpinnerLoader/SpinnerLoader.module.css: -------------------------------------------------------------------------------- 1 | .loading { 2 | display: inline-block; 3 | border-style: solid; 4 | border-radius: 50%; 5 | border-top-color: hsla(0deg, 0%, 100%, 0%); 6 | } 7 | 8 | .primary { 9 | border-color: var(--accent-light); 10 | } 11 | 12 | .loading :global { 13 | animation: spin 1s linear infinite; 14 | } 15 | 16 | /* stylelint-disable-next-line keyframes-name-pattern, csstree/validator */ 17 | @keyframes :global(spin) { 18 | to { 19 | transform: rotate(360deg); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/SpinnerLoader/SpinnerLoader.module.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["SpinnerLoader.module.scss","SpinnerLoader.module.css"],"names":[],"mappings":"AAAA;EACE,qBAAA;EACA,mBAAA;EACA,iCAAA;EACA,kBAAA;EACA,yCAAA;ACCF;ADCE;EACE,0CAAA;UAAA,kCAAA;ACCJ;;ADGA;EACE;IACE,yBAAA;ECAF;AACF;;ADHA;EACE;IACE,yBAAA;ECAF;AACF","file":"SpinnerLoader.module.css"} -------------------------------------------------------------------------------- /frontend/src/components/utilities/SpinnerLoader/SpinnerLoader.module.scss: -------------------------------------------------------------------------------- 1 | .loading { 2 | display: inline-block; 3 | border-style: solid; 4 | border-radius: 50%; 5 | border-top-color: hsla(0deg, 0%, 100%, 0%); 6 | 7 | :global { 8 | animation: spin 1s linear infinite; 9 | } 10 | } 11 | 12 | .primary { 13 | border-color: var(--accent-light); 14 | } 15 | 16 | /* stylelint-disable-next-line csstree/validator, keyframes-name-pattern, scss/at-rule-no-unknown */ 17 | @keyframes:global (spin) { 18 | to { 19 | transform: rotate(360deg); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/SpinnerLoader/SpinnerLoader.test.tsx: -------------------------------------------------------------------------------- 1 | import { cleanup, render, screen } from '@testing-library/react' 2 | import { afterEach, describe, expect, it } from 'vitest' 3 | 4 | import SpinnerLoader from './SpinnerLoader' 5 | 6 | describe('test SpinnerLoader component', () => { 7 | afterEach(cleanup) 8 | it('should render with text, and default classes but no others', () => { 9 | render() 10 | const slElm = screen.getByTestId('spinnerLoader') 11 | expect(slElm).toBeTruthy() 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/SpinnerLoader/SpinnerLoader.tsx: -------------------------------------------------------------------------------- 1 | import css from './SpinnerLoader.module.scss' 2 | 3 | interface SpinnerLoaderType { 4 | size: number 5 | stroke?: number 6 | className?: string 7 | color?: 'light' | 'primary' 8 | } 9 | 10 | export default function SpinnerLoader({ 11 | size, 12 | stroke = 3, 13 | className = undefined, 14 | color = 'light' 15 | }: SpinnerLoaderType) { 16 | return ( 17 |
18 |
22 |
23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/SpinnerLoader/index.ts: -------------------------------------------------------------------------------- 1 | import SpinnerLoader from './SpinnerLoader' 2 | 3 | export default SpinnerLoader 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Tabs/TabPanel.tsx: -------------------------------------------------------------------------------- 1 | import { type ComponentPropsWithoutRef, type ReactElement, type ReactNode } from 'react' 2 | 3 | interface TabPanelType extends ComponentPropsWithoutRef<'div'> { 4 | children: ReactNode | ReactElement 5 | value?: string 6 | panelRef?: undefined 7 | } 8 | 9 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 10 | function TabPanel({ children, panelRef = undefined, ...restProps }: TabPanelType) { 11 | return ( 12 | // eslint-disable-next-line react/jsx-props-no-spreading 13 |
14 | {children} 15 |
16 | ) 17 | } 18 | export default TabPanel 19 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Tabs/index.tsx: -------------------------------------------------------------------------------- 1 | import TabPanel from './TabPanel' 2 | import Tabs from './Tabs' 3 | 4 | export { TabPanel } 5 | export default Tabs 6 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/TagFilter/TagFilter.module.css: -------------------------------------------------------------------------------- 1 | .tagsSection { 2 | composes: mt-2 mb-4 flx flx-wrap gap-1 from global; 3 | } 4 | 5 | .tagList { 6 | max-height: 210px; 7 | overflow-y: auto; 8 | } 9 | 10 | .tagList > li { 11 | margin-bottom: 2px !important; 12 | padding: 0 !important; 13 | } 14 | 15 | .tagItem { 16 | composes: flx ai-cen jc-sb pos-rel from global; 17 | width: 140px; 18 | } 19 | 20 | .tagItem:hover { 21 | opacity: 1; 22 | } 23 | 24 | .tagItemActionBtn { 25 | opacity: 0; 26 | } 27 | 28 | .tagItem:hover .tagItemActionBtn { 29 | opacity: 1; 30 | } 31 | 32 | .pinTag { 33 | opacity: 1; 34 | } 35 | 36 | .tagItemAction { 37 | composes: pos-abs from global; 38 | right: 2px; 39 | } 40 | 41 | .tagItemTitle { 42 | text-overflow: ellipsis; 43 | max-width: 135px; 44 | overflow: hidden; 45 | white-space: nowrap; 46 | } 47 | 48 | .tagItem:hover .tagItemTitle { 49 | max-width: 95px; 50 | } 51 | 52 | .tagList::-webkit-scrollbar-thumb { 53 | border-radius: 100px; 54 | transition: 0.3s all ease; 55 | } 56 | 57 | .tagList::-webkit-scrollbar { 58 | width: 3px; 59 | opacity: 0; 60 | } 61 | 62 | .tagList:hover::-webkit-scrollbar-thumb { 63 | background-color: var(--bg-15); 64 | } 65 | 66 | .tagList:hover::-webkit-scrollbar-track { 67 | background: var(--bg-5); 68 | } 69 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/TagFilter/TagFilterType.d.ts: -------------------------------------------------------------------------------- 1 | type TagList = { 2 | id: number 3 | label: string 4 | pinned: boolean 5 | active: boolean 6 | filter?: JSON 7 | } 8 | 9 | type TagsListType = { 10 | tagsList: TagList[] 11 | onAdd?: () => void 12 | onEdit?: (tagId: number) => void 13 | onRemove?: (tagId: number) => void 14 | onPin?: (tagId: number) => void 15 | onUnpin?: (tagId: number) => void 16 | onActive: (tagId: number) => void 17 | onInactive: (tagId: number) => void 18 | onFilter?: (tagId: number) => void 19 | className?: string 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/TagFilter/index.tsx: -------------------------------------------------------------------------------- 1 | import TagFilter from './TagFilter' 2 | 3 | export default TagFilter 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/TelemetryPopup/Index.ts: -------------------------------------------------------------------------------- 1 | import TelemetryPopup from './TelemetryPopup' 2 | 3 | export default TelemetryPopup 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Tip/Tip.tsx: -------------------------------------------------------------------------------- 1 | // import 'tippy.js/dist/tippy.css' 2 | import { type TippyProps } from '@tippyjs/react' 3 | import Tippy from '@tippyjs/react' 4 | import { roundArrow } from 'tippy.js' 5 | import 'tippy.js/animations/shift-away.css' 6 | 7 | // import 'tippy.js/dist/svg-arrow.css' 8 | import './static/TipLightTheme.css' 9 | 10 | interface TipPropsTypes { 11 | isArrow?: boolean 12 | target?: TippyProps['singleton'] 13 | children: JSX.Element[] 14 | } 15 | 16 | export default function Tip({ isArrow = true, target = undefined, children }: TipPropsTypes) { 17 | return ( 18 | 30 | {children[0]} 31 | 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Tip/index.tsx: -------------------------------------------------------------------------------- 1 | import Tip from './Tip' 2 | 3 | export default Tip 4 | -------------------------------------------------------------------------------- /frontend/src/components/utilities/Tip/static/TipLightTheme.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable */ 2 | .tippy-box[data-theme~='light'] { 3 | color: #26323d; 4 | box-shadow: 5 | 0 2.4041px 1.356px 0 hsla(0deg, 0%, 0%, 3%), 6 | 0 4.6704px 3.2585px 0 hsla(0deg, 0%, 0%, 5%), 7 | 0 6.7969px 6.1356px 0 hsla(0deg, 0%, 0%, 6%), 8 | 0 8.8363px 10.9448px 0 hsla(0deg, 0%, 0%, 7%), 9 | 0 11.2514px 20.471px 0 hsla(0deg, 0%, 0%, 9%), 10 | 0 24px 49px 0 hsla(0deg, 0%, 0%, 12%); 11 | background-color: var(--bg-5); 12 | border: 1px solid hsla(0deg, 0%, 93%, 100%); 13 | } 14 | 15 | .tippy-box[data-theme~='light'][data-placement^='top'] > .tippy-arrow::before { 16 | border-top-color: var(--bg-5); 17 | } 18 | 19 | .tippy-box[data-theme~='light'][data-placement^='bottom'] > .tippy-arrow::before { 20 | border-bottom-color: var(--bg-5); 21 | } 22 | 23 | .tippy-box[data-theme~='light'][data-placement^='left'] > .tippy-arrow::before { 24 | border-left-color: var(--bg-5); 25 | } 26 | 27 | .tippy-box[data-theme~='light'][data-placement^='right'] > .tippy-arrow::before { 28 | border-right-color: var(--bg-5); 29 | } 30 | 31 | .tippy-box[data-theme~='light'] > .tippy-backdrop { 32 | background-color: var(--bg-5); 33 | } 34 | 35 | .tippy-box[data-theme~='light'] > .tippy-svg-arrow { 36 | fill: var(--bg); 37 | } 38 | 39 | .tippy-box { 40 | border-radius: calc(var(--border-rad) - 2px); 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/config/devHotModule.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/extensions, import/no-unresolved, import/no-absolute-path 2 | import RefreshRuntime from '/@react-refresh' 3 | 4 | RefreshRuntime.injectIntoGlobalHook(window) 5 | window.$RefreshReg$ = () => {} 6 | window.$RefreshSig$ = () => type => type 7 | window.__vite_plugin_react_preamble_installed__ = true // eslint-disable-line no-underscore-dangle 8 | -------------------------------------------------------------------------------- /frontend/src/config/themes/common.ts: -------------------------------------------------------------------------------- 1 | import { type AliasToken } from 'antd/es/theme/internal' 2 | 3 | const fontFamily = 4 | "'Outfit',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji'" 5 | 6 | const commonThemeToken: Partial = { 7 | fontFamily, 8 | borderRadius: 10, 9 | borderRadiusSM: 8, 10 | borderRadiusXS: 4, 11 | colorPrimary: '#2bbdff', 12 | colorSuccess: '#00ff7d', 13 | colorWarning: '#ffc041' 14 | } 15 | 16 | export default commonThemeToken 17 | -------------------------------------------------------------------------------- /frontend/src/config/themes/theme.dark.ts: -------------------------------------------------------------------------------- 1 | import { type OverrideToken } from 'antd/es/theme/interface' 2 | import { type AliasToken } from 'antd/es/theme/internal' 3 | 4 | import commonThemeToken from './common' 5 | 6 | export const darkThemeToken: Partial = { 7 | ...commonThemeToken, 8 | colorBgContainer: '#1c1a1e', 9 | colorBgBase: '#1c1a1e', 10 | colorTextBase: '#ffffff' 11 | // colorTextQuaternary: '#ffffff' 12 | // colorBgBase: '#161218', 13 | // colorBgBase: '#040304', 14 | // colorTextBase: '#fef1ff', 15 | // colorBgElevated: 'rgb(28, 21, 28)', 16 | // colorBgContainer: '#151015', 17 | // colorBgContainer: '#221E20', 18 | // colorBgContainer: '#231E27', 19 | // colorBgContainer: '#2A242F', 20 | // boxShadow: 21 | // '0 0 0 1px rgb(52, 40, 52), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05);', 22 | // boxShadowSecondary: 23 | // ' 0 0 0 1px rgb(52, 40, 52), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05) ', 24 | // controlOutline: '#ffaace33' 25 | } 26 | 27 | export const darkThemeComponentToken: OverrideToken = { 28 | Menu: { 29 | darkPopupBg: darkThemeToken.colorBgContainer, 30 | darkItemColor: darkThemeToken.colorTextBase 31 | }, 32 | Button: { 33 | defaultGhostBorderColor: darkThemeToken.colorTextBase, 34 | defaultGhostColor: darkThemeToken.colorTextBase 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /frontend/src/config/themes/theme.light.ts: -------------------------------------------------------------------------------- 1 | import { type OverrideToken } from 'antd/es/theme/interface' 2 | import { type AliasToken } from 'antd/es/theme/internal' 3 | 4 | import commonThemeToken from './common' 5 | 6 | export const lightThemeToken: Partial = { 7 | ...commonThemeToken, 8 | colorBgContainer: '#fff', 9 | controlOutline: '#48484823', 10 | boxShadowSecondary: 11 | '0 0 0 1px rgba(0,0,0,0.05) ,0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05) ', 12 | boxShadow: 13 | '0 0 0 1px rgba(0,0,0,0.05), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 9px 28px 8px rgba(0, 0, 0, 0.05) ' 14 | } 15 | 16 | export const lightThemeComponentToken: OverrideToken = { 17 | Button: { 18 | defaultGhostBorderColor: '#1c1a1e', 19 | defaultGhostColor: '#1c1a1e' 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/icons/AntIconWrapper.tsx: -------------------------------------------------------------------------------- 1 | interface AntIconWrapperPropsTypes { 2 | children: JSX.Element 3 | } 4 | 5 | export default function AntIconWrapper({ children }: AntIconWrapperPropsTypes): JSX.Element { 6 | return ( 7 | 8 | {children} 9 | 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /frontend/src/icons/CheckCircle.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function CheckCircle({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/icons/ChevronDown.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function ChevronDown({ size = '1em', stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/icons/ChevronLeft.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function ChevronLeft({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/icons/CloseIcn.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function CloseIcn({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/icons/CopyIcn.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function CopyIcn({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 16 | 21 | 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/icons/DashboardIcn.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function DashboardIcn({ size = undefined, stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/icons/DeleteIcon.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function DeleteIcon({ size = '1em', stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/icons/Dots.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function Dots({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/icons/DotsVertical.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function DotsVertical({ size = undefined, stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/icons/EditIcon.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function EditIcon({ size = '1em', stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 19 | 20 | 21 | 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/icons/IconTypes.ts: -------------------------------------------------------------------------------- 1 | export default interface IconTypes { 2 | size?: number | string 3 | stroke?: number 4 | className?: string 5 | h?: number | undefined 6 | w?: number | undefined 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/icons/Icons.module.css: -------------------------------------------------------------------------------- 1 | .iconsSection { 2 | composes: flx from global; 3 | } 4 | 5 | .icon { 6 | composes: p-2 mr-2 pointer from global; 7 | background-color: var(--light); 8 | box-shadow: var(--shadow-1); 9 | border-radius: 5px; 10 | } 11 | -------------------------------------------------------------------------------- /frontend/src/icons/Icons.tsx: -------------------------------------------------------------------------------- 1 | import CheckCircle from './CheckCircle' 2 | import CloseIcn from './CloseIcn' 3 | import DashboardIcn from './DashboardIcn' 4 | import EditIcon from './EditIcon' 5 | import cls from './Icons.module.css' 6 | import Plus from './Plus' 7 | import SearchIcon from './SearchIcon' 8 | import SunIcn from './SunIcn' 9 | 10 | export default function Icons(): JSX.Element { 11 | const allIcons = [ 12 | , 13 | , 14 | , 15 | , 16 | , 17 | , 18 | 19 | ] 20 | return ( 21 |
22 | {allIcons.map(v => ( 23 |
{v}
24 | ))} 25 |
26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/icons/LucideIcn.tsx: -------------------------------------------------------------------------------- 1 | import { type CSSProperties } from 'react' 2 | 3 | import * as icons from 'lucide-react' 4 | import { type LucideIcon as LucideIconType } from 'lucide-react' 5 | 6 | import AntIconWrapper from './AntIconWrapper' 7 | 8 | interface LucideIcnPropsTypes { 9 | name: keyof typeof icons 10 | color?: string 11 | size?: number | string 12 | strokeWidth?: number 13 | style?: CSSProperties 14 | } 15 | export default function LucideIcn({ 16 | name, 17 | color, 18 | size = '1em', 19 | strokeWidth, 20 | style 21 | }: LucideIcnPropsTypes) { 22 | const LucideIcon = icons[name] as LucideIconType 23 | return ( 24 | 25 | 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /frontend/src/icons/MoonIcn.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function MoonIcn({ size = '1em', stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 8 | 15 | 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/icons/PinIcon.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function PinIcon({ size = '1em', stroke = 0.2, className }: IconTypes) { 5 | return ( 6 | 7 | 16 | 23 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/icons/PinSolidIcon.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function PinSolidIcon({ size = '1em', className }: IconTypes) { 5 | return ( 6 | 7 | 8 | 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/icons/Plus.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function Plus({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 17 | 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/src/icons/RedoIcon.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function RedoIcon({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/icons/RouterIcn.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | 3 | type RouterIcnProps = { 4 | size?: number 5 | className?: string 6 | } 7 | 8 | export default function RouterIcn({ size = 42, className }: RouterIcnProps) { 9 | return ( 10 | 11 | 20 | 24 | 28 | 29 | 30 | 31 | 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /frontend/src/icons/SearchIcon.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function SearchIcon({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/icons/SettingIcon.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function SettingIcon({ size = '1em', stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 24 | 25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/icons/SunIcn.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function SunIcn({ size = '1em', stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 23 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /frontend/src/icons/SupportIcn.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function SupportIcn({ size = '1em', stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 14 | 21 | 22 | 23 | 24 | 25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /frontend/src/icons/UndoIcon.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function UndoIcon({ size = '1em', stroke = 4, className }: IconTypes) { 5 | return ( 6 | 7 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/icons/Wire.tsx: -------------------------------------------------------------------------------- 1 | import AntIconWrapper from './AntIconWrapper' 2 | import type IconTypes from './IconTypes' 3 | 4 | export default function Wire({ size = '1em', stroke = 2, className }: IconTypes) { 5 | return ( 6 | 7 | 17 | 18 | 19 | 20 | 21 | 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import { HashRouter } from 'react-router-dom' 4 | 5 | import config from '@config/config' 6 | import '@resource/styles/global.css' 7 | import '@resource/styles/plugin.css' 8 | import '@resource/styles/utilities.sass' 9 | import '@resource/styles/variables.css' 10 | import '@resource/styles/wp-css-reset.css' 11 | import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 12 | import { ReactQueryDevtools } from '@tanstack/react-query-devtools' 13 | import 'antd/dist/reset.css' 14 | 15 | import AppRoutes from './AppRoutes' 16 | 17 | const { BASE_URL } = config 18 | 19 | if (!window.location.hash && BASE_URL) { 20 | window.location = BASE_URL 21 | } 22 | 23 | const queryClient = new QueryClient() 24 | const elm = document.getElementById('bit-fm-root') 25 | if (elm) { 26 | const root = createRoot(elm) 27 | 28 | root.render( 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /frontend/src/pages/Error404/Error404.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | import { Link, useLocation, useNavigate } from 'react-router-dom' 3 | 4 | import { __ } from '@common/helpers/i18nwrap' 5 | import space from '@resource/img/space.svg' 6 | 7 | export default function Error404() { 8 | const [sec, setsec] = useState(9) 9 | const navigate = useNavigate() 10 | const location = useLocation() 11 | 12 | useEffect(() => { 13 | setTimeout(() => { 14 | if (sec === 0) { 15 | navigate('/', { replace: true }) 16 | } 17 | setsec(sec - 1) 18 | }, 1000) 19 | // eslint-disable-next-line react-hooks/exhaustive-deps 20 | }, [sec]) 21 | console.log('location', location) 22 | return ( 23 |
24 |
25 |
{__('404')}
26 |
{__('Lost In Space')}
27 |
28 | {__('Redirecting Home in')} {sec} 29 |
30 |
31 | 32 | {__('Go Home')} 33 | 34 |
35 | 404 not found 36 |
37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /frontend/src/pages/Error404/index.ts: -------------------------------------------------------------------------------- 1 | import Error404 from './Error404' 2 | 3 | export default Error404 4 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/index.ts: -------------------------------------------------------------------------------- 1 | import Layout from './ui/Layout' 2 | 3 | export default Layout 4 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Layout.module.css: -------------------------------------------------------------------------------- 1 | .layoutWrp { 2 | composes: flx from global; 3 | height: calc(100% - 15px); 4 | margin: 3px 10px 7px 0; 5 | border-radius: 0.8125rem; 6 | overflow: hidden; 7 | border: 2px solid var(--border-20); 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Layout.tsx: -------------------------------------------------------------------------------- 1 | import { Outlet } from 'react-router-dom' 2 | 3 | import { $appConfig } from '@common/globalStates' 4 | import { Global, ThemeProvider } from '@emotion/react' 5 | import globalCssInJs from '@resource/globalCssInJs' 6 | import { Layout as AntLayout, theme } from 'antd' 7 | import { useAtomValue } from 'jotai' 8 | 9 | import cls from './Layout.module.css' 10 | import TopNavigation from './Navigation/TopNavigation' 11 | 12 | const { useToken } = theme 13 | 14 | export default function Layout() { 15 | const { isDarkTheme } = useAtomValue($appConfig) 16 | const antConfig = useToken() 17 | 18 | return ( 19 | 20 | 29 | 30 | 31 | 32 | {/* */} 33 |
34 | 35 |
36 |
37 |
38 |
39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Navigation/Sidebar/Sidebar.module.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | composes: flx ai-cen flx-col from global; 3 | height: 100%; 4 | transition: width var(--tran-4); 5 | transition-delay: 0s; 6 | } 7 | 8 | .sidebarLogo { 9 | composes: flx ai-cen col-gap-1 from global; 10 | color: white; 11 | margin-top: 5px; 12 | height: 42px; 13 | min-height: 42px; 14 | } 15 | 16 | .navList { 17 | composes: flx flx-col jc-sb mt-1 w-100 from global; 18 | height: calc(100% - 58px); 19 | } 20 | 21 | .navItem { 22 | composes: link flx ai-cen col-gap-1 pos-rel fw-med from global; 23 | padding: 10px 15px; 24 | margin-block: 0.1875rem; 25 | transition: background ease-in var(--tran-2); 26 | height: 40px; 27 | z-index: 0; 28 | } 29 | 30 | .navItem:focus { 31 | box-shadow: none !important; 32 | outline: none !important; 33 | } 34 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Navigation/Sidebar/SidebarNavItemWithTooltip.tsx: -------------------------------------------------------------------------------- 1 | import { type ReactElement } from 'react' 2 | 3 | import { $appConfig } from '@common/globalStates' 4 | import { Tooltip } from 'antd' 5 | import { useAtomValue } from 'jotai' 6 | 7 | type NavTooltip = { 8 | children: ReactElement 9 | label: string | JSX.Element 10 | } 11 | 12 | export default function SidebarNavItemWithTooltip({ children, label }: NavTooltip) { 13 | const { isSidebarCollapsed } = useAtomValue($appConfig) 14 | 15 | if (!isSidebarCollapsed) { 16 | return children 17 | } 18 | 19 | return ( 20 | 21 | {children} 22 | 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Navigation/Sidebar/index.ts: -------------------------------------------------------------------------------- 1 | import Sidebar from './Sidebar' 2 | 3 | export default Sidebar 4 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Navigation/TopNavigation/data/useFetchLang.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { useQuery } from '@tanstack/react-query' 3 | 4 | type LangType = { 5 | code: string 6 | name: string 7 | } 8 | export default function useFetchLang() { 9 | const { data, isLoading, isFetching } = useQuery({ 10 | queryKey: ['fetch_languages'], 11 | queryFn: async () => request>({ action: 'language/get', method: 'GET' }), 12 | staleTime: 4320000 13 | }) 14 | return { 15 | isLoading, 16 | isFetching, 17 | languages: data?.code !== 'SUCCESS' ? [] : data?.data 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Navigation/TopNavigation/data/useUpdateLang.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { useMutation } from '@tanstack/react-query' 3 | 4 | export default function useUpdateLang() { 5 | const { mutateAsync } = useMutation(async (lang: string) => 6 | request({ 7 | action: 'language/update', 8 | data: { lang } 9 | }) 10 | ) 11 | 12 | return { 13 | updateLanguage: (lang: string) => mutateAsync(lang) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Navigation/TopNavigation/data/useUpdateTheme.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { useMutation } from '@tanstack/react-query' 3 | 4 | export default function useUpdateTheme() { 5 | const { mutateAsync } = useMutation(async (theme: string) => 6 | request<{ theme: Array }>({ 7 | action: 'theme/update', 8 | data: { theme } 9 | }) 10 | ) 11 | 12 | return { 13 | updateTheme: (theme: string) => mutateAsync(theme) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/pages/Layout/ui/Navigation/TopNavigation/index.ts: -------------------------------------------------------------------------------- 1 | import TopNavigation from './TopNavigation' 2 | 3 | export default TopNavigation 4 | -------------------------------------------------------------------------------- /frontend/src/pages/Logs/data/useDeleteLog.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { useMutation } from '@tanstack/react-query' 3 | 4 | export default function useDeleteLog() { 5 | const { mutateAsync, isLoading } = useMutation(async (ids: number[]) => 6 | request({ 7 | action: 'logs/delete', 8 | data: { ids } 9 | }) 10 | ) 11 | 12 | return { 13 | deleteLog: (ids: number[]) => mutateAsync(ids), 14 | isLogDeleting: isLoading 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/pages/Logs/data/useFetchLogs.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { useQuery } from '@tanstack/react-query' 3 | 4 | export interface LogQueryType { 5 | searchKeyValue?: string 6 | pageNo: number 7 | limit: number 8 | } 9 | 10 | export type LoggedFileDetailsType = { 11 | path: string 12 | hash: string 13 | } 14 | 15 | type LogDetailsType = { 16 | driver: string 17 | files: Array 18 | } 19 | 20 | export type LogType = { 21 | id: number 22 | user_id: number 23 | command: string 24 | details: LogDetailsType 25 | } 26 | 27 | type FetchLogsType = { 28 | logs: Array 29 | count: number 30 | current: number 31 | pages: number 32 | } 33 | 34 | export default function useFetchLogs(searchData: LogQueryType) { 35 | const queryId = `logs-${searchData.pageNo}` 36 | 37 | const { data, isLoading, isFetching, refetch } = useQuery({ 38 | refetchOnWindowFocus: false, 39 | queryKey: ['all_logs', queryId], 40 | queryFn: async () => request({ action: 'logs/all', data: searchData }) 41 | }) 42 | return { 43 | isLoading, 44 | refetch, 45 | isLogsFetching: isFetching, 46 | logs: data?.data?.logs ?? [], 47 | total: data?.data?.count ?? 0, 48 | current: data?.data?.current ?? 0, 49 | pages: data?.data?.pages ?? 0 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /frontend/src/pages/Logs/index.ts: -------------------------------------------------------------------------------- 1 | import Logs from './ui/Logs' 2 | 3 | export default Logs 4 | -------------------------------------------------------------------------------- /frontend/src/pages/Permissions/PermissionsSettingsTypes.d.ts: -------------------------------------------------------------------------------- 1 | export interface PermissionConfig { 2 | commands: Array 3 | path: string 4 | } 5 | 6 | export interface PermissionsSettingsType { 7 | do_not_use_for_admin: boolean 8 | file_type: 'text' | 'image' | 'application' | 'video' | 'audio' 9 | file_size: number 10 | folder_options: 'common' | 'role' | 'user' 11 | by_role: Array 12 | by_user: Array 13 | } 14 | export interface UserPermissionType extends PermissionConfig { 15 | id: number 16 | } 17 | 18 | export type User = { 19 | ID: number 20 | user_login: string 21 | display_name: string 22 | } 23 | 24 | export type DefaultOptionType = Partial 25 | 26 | interface FetchPermissionsSettingsType { 27 | permissions: PermissionsSettingsType 28 | roles: Array 29 | users: Array 30 | commands: Array 31 | fileTypes: Array 32 | wpRoot: string 33 | } 34 | 35 | interface FetchUsersType { 36 | users: Array 37 | total: number 38 | pages: number 39 | current: number 40 | } 41 | -------------------------------------------------------------------------------- /frontend/src/pages/Permissions/data/useAddUserPermission.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { type PermissionConfig } from '@pages/Permissions/PermissionsSettingsTypes' 3 | import { useMutation } from '@tanstack/react-query' 4 | 5 | type UpdatePermissionPayload = { id: number } & PermissionConfig 6 | export default function useAddUserPermission() { 7 | const { mutateAsync, isLoading } = useMutation(async (permission: UpdatePermissionPayload) => 8 | request({ 9 | action: 'permissions/user/add', 10 | data: permission 11 | }) 12 | ) 13 | 14 | return { 15 | addPermission: (permission: UpdatePermissionPayload) => mutateAsync(permission), 16 | addingUserPermission: isLoading 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/pages/Permissions/data/useDeleteUserPermission.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { useMutation } from '@tanstack/react-query' 3 | 4 | export default function useDeleteUserPermission() { 5 | const { mutateAsync, isLoading, variables } = useMutation(async (id: number) => 6 | request({ 7 | action: 'permissions/user/delete', 8 | data: { id } 9 | }) 10 | ) 11 | 12 | return { 13 | deletePermission: (id: number) => mutateAsync(id), 14 | isUserPermissionDeleting: isLoading, 15 | delInProgressId: variables 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/pages/Permissions/data/useFetchPermissionsSettings.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { type FetchPermissionsSettingsType } from '@pages/Permissions/PermissionsSettingsTypes' 3 | import { useQuery } from '@tanstack/react-query' 4 | 5 | export default function useFetchPermissionsSettings() { 6 | const { data, isLoading, isFetching, refetch } = useQuery({ 7 | refetchOnWindowFocus: false, 8 | staleTime: 120000, 9 | queryKey: ['fetch_permissions_settings'], 10 | queryFn: async () => 11 | request({ action: 'permissions/get', method: 'GET' }) 12 | }) 13 | 14 | return { 15 | isLoading, 16 | isFetching, 17 | refetch, 18 | permissions: data?.data.permissions, 19 | roles: data?.data.roles, 20 | users: data?.data.users, 21 | commands: data?.data.commands || [], 22 | fileTypes: data?.data.fileTypes, 23 | wpRoot: data?.data.wpRoot 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/pages/Permissions/data/useUpdatePermissionsSettings.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { type PermissionsSettingsType } from '@pages/Permissions/PermissionsSettingsTypes' 3 | import { useMutation } from '@tanstack/react-query' 4 | 5 | export default function useUpdatePermissionsSettings() { 6 | const { mutateAsync, isLoading } = useMutation( 7 | async (updatedPermissionsSettings: PermissionsSettingsType) => 8 | request>({ 9 | action: 'permissions/update', 10 | data: updatedPermissionsSettings 11 | }) 12 | ) 13 | 14 | return { 15 | updatePermission: (updatedPermissionsSettings: PermissionsSettingsType) => 16 | mutateAsync(updatedPermissionsSettings), 17 | isPermissionUpdating: isLoading 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/pages/Permissions/data/useUpdateUserPermission.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { type UserPermissionType } from '@pages/Permissions/PermissionsSettingsTypes' 3 | import { useMutation } from '@tanstack/react-query' 4 | 5 | export default function useUpdateUserPermission() { 6 | const { mutateAsync, isLoading } = useMutation(async (updatedPermission: UserPermissionType) => 7 | request>({ 8 | action: 'permissions/user/add', 9 | data: updatedPermission 10 | }) 11 | ) 12 | 13 | return { 14 | updateUserPermission: (updatedPermission: UserPermissionType) => mutateAsync(updatedPermission), 15 | isUserPermissionUpdating: isLoading 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/pages/Permissions/index.ts: -------------------------------------------------------------------------------- 1 | import Permissions from './ui/Permissions' 2 | 3 | export default Permissions 4 | -------------------------------------------------------------------------------- /frontend/src/pages/Settings/data/useFetchSettings.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { type FetchSettingsType } from '@pages/Settings/settingsTypes' 3 | import { useQuery } from '@tanstack/react-query' 4 | 5 | export default function useFetchSettings() { 6 | const { data, isLoading, isFetching } = useQuery({ 7 | queryKey: ['fetch_settings'], 8 | queryFn: async () => request({ action: 'settings/get', method: 'GET' }) 9 | }) 10 | return { 11 | isLoading, 12 | isFetching, 13 | settings: data?.data?.settings, 14 | languages: data?.data?.languages, 15 | themes: data?.data?.themes, 16 | defaults: data?.data?.defaults 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/pages/Settings/data/useUpdateSettings.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { type SettingsType } from '@pages/Settings/settingsTypes' 3 | import { useMutation } from '@tanstack/react-query' 4 | 5 | export default function useUpdateSettings() { 6 | const { mutateAsync, isLoading } = useMutation(async (settingsToUpdate: SettingsType) => 7 | request>({ 8 | action: 'settings/update', 9 | data: settingsToUpdate 10 | }) 11 | ) 12 | 13 | return { 14 | updateSettings: (updatedSettings: SettingsType) => mutateAsync(updatedSettings), 15 | isSettingsUpdating: isLoading 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/pages/Settings/data/useUpdateViewType.ts: -------------------------------------------------------------------------------- 1 | import request from '@common/helpers/request' 2 | import { useMutation } from '@tanstack/react-query' 3 | 4 | export default function useUpdateViewType() { 5 | const { mutateAsync, isLoading } = useMutation(async (viewType: string) => 6 | request>({ 7 | action: 'settings/toggle-view', 8 | data: { viewType } 9 | }) 10 | ) 11 | 12 | return { 13 | toggleViewType: (viewType: string) => mutateAsync(viewType), 14 | isSettingsUpdating: isLoading 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/pages/Settings/index.ts: -------------------------------------------------------------------------------- 1 | import Settings from './ui/Settings' 2 | 3 | export default Settings 4 | -------------------------------------------------------------------------------- /frontend/src/pages/Settings/settingsTypes.d.ts: -------------------------------------------------------------------------------- 1 | export type ThemeType = { 2 | key: string 3 | title: string 4 | } 5 | 6 | export type LanguageType = { 7 | code: string 8 | name: string 9 | } 10 | 11 | export interface SettingsType { 12 | show_url_path: string 13 | language: string 14 | size: FinderWindowSize 15 | default_view_type: 'icons' | 'list' 16 | display_ui_options: Array<'toolbar' | 'places' | 'tree' | 'path' | 'stat'> 17 | root_folder_path: string 18 | root_folder_url: string 19 | theme: string 20 | root_folder_name: string 21 | show_hidden_files: boolean 22 | create_hidden_files_folders: boolean 23 | remember_last_dir: boolean 24 | clear_history_on_reload: boolean 25 | create_trash_files_folders: boolean 26 | } 27 | 28 | export type FinderWindowSize = { 29 | width: number 30 | height: number 31 | unit?: 'px' 32 | } 33 | 34 | export type DefaultOptionType = Partial 35 | 36 | interface FetchSettingsType { 37 | settings: SettingsType 38 | languages: Array 39 | themes: Array 40 | defaults: DefaultOptionType 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/pages/Support/index.ts: -------------------------------------------------------------------------------- 1 | import Support from './ui/Support' 2 | 3 | export default Support 4 | -------------------------------------------------------------------------------- /frontend/src/pages/SystemInformation/index.ts: -------------------------------------------------------------------------------- 1 | import SystemInformation from './ui/SystemInformation' 2 | 3 | export default SystemInformation 4 | -------------------------------------------------------------------------------- /frontend/src/pages/root/helpers/initThemeChangeHandler.ts: -------------------------------------------------------------------------------- 1 | import { type RefObject } from 'react' 2 | 3 | import request from '@common/helpers/request' 4 | 5 | export default function initThemeChangeHandler(finderRef: RefObject) { 6 | finderRef.current?.addEventListener('change', (e: Event) => { 7 | const target = e.target as HTMLSelectElement 8 | 9 | if (target && target.nodeName !== 'SELECT') { 10 | return 11 | } 12 | 13 | if ( 14 | target?.className?.indexOf('elfinder-tabstop') !== -1 && 15 | target[0]?.className.indexOf('elfinder-theme-option') !== -1 16 | ) { 17 | request({ action: 'theme/update', data: { theme: target.value } }).then(response => { 18 | if (response.code === 'SUCCESS') { 19 | window.location.reload() 20 | } 21 | }) 22 | } 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/resource/img/earlyBirdOffer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/frontend/src/resource/img/earlyBirdOffer.png -------------------------------------------------------------------------------- /frontend/src/types/emotion.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-ts-comment */ 2 | 3 | /* eslint-disable @typescript-eslint/consistent-type-imports */ 4 | import '@emotion/react' 5 | import { type GlobalToken } from 'antd' 6 | 7 | declare module '@emotion/react' { 8 | export interface Theme { 9 | theme: import('@ant-design/cssinjs').Theme< 10 | // @ts-ignore 11 | import('./internal').SeedToken, 12 | // @ts-ignore 13 | import('./interface').MapToken 14 | > 15 | token: GlobalToken 16 | hashId: string 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/types/finder.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'elfinder' { 2 | export interface File { 3 | hash: string 4 | write: boolean 5 | volumeid: string 6 | i18n: string 7 | name: string 8 | } 9 | 10 | export interface CommandOptions { 11 | _userAction: boolean 12 | _currentType: string 13 | } 14 | 15 | export interface FinderInstance { 16 | id: string 17 | viewType: string 18 | changeTheme(theme: string): FinderInstance 19 | parents(hash: string): Array 20 | cwd(): File 21 | file(hash: string, alsoHidden?: Array): File 22 | bind(event: string, callback: (...args: unknown) => void, priorityFirst?: boolean): void 23 | storage(name: string, value: string): void 24 | destroy(): void 25 | open(): void 26 | reload(): void 27 | disable(): void 28 | enable(): void 29 | addCommand(commandName: string, commandOptions?: CommandOptions): void 30 | removeCommand(commandName: string): void 31 | exec(cmd: string, files?: Array | string, opts?, dstHash?): void 32 | toast({ 33 | mode, 34 | msg, 35 | hideDuration 36 | }: { 37 | mode: 'error' | 'warnning' | 'success' 38 | msg: string 39 | hideDuration: number 40 | }): void 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /frontend/src/types/global.d.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | 3 | // interface cls { [key: string]: string; } 4 | // declare module '*.module.css' { 5 | // const classes: { [key: string]: string } 6 | // export = classes 7 | // } 8 | 9 | declare module 'i18nwrap' 10 | declare module 'incstr' 11 | declare module 'postcss-csso' 12 | declare module '*.module.css' 13 | declare module '*.module.scss' 14 | declare module '*.module.sass' 15 | declare module '*.svg' 16 | declare module '*.png' 17 | declare module '*.webp' 18 | declare module '*.json' 19 | declare module 'deepmerge-alt' 20 | declare module 'detect-port' 21 | 22 | // export type Prettify = { 23 | // [K in keyof T]: T[K] 24 | // // eslint-disable-next-line @typescript-eslint/ban-types 25 | // } & {} 26 | -------------------------------------------------------------------------------- /frontend/src/types/ts-reset.d.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import '@total-typescript/ts-reset' 3 | -------------------------------------------------------------------------------- /frontend/src/types/window.d.ts: -------------------------------------------------------------------------------- 1 | import { type Edge, type Node, type SetViewport, type Viewport } from 'reactflow' 2 | 3 | import { type FinderInstance } from 'elfinder' 4 | 5 | interface AppStateType { 6 | flowState: { 7 | edges: Edge[] 8 | nodes: Node[] 9 | viewport: Viewport 10 | setViewport: SetViewport 11 | } 12 | } 13 | 14 | declare global { 15 | interface Window { 16 | appState: AppStateType 17 | elFinder: FinderInstance 18 | } 19 | } 20 | 21 | export {} 22 | -------------------------------------------------------------------------------- /gettext-parser.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | funcArgumentsMap: { 3 | __: ['msgid'], 4 | _n: ['msgid', 'msgid_plural'], 5 | _x: ['msgid', 'msgctxt'], 6 | _nx: ['msgid', 'msgid_plural', null, 'msgctxt'], 7 | }, 8 | trim: true, 9 | } 10 | -------------------------------------------------------------------------------- /libs/elFinder/files/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /libs/elFinder/files/.trash/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /libs/elFinder/img/arrows-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/arrows-active.png -------------------------------------------------------------------------------- /libs/elFinder/img/arrows-normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/arrows-normal.png -------------------------------------------------------------------------------- /libs/elFinder/img/crop.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/crop.gif -------------------------------------------------------------------------------- /libs/elFinder/img/dialogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/dialogs.png -------------------------------------------------------------------------------- /libs/elFinder/img/editor-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/editor-icons.png -------------------------------------------------------------------------------- /libs/elFinder/img/icons-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/icons-big.png -------------------------------------------------------------------------------- /libs/elFinder/img/icons-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/icons-small.png -------------------------------------------------------------------------------- /libs/elFinder/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/logo.png -------------------------------------------------------------------------------- /libs/elFinder/img/progress.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/progress.gif -------------------------------------------------------------------------------- /libs/elFinder/img/quicklook-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/quicklook-bg.png -------------------------------------------------------------------------------- /libs/elFinder/img/quicklook-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/quicklook-icons.png -------------------------------------------------------------------------------- /libs/elFinder/img/resize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/resize.png -------------------------------------------------------------------------------- /libs/elFinder/img/spinner-mini.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/spinner-mini.gif -------------------------------------------------------------------------------- /libs/elFinder/img/toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/toolbar.png -------------------------------------------------------------------------------- /libs/elFinder/img/trashmesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/trashmesh.png -------------------------------------------------------------------------------- /libs/elFinder/img/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_box.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_box.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_dropbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_dropbox.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_dropbox.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_ftp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_ftp.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_googledrive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_googledrive.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_googledrive.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_local.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_local.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_network.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_onedrive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_onedrive.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_onedrive.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_sql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_sql.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_trash.png -------------------------------------------------------------------------------- /libs/elFinder/img/volume_icon_zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bit-Apps-Pro/file-manager/3bdba3797fe27f357c42ccb0baa3c3d6d1388bac/libs/elFinder/img/volume_icon_zip.png -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/elfinder.fallback.js: -------------------------------------------------------------------------------- 1 | (function(factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | define(factory); 4 | } else if (typeof exports !== 'undefined') { 5 | module.exports = factory(); 6 | } else { 7 | factory(); 8 | } 9 | }(this, function() { 10 | return void 0; 11 | })); 12 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/cs.html.js: -------------------------------------------------------------------------------- 1 |

Tipy na obsluhu

2 |

Obsluha na uživatelském rozhraní je podobná standardnímu správci souborů operačního systému. Drag and Drop však není možné používat s mobilními prohlížeči.

3 |
    4 |
  • Kliknutím pravým tlačítkem nebo dlouhým klepnutím zobrazíte kontextové menu.
  • 5 |
  • Přetáhněte do stromu složek nebo do aktuálního pracovního prostoru a přetáhněte / kopírujte položky.
  • 6 |
  • Výběr položky v pracovním prostoru můžete rozšířit pomocí kláves Shift nebo Alt (Možnost).
  • 7 |
  • Přemístěte soubory a složky do cílové složky nebo do pracovního prostoru.
  • 8 |
  • Dialog předávání může přijímat data schránky nebo seznamy adres URL a přitáhnout a odejít z jiných prohlížečů nebo správců souborů.
  • 9 |
  • Zatažením spusťte stisknutím klávesy Alt (Možnost) přetáhněte do vnějšího prohlížeče. Tato funkce se převezme pomocí prohlížeče Google Chrome.
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/en.html.js: -------------------------------------------------------------------------------- 1 |

Operation Tips

2 |

Operation on the UI is similar to operating system's standard file manager. However, Drag and Drop is not possible with mobile browsers.

3 |
    4 |
  • Right click or long tap to show the context menu.
  • 5 |
  • Drag and drop into the folder tree or the current workspace to move/copy items.
  • 6 |
  • Item selection in the workspace can be extended selection with Shift or Alt (Option) key.
  • 7 |
  • Drag and Drop to the destination folder or workspace to upload files and folders.
  • 8 |
  • The upload dialog can accept paste/drop clipboard data or URL lists and Drag and Drop from other browser or file managers etc.
  • 9 |
  • Drag start with pressing Alt(Option) key to drag out to outside browser. It will became download operation with Google Chrome.
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/es.html.js: -------------------------------------------------------------------------------- 1 |

Consejos de operación

2 |

Operar en la Interfaz del Usuario es similar al administrador de archivos estandar del sistema operativo. Sin embargo, Arrastrar y soltar no es posible con los navegadores móviles.

3 |
    4 |
  • Click derecho o un tap largo para mostrar el menú de contexto.
  • 5 |
  • Arrastrar y soltar dentro del árbol de carpetas o el espacio de trabajo actual para mover/copiar elementos.
  • 6 |
  • La selección de elementos en el espacio de trabajo puede ampliarse con la tecla Shift o Alt (Opción).
  • 7 |
  • Arrastrar y soltar a la carpeta de destino o área de trabajo para cargar archivos y carpetas.
  • 8 |
  • El cuadro de diálogo de carga puede aceptar pegar/soltar datos del portapapeles o listas de URL y arrastrar y soltar desde otro navegador o administrador de archivos, etc.
  • 9 |
  • Iniciar a arrastrar presionando la tecla Alt (Opción) para arrastrar fuera del navegador. Se convertirá en una operación de descarga con Google Chrome.
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/ja.html.js: -------------------------------------------------------------------------------- 1 |

操作のヒント

2 |

UIの操作は、オペレーティングシステムの標準ファイルマネージャにほぼ準拠しています。ただし、モバイルブラウザではドラッグ&ドロップはできません。

3 |
    4 |
  • 右クリックまたはロングタップでコンテキストメニューを表示します。
  • 5 |
  • アイテムを移動/コピーするには、フォルダツリーまたはワークスペースにドラッグ&ドロップします。
  • 6 |
  • ワークスペース内のアイテムの選択は、ShiftキーまたはAltキー(Optionキー)で選択範囲を拡張できます。
  • 7 |
  • コピー先のフォルダまたはワークスペースにドラッグアンドドロップして、ファイルとフォルダをアップロードします。
  • 8 |
  • アップロードダイアログでは、クリップボードのデータやURLリストのペースト/ドロップ、他のブラウザやファイルマネージャからのドラッグ&ドロップなどを受け入れることができます。
  • 9 |
  • Altキー(Optionキー)を押しながらドラッグすると、ブラウザの外にドラッグできます。Google Chromeでダウンロード操作になります。
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/ko.html.js: -------------------------------------------------------------------------------- 1 |

사용 팁

2 |

UI 조작은 운영체제의 표준 파일 관리자를 사용하는 방법과 비슷합니다. 하지만 모바일 브라우저에서는 드래그앤드롭을 사용할 수 없습니다.

3 |
    4 |
  • 오른쪽 클릭하거나 길게 누르면 컨텍스트 메뉴가 나타납니다.
  • 5 |
  • 이동/복사하려면 폴더 트리 또는 원하는 폴더로 드래그앤드롭하십시오.
  • 6 |
  • 작업공간에서 항목을 선택하려면 Shift또는 Alt(Option) 키를 사용하여 선택 영역을 넓힐 수 있습니다.
  • 7 |
  • 업로드 대상 폴더 또는 작업 영역으로 파일및 폴더를 드래그앤드롭하여 업로드할 수 있습니다.
  • 8 |
  • 다른 브라우저 또는 파일관리자등에서 드래그앤드롭하거나, 클립보드를 통해 데이터또는 URL을 복사/붙여넣어 업로드할 수 있습니다.
  • 9 |
  • 크롬브라우저의 경우, Alt(Option) 키를 누른 상태에서 브라우저 밖으로 드래그앤드롭하면 다운로드가 가능합니다.
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/pl.html.js: -------------------------------------------------------------------------------- 1 |

Wskazówki Obsługi

2 |

Działanie w interfejsie użytkownika jest podobne do standardowego menedżera plików systemu operacyjnego. Jednak Przeciąganie i Upuszczanie nie jest możliwe w przeglądarkach mobilnych.

3 |
    4 |
  • Kliknij prawym przyciskiem myszy lub dłużej, aby wyświetlić menu kontekstowe.
  • 5 |
  • Przeciągnij i upuść w drzewie folderów lub bieżącym obszarze roboczym, aby przenieść/kopiować elementy.
  • 6 |
  • Wybór elementu w obszarze roboczym można rozszerzyć wybór z klawiszem Shift lub Alt(Opcja).
  • 7 |
  • Przeciągnij i Upuść do folderu docelowego lub obszaru roboczego, aby przesłać pliki i foldery.
  • 8 |
  • W oknie dialogowym przesyłania można zaakceptować wklejanie/upuszczanie danych schowka lub listy adresów URL, i Przeciągnij i Upuść z innych przeglądarek lub menedżerów plików, itp.
  • 9 |
  • Rozpocznij Przeciąganie naciskając Alt (Opcja), aby przeciągnąć na zewnątrz przeglądarki. Stanie się operacją pobierania z Google Chrome.
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/ru.html.js: -------------------------------------------------------------------------------- 1 |

Советы по работе

2 |

Работа с пользовательским интерфейсом похожа на стандартный файловый менеджер операционной системы. Однако перетаскивание в мобильных браузерах невозможно.

3 |
    4 |
  • Щелкните правой кнопкой мыши или используйте «длинный тап», чтобы отобразить контекстное меню.
  • 5 |
  • Перетащите в дерево папок или текущую рабочую область для перемещения / копирования элементов.
  • 6 |
  • Выбор элемента в рабочей области может быть расширен с помощью клавиши Shift или Alt (Option).
  • 7 |
  • Перетащите в папку назначения или рабочую область для загрузки файлов и папок.
  • 8 |
  • В диалоговом окне загрузки можно использовать вставку данных или списков URL-адресов из буфера обмена, а также перетаскивать из других браузеров или файловых менеджеров и т.д.
  • 9 |
  • Начните перетаскивание, нажав Alt (Option), чтобы перетащить за пределы браузера. Это запустить процесс скачивания в Google Chrome.
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/sk.html.js: -------------------------------------------------------------------------------- 1 |

Tipy na obsluhu

2 |

Obsluha na používateľskom rozhraní je podobná štandardnému správcovi súborov operačného systému. Drag and Drop však nie je možné používať s mobilnými prehliadačmi.

3 |
    4 |
  • Kliknutím pravým tlačidlom alebo dlhým klepnutím zobrazíte kontextové menu.
  • 5 |
  • Presuňte myšou do stromu priečinkov alebo do aktuálneho pracovného priestoru a presuňte / kopírujte položky.
  • 6 |
  • Výber položky v pracovnom priestore môžete rozšíriť pomocou klávesov Shift alebo Alt (Možnosť).
  • 7 |
  • Premiestnite súbory a priečinky do cieľovej zložky alebo do pracovného priestoru.
  • 8 |
  • Dialog odovzdávania môže prijímať dáta schránky alebo zoznamy adries URL a pritiahnuť a odísť z iných prehliadačov alebo správcov súborov.
  • 9 |
  • Potiahnutím spustite stlačením klávesu Alt (Možnosť) pretiahnite do vonkajšieho prehliadača. Táto funkcia sa prevezme pomocou prehliadača Google Chrome.
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/i18n/help/tr.html.js: -------------------------------------------------------------------------------- 1 |

İşlem İpuçları

2 |

Kullanıcı arayüzündeki işlem, işletim sisteminin standart dosya yöneticisine benzer. Ancak Sürükle ve Bırak özelliği mobil tarayıcılarda mümkün değildir.

3 |
    4 |
  • Bağlam menüsünü göstermek için sağ tıklayın veya uzun dokunun.
  • 5 |
  • Öğeleri taşımak/kopyalamak için klasör ağacına veya geçerli çalışma alanına sürükleyip bırakın.
  • 6 |
  • Çalışma alanındaki öğe seçimi Shift veya Alt (Seçenek) tuşuyla genişletilebilir.
  • 7 |
  • Dosya ve klasör yüklemek için hedef klasöre veya çalışma alanına sürükleyip bırakın.
  • 8 |
  • Yükleme iletişim kutusu, pano verilerini veya URL listelerini yapıştırma/bırakma ve diğer tarayıcı veya dosya yöneticilerinden Sürükle ve Bırak vb.
  • 9 |
  • Dış tarayıcıya sürüklemek için Alt (Seçenek) tuşuna basarak sürükleyin. Google Chrome ile indirme işlemi olacak.
  • 10 |
11 | -------------------------------------------------------------------------------- /libs/elFinder/js/worker/calcfilehash.js: -------------------------------------------------------------------------------- 1 | var type = self.data.type, 2 | bin = self.data.bin, 3 | hashOpts = self.data.hashOpts; 4 | 5 | self.res = {}; 6 | if (type === 'md5') { 7 | let sp = new self.SparkMD5.ArrayBuffer(); 8 | sp.append(bin); 9 | self.res.hash = sp.end(); 10 | } else { 11 | let sha = new jsSHA('SHA' + (type.length === 5? type : ('-' + type)).toUpperCase(), 'ARRAYBUFFER'), 12 | opts = {}; 13 | if (type === 'ke128') { 14 | opts.shakeLen = hashOpts.shake128len; 15 | } else if (type === 'ke256') { 16 | opts.shakeLen = hashOpts.shake256len; 17 | } 18 | sha.update(bin); 19 | self.res.hash = sha.getHash('HEX', opts); 20 | } 21 | -------------------------------------------------------------------------------- /libs/elFinder/js/worker/quicklook.tiff.js: -------------------------------------------------------------------------------- 1 | if (self.data.memory) { 2 | Tiff.initialize({ TOTAL_MEMORY: self.data.memory }); 3 | } 4 | 5 | var tiff = new Tiff({ buffer: self.data.data }); 6 | self.res = { 7 | image: tiff.readRGBAImage(), 8 | width: tiff.width(), 9 | height: tiff.height() 10 | }; 11 | -------------------------------------------------------------------------------- /libs/elFinder/php/.tmp/.htaccess: -------------------------------------------------------------------------------- 1 | order deny,allow 2 | deny from all 3 | -------------------------------------------------------------------------------- /libs/elFinder/php/editors/ZipArchive/editor.php: -------------------------------------------------------------------------------- 1 | "; 8 | print_r($obj); 9 | echo ""; 10 | } 11 | endif; 12 | 13 | // Log to a file 14 | if (!function_exists('pl')) : 15 | function pl($obj) 16 | { 17 | ob_start(); 18 | print_r($obj); 19 | echo "\n--------------------------------- x ---------------------------------\n"; 20 | $content = ob_get_clean(); 21 | 22 | $log_file = plugin_dir_path(__FILE__) . 'log.txt'; 23 | $fp = fopen($log_file, "a+"); 24 | fwrite($fp, $content . file_get_contents($log_file)); 25 | fclose($fp); 26 | } 27 | endif; 28 | -------------------------------------------------------------------------------- /testing/test.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/build_copy.js: -------------------------------------------------------------------------------- 1 | const copy = require('recursive-copy'); 2 | const path = require('node:path'); 3 | 4 | // Copy files 5 | const options = { 6 | overwrite: true, 7 | expand: true, 8 | filter: [ 9 | // '**/*', 10 | 'assets/**/*', 11 | 'backend/**/*', 12 | 'languages/**/*', 13 | 'libs/**/*', 14 | 'vendor/**/*', 15 | '!vendor/typisttech/**/*', 16 | 'views/**/*', 17 | 'file-manager.php', 18 | 'license.txt', 19 | 'readme.txt' 20 | ] 21 | }; 22 | 23 | copy('.', path.join('build', 'file-manager'), options) 24 | .on(copy.events.COPY_FILE_START, (copyOperation) => { 25 | console.info(`Copying file ${copyOperation.src}...`); 26 | }) 27 | .on(copy.events.COPY_FILE_COMPLETE, (copyOperation) => { 28 | console.info(`Copied to ${copyOperation.dest}`); 29 | }) 30 | .on(copy.events.ERROR, (error, copyOperation) => { 31 | console.error(`Unable to copy ${copyOperation.dest}`); 32 | }) 33 | .then((results) => { 34 | console.info(`${results.length} file(s) copied`); 35 | }) 36 | .catch((error) => console.error(`Copy failed: ${error}`)); -------------------------------------------------------------------------------- /tools/build_elfinder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd submodule/sources/elFinder || exit; 3 | echo "Building elFinder from submodule."; 4 | npm i; 5 | npm run plugin-build; 6 | cd ../../.. || exit; 7 | -------------------------------------------------------------------------------- /tools/zip_build.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var make_zip = require('zip-local'); 3 | 4 | make_zip.sync.zip('build/file-manager').compress().save( 'build/file-manager.zip'); -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "typeRoots": ["./node_modules/@types", "./frontend/src/types"], 4 | "strict": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "composite": true, 7 | "module": "ESNext", 8 | "moduleResolution": "Node", 9 | "allowSyntheticDefaultImports": true 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /views/finder.php: -------------------------------------------------------------------------------- 1 | preferences(); 8 | 9 | wp_enqueue_style('bfm-jquery-ui-css'); 10 | if (\in_array($preferences->getTheme(), ['default', 'bootstrap'])) { 11 | wp_enqueue_style(Config::SLUG . 'elfinder-css'); 12 | wp_enqueue_style(Config::SLUG . 'theme-css'); 13 | } 14 | 15 | wp_enqueue_script(Config::SLUG . 'elfinder-script'); 16 | wp_enqueue_script(Config::SLUG . 'elfinder-editor-script'); 17 | 18 | wp_enqueue_script(Config::SLUG . 'elfinder-lang', $preferences->getLangUrl(), [Config::SLUG . 'elfinder-script']); 19 | wp_enqueue_script('bfm-finder-loader'); 20 | ?> 21 | 22 | 25 | 26 |
27 |
28 | isLinkPathVisibleInInfo() == 'hide') { 30 | ?> 31 | 37 | --------------------------------------------------------------------------------