├── .git-blame-ignore-revs
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── general_query.md
├── file-preview-modified.png
├── file_preview.png
├── grid.png
├── grid_context.png
├── home-modified.png
├── list.png
├── logo.svg
├── logo_dark.svg
├── logo_light.svg
├── new_logo.svg
├── og_1200.png
├── search-modified.png
├── share-modified.png
├── share_menu.png
├── text_editor.png
├── text_editor_realtime.png
├── try-on-f-cloud-button.svg
├── try_on_FC_dark.svg
├── try_on_FC_light.svg
├── upload-modified.png
└── workflows
│ └── build-image.yml
├── .gitignore
├── .gitmodules
├── LICENSE
├── MANIFEST.in
├── README.md
├── docker
├── docker-compose.yml
└── init.sh
├── drive
├── __init__.py
├── api
│ ├── __init__.py
│ ├── activity.py
│ ├── embed.py
│ ├── files.py
│ ├── list.py
│ ├── notifications.py
│ ├── permissions.py
│ ├── product.py
│ ├── storage.py
│ └── tags.py
├── config
│ ├── __init__.py
│ ├── desktop.py
│ └── docs.py
├── drive
│ ├── __init__.py
│ └── doctype
│ │ ├── __init__.py
│ │ ├── account_request
│ │ ├── __init__.py
│ │ ├── account_request.js
│ │ ├── account_request.json
│ │ ├── account_request.py
│ │ └── test_account_request.py
│ │ ├── drive_document
│ │ ├── __init__.py
│ │ ├── drive_document.js
│ │ ├── drive_document.json
│ │ ├── drive_document.py
│ │ └── test_drive_document.py
│ │ ├── drive_document_version
│ │ ├── __init__.py
│ │ ├── drive_document_version.js
│ │ ├── drive_document_version.json
│ │ ├── drive_document_version.py
│ │ └── test_drive_document_version.py
│ │ ├── drive_entity_activity_log
│ │ ├── __init__.py
│ │ ├── drive_entity_activity_log.js
│ │ ├── drive_entity_activity_log.json
│ │ ├── drive_entity_activity_log.py
│ │ ├── patches
│ │ │ ├── initialize_creation.py
│ │ │ └── share_creation.py
│ │ └── test_drive_entity_activity_log.py
│ │ ├── drive_entity_log
│ │ ├── __init__.py
│ │ ├── drive_entity_log.js
│ │ ├── drive_entity_log.json
│ │ ├── drive_entity_log.py
│ │ └── test_drive_entity_log.py
│ │ ├── drive_entity_tag
│ │ ├── __init__.py
│ │ ├── drive_entity_tag.json
│ │ └── drive_entity_tag.py
│ │ ├── drive_favourite
│ │ ├── __init__.py
│ │ ├── drive_favourite.js
│ │ ├── drive_favourite.json
│ │ ├── drive_favourite.py
│ │ └── test_drive_favourite.py
│ │ ├── drive_file
│ │ ├── __init__.py
│ │ ├── drive_file.js
│ │ ├── drive_file.json
│ │ ├── drive_file.py
│ │ └── test_drive_file.py
│ │ ├── drive_notification
│ │ ├── __init__.py
│ │ ├── drive_notification.js
│ │ ├── drive_notification.json
│ │ ├── drive_notification.py
│ │ └── test_drive_notification.py
│ │ ├── drive_permission
│ │ ├── __init__.py
│ │ ├── drive_permission.js
│ │ ├── drive_permission.json
│ │ ├── drive_permission.py
│ │ └── test_drive_permission.py
│ │ ├── drive_s3_settings
│ │ ├── __init__.py
│ │ ├── drive_s3_settings.js
│ │ ├── drive_s3_settings.json
│ │ ├── drive_s3_settings.py
│ │ └── test_drive_s3_settings.py
│ │ ├── drive_settings
│ │ ├── __init__.py
│ │ ├── drive_settings.js
│ │ ├── drive_settings.json
│ │ ├── drive_settings.py
│ │ └── test_drive_settings.py
│ │ ├── drive_site_settings
│ │ ├── __init__.py
│ │ ├── drive_site_settings.js
│ │ ├── drive_site_settings.json
│ │ ├── drive_site_settings.py
│ │ └── test_drive_site_settings.py
│ │ ├── drive_tag
│ │ ├── __init__.py
│ │ ├── drive_tag.js
│ │ ├── drive_tag.json
│ │ ├── drive_tag.py
│ │ └── test_drive_tag.py
│ │ ├── drive_team
│ │ ├── __init__.py
│ │ ├── drive_team.js
│ │ ├── drive_team.json
│ │ ├── drive_team.py
│ │ └── test_drive_team.py
│ │ ├── drive_team_member
│ │ ├── __init__.py
│ │ ├── drive_team_member.json
│ │ └── drive_team_member.py
│ │ └── drive_user_invitation
│ │ ├── __init__.py
│ │ ├── drive_user_invitation.js
│ │ ├── drive_user_invitation.json
│ │ ├── drive_user_invitation.py
│ │ └── test_drive_user_invitation.py
├── hooks.py
├── install.py
├── locks
│ └── distributed_lock.py
├── modules.txt
├── patches.txt
├── patches
│ ├── __init__.py
│ ├── folder_size.py
│ ├── settings.py
│ └── team_restructure.py
├── public
│ └── .gitkeep
├── templates
│ ├── __init__.py
│ └── emails
│ │ ├── drive_invitation.html
│ │ ├── drive_share.html
│ │ └── otp.html
├── utils
│ ├── __init__.py
│ ├── dev.py
│ ├── files.py
│ └── users.py
└── www
│ ├── __init__.py
│ └── drive.py
├── frontend
├── .eslintrc.js
├── .husky
│ └── pre-commit
├── .prettierrc
├── components.d.ts
├── index.html
├── jsconfig.json
├── package.json
├── postcss.config.js
├── public
│ ├── browserconfig.xml
│ ├── color-circle.png
│ ├── favicon-114x114.png
│ ├── favicon-120x120.png
│ ├── favicon-128x128.png
│ ├── favicon-144x144.png
│ ├── favicon-150x150.png
│ ├── favicon-152x152.png
│ ├── favicon-16x16.png
│ ├── favicon-180x180.png
│ ├── favicon-192x192.png
│ ├── favicon-310x310.png
│ ├── favicon-32x32.png
│ ├── favicon-384x384.png
│ ├── favicon-512x512.png
│ ├── favicon-57x57.png
│ ├── favicon-60x60.png
│ ├── favicon-70x70.png
│ ├── favicon-72x72.png
│ ├── favicon-76x76.png
│ ├── favicon-96x96.png
│ ├── favicon.ico
│ └── manifest.json
├── src
│ ├── App.vue
│ ├── assets
│ │ └── images
│ │ │ └── icons
│ │ │ ├── Link.svg
│ │ │ ├── after effects.svg
│ │ │ ├── application.svg
│ │ │ ├── archive.svg
│ │ │ ├── audio.svg
│ │ │ ├── code.svg
│ │ │ ├── document.svg
│ │ │ ├── excel.svg
│ │ │ ├── folder.svg
│ │ │ ├── image.svg
│ │ │ ├── logo.svg
│ │ │ ├── markdown.svg
│ │ │ ├── page-break.svg
│ │ │ ├── pdf.svg
│ │ │ ├── photoshop.svg
│ │ │ ├── presentation.svg
│ │ │ ├── shared-folder.svg
│ │ │ ├── sketch.svg
│ │ │ ├── spreadsheet.svg
│ │ │ ├── text.svg
│ │ │ ├── unknown.svg
│ │ │ ├── video.svg
│ │ │ └── word.svg
│ ├── components
│ │ ├── ActivityTree.vue
│ │ ├── ActivityTreeItem.vue
│ │ ├── ActivityTreeShare.vue
│ │ ├── AppSwitcher.vue
│ │ ├── BottomBar.vue
│ │ ├── CTADeleteDialog.vue
│ │ ├── ColorPopover.vue
│ │ ├── ContextMenu.vue
│ │ ├── CustomListRow.vue
│ │ ├── CustomListRowItem.vue
│ │ ├── DeleteDialog.vue
│ │ ├── Dialogs.vue
│ │ ├── DocEditor
│ │ │ ├── PreviewEditor.vue
│ │ │ ├── TextEditor.vue
│ │ │ ├── commands.js
│ │ │ ├── components
│ │ │ │ ├── AnnotationList.vue
│ │ │ │ ├── ColorInput.vue
│ │ │ │ ├── ColorPicker.vue
│ │ │ │ ├── DocMenuAndInfoBar.vue
│ │ │ │ ├── FontColor.vue
│ │ │ │ ├── InsertImage.vue
│ │ │ │ ├── InsertLink.vue
│ │ │ │ ├── InsertVideo.vue
│ │ │ │ ├── MentionList.vue
│ │ │ │ ├── Menu.vue
│ │ │ │ ├── MenuBar.vue
│ │ │ │ ├── NewAnnotation.vue
│ │ │ │ ├── NewComment.vue
│ │ │ │ ├── NewManualSnapshotDialog.vue
│ │ │ │ ├── OuterComment.vue
│ │ │ │ ├── ResizableMediaNodeView.vue
│ │ │ │ ├── SnapshotPreviewDialog.vue
│ │ │ │ ├── TableBubbleMenu.vue
│ │ │ │ ├── TableCellMenu.vue
│ │ │ │ ├── TableColumnMenu.vue
│ │ │ │ ├── TableRowMenu.vue
│ │ │ │ └── suggestionList.vue
│ │ │ ├── editor.css
│ │ │ ├── extensions
│ │ │ │ ├── AnnotationExtension
│ │ │ │ │ └── annotation.ts
│ │ │ │ ├── DetailsExtension
│ │ │ │ │ └── DetailsExtension
│ │ │ │ │ │ ├── details-item.ts
│ │ │ │ │ │ ├── details.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── summary.ts
│ │ │ │ ├── InsDelMark.ts
│ │ │ │ ├── InsDelNode.ts
│ │ │ │ ├── Pagebreak.ts
│ │ │ │ ├── backgroundColor.ts
│ │ │ │ ├── character-count.ts
│ │ │ │ ├── collaboration.ts
│ │ │ │ ├── collaborationCursor.ts
│ │ │ │ ├── color.ts
│ │ │ │ ├── comment.ts
│ │ │ │ ├── createDiffMark.ts
│ │ │ │ ├── diffType.js
│ │ │ │ ├── document.ts
│ │ │ │ ├── font-family.ts
│ │ │ │ ├── font-size.ts
│ │ │ │ ├── image-extension.js
│ │ │ │ ├── indent.ts
│ │ │ │ ├── lineHeight.ts
│ │ │ │ ├── link.ts
│ │ │ │ ├── mention
│ │ │ │ │ ├── MentionExtension.ts
│ │ │ │ │ └── mention.js
│ │ │ │ ├── paragraph.ts
│ │ │ │ ├── placeholder.ts
│ │ │ │ ├── resizenode
│ │ │ │ │ ├── dropMedia.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── resizableMedia.ts
│ │ │ │ │ └── resizableMediaMenuUtil.ts
│ │ │ │ ├── suggestion
│ │ │ │ │ ├── suggestion.js
│ │ │ │ │ └── suggestionExtension.js
│ │ │ │ ├── table
│ │ │ │ │ ├── cell.ts
│ │ │ │ │ ├── header.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── row.ts
│ │ │ │ │ ├── table.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── text-align.ts
│ │ │ │ ├── text-style.ts
│ │ │ │ ├── text.ts
│ │ │ │ ├── typography.ts
│ │ │ │ ├── underline.ts
│ │ │ │ └── video-extension.js
│ │ │ ├── genDiff.js
│ │ │ ├── icons
│ │ │ │ ├── AlignCenter.vue
│ │ │ │ ├── AlignJustify.vue
│ │ │ │ ├── AlignLeft.vue
│ │ │ │ ├── AlignRight.vue
│ │ │ │ ├── BlockQuote.vue
│ │ │ │ ├── Bold.vue
│ │ │ │ ├── Check.vue
│ │ │ │ ├── Code.vue
│ │ │ │ ├── Codeblock.vue
│ │ │ │ ├── Details.vue
│ │ │ │ ├── Image.vue
│ │ │ │ ├── Indent.vue
│ │ │ │ ├── Italic.vue
│ │ │ │ ├── List.vue
│ │ │ │ ├── Mention.vue
│ │ │ │ ├── NewAnnotation.vue
│ │ │ │ ├── NewLink.vue
│ │ │ │ ├── OrderList.vue
│ │ │ │ ├── Outdent.vue
│ │ │ │ ├── PageBreak.vue
│ │ │ │ ├── StrikeThrough.vue
│ │ │ │ ├── Style.vue
│ │ │ │ ├── ToggleHeaderCell.vue
│ │ │ │ ├── Underline.vue
│ │ │ │ ├── Video.vue
│ │ │ │ ├── align-center.vue
│ │ │ │ ├── align-item-center.vue
│ │ │ │ ├── align-item-left.vue
│ │ │ │ ├── align-item-right.vue
│ │ │ │ ├── align-left.vue
│ │ │ │ ├── align-right.vue
│ │ │ │ ├── delete.vue
│ │ │ │ ├── float-item-left.vue
│ │ │ │ ├── float-item-right.vue
│ │ │ │ ├── float-left.vue
│ │ │ │ ├── float-right.vue
│ │ │ │ ├── line-height.vue
│ │ │ │ └── quote.vue
│ │ │ ├── index.js
│ │ │ ├── utils.js
│ │ │ └── utils
│ │ │ │ ├── deleteNodes.ts
│ │ │ │ ├── getNestedNodes.ts
│ │ │ │ └── getSelectedContent.ts
│ │ ├── DriveToolBar.vue
│ │ ├── EntityToolbar.vue
│ │ ├── EspressoIcons
│ │ │ ├── AddUser.vue
│ │ │ ├── Apps.vue
│ │ │ ├── Check.vue
│ │ │ ├── ChevronDown.vue
│ │ │ ├── Clock.vue
│ │ │ ├── Cloud.vue
│ │ │ ├── Colour-picker.vue
│ │ │ ├── Comment.vue
│ │ │ ├── Diamond.vue
│ │ │ ├── Docs.vue
│ │ │ ├── DownArrow.vue
│ │ │ ├── Download.vue
│ │ │ ├── Edit.vue
│ │ │ ├── File-upload.vue
│ │ │ ├── File.vue
│ │ │ ├── Filter.vue
│ │ │ ├── Folder-upload.vue
│ │ │ ├── Folder.vue
│ │ │ ├── Globe.vue
│ │ │ ├── Groups.vue
│ │ │ ├── Home.vue
│ │ │ ├── Info.vue
│ │ │ ├── Link.vue
│ │ │ ├── Lock.vue
│ │ │ ├── Move-2.vue
│ │ │ ├── Move.vue
│ │ │ ├── MyDrive.vue
│ │ │ ├── NewFile.vue
│ │ │ ├── NewFolder.vue
│ │ │ ├── Open.vue
│ │ │ ├── Organization.vue
│ │ │ ├── Palette.vue
│ │ │ ├── Preview.vue
│ │ │ ├── Printer.vue
│ │ │ ├── Recent.vue
│ │ │ ├── Rename.vue
│ │ │ ├── Search.vue
│ │ │ ├── Share.vue
│ │ │ ├── ShareNew.vue
│ │ │ ├── Sort.vue
│ │ │ ├── Star.vue
│ │ │ ├── Trash.vue
│ │ │ ├── User.vue
│ │ │ ├── Users.vue
│ │ │ ├── View.vue
│ │ │ ├── ViewGrid.vue
│ │ │ └── ViewList.vue
│ │ ├── FilePicker.vue
│ │ ├── FilePreview.vue
│ │ ├── FileRender.vue
│ │ ├── FileTypePreview
│ │ │ ├── AudioPreview.vue
│ │ │ ├── DocPreview.vue
│ │ │ ├── ImagePreview.vue
│ │ │ ├── MSOfficePreview.vue
│ │ │ ├── PDFPreview.vue
│ │ │ ├── SheetPreview.vue
│ │ │ ├── TextPreview.vue
│ │ │ └── VideoPreview.vue
│ │ ├── FileUploader.vue
│ │ ├── FolderContentsError.vue
│ │ ├── FrappeDriveLogo.vue
│ │ ├── FrappeFileLine.vue
│ │ ├── FrappeFolder.vue
│ │ ├── FrappeFolderLine.vue
│ │ ├── FrappeLogo.vue
│ │ ├── GeneralAccess.vue
│ │ ├── GeneralDialog.vue
│ │ ├── GenericPage.vue
│ │ ├── GridItem.vue
│ │ ├── GridView.vue
│ │ ├── InfoPopup.vue
│ │ ├── InfoSidebar.vue
│ │ ├── ListView.vue
│ │ ├── Loader.vue
│ │ ├── MimeIcons
│ │ │ ├── Archive.vue
│ │ │ ├── Audio.vue
│ │ │ ├── Document.vue
│ │ │ ├── Folder.vue
│ │ │ ├── Image.vue
│ │ │ ├── PDF.vue
│ │ │ ├── Presentation.vue
│ │ │ ├── Spreadsheet.vue
│ │ │ ├── Unknown.vue
│ │ │ └── Video.vue
│ │ ├── MobileSidebar.vue
│ │ ├── MoveDialog.vue
│ │ ├── Navbar.vue
│ │ ├── NewFolderDialog.vue
│ │ ├── NewLinkDialog.vue
│ │ ├── NoFilesSection.vue
│ │ ├── PrimaryDropdown.vue
│ │ ├── ProgressRing.vue
│ │ ├── RenameDialog.vue
│ │ ├── SaasLoginBox.vue
│ │ ├── SearchPopup.vue
│ │ ├── Settings
│ │ │ ├── EditTagDialog.vue
│ │ │ ├── NewTagDialog.vue
│ │ │ ├── ProfileSettings.vue
│ │ │ ├── SettingsDialog.vue
│ │ │ ├── StorageSettings.vue
│ │ │ ├── TagSettings.vue
│ │ │ └── UserListSettings.vue
│ │ ├── ShareDialog
│ │ │ ├── AccessButton.vue
│ │ │ ├── ShareDialog.vue
│ │ │ ├── UserAutoComplete.vue
│ │ │ └── UserSearch.vue
│ │ ├── ShortcutsDialog.vue
│ │ ├── Sidebar.vue
│ │ ├── SidebarItem.vue
│ │ ├── StorageBar.vue
│ │ ├── Tag.vue
│ │ ├── TagColorInput.vue
│ │ ├── TagInput.vue
│ │ ├── TeamSwitcher.vue
│ │ ├── TiptapInput.vue
│ │ ├── Toast.vue
│ │ ├── UploadTracker.vue
│ │ ├── UserDropdown.vue
│ │ ├── UsersBar.vue
│ │ ├── VideoPlayer.vue
│ │ ├── arrow-down-to-line-off.vue
│ │ └── message-circle-off.vue
│ ├── emitter.js
│ ├── index.css
│ ├── main.js
│ ├── pages
│ │ ├── Document.vue
│ │ ├── Favourites.vue
│ │ ├── File.vue
│ │ ├── Folder.vue
│ │ ├── LoginSignup.vue
│ │ ├── Notifications.vue
│ │ ├── Personal.vue
│ │ ├── Recents.vue
│ │ ├── Setup.vue
│ │ ├── Shared.vue
│ │ ├── Team.vue
│ │ ├── Teams.vue
│ │ └── Trash.vue
│ ├── resources
│ │ ├── files.js
│ │ └── permissions.js
│ ├── router.js
│ ├── socket.ts
│ ├── store.js
│ ├── translation.js
│ └── utils
│ │ ├── chunkFileUpload.js
│ │ ├── disable-scroll.ts
│ │ ├── download.js
│ │ ├── dragSelect.js
│ │ ├── file-to-base64.js
│ │ ├── files.js
│ │ ├── format.js
│ │ ├── fuzzySearcher.js
│ │ ├── getIconUrl.js
│ │ ├── getLink.js
│ │ ├── helpers.ts
│ │ ├── markdown.js
│ │ ├── random-color.js
│ │ ├── theme.js
│ │ └── toasts.js
├── tailwind.config.js
├── vite.config.js
└── yarn.lock
├── package-lock.json
├── package.json
├── pyproject.toml
├── realtime
└── handlers.js
├── requirements.txt
├── setup.py
└── yarn.lock
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # Run code through Prettier added pre-commit formatting using husky and pretty-quick added eslint rules check package.json
2 | c2d5eeb0e8b9944cc664bbbefe211563c54ee9b7
3 | # Black on python
4 | 6795d6cc3cc16a0a81846734abc807077363a4ac
5 | # Formatting
6 | 4e6133b9693857fd507372a8fab5d3c58577a1b3
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ""
5 | labels: bug
6 | assignees: ""
7 | ---
8 |
9 | **Describe the bug**
10 | A clear and concise description of what the bug is.
11 |
12 | **To Reproduce**
13 | Steps to reproduce the behavior:
14 |
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 |
28 | - OS: [e.g. iOS]
29 | - Browser [e.g. chrome, safari]
30 | - Version [e.g. 22]
31 |
32 | **Smartphone (please complete the following information):**
33 |
34 | - Device: [e.g. iPhone6]
35 | - OS: [e.g. iOS8.1]
36 | - Browser [e.g. stock browser, safari]
37 | - Version [e.g. 22]
38 |
39 | **Additional context**
40 | Add any other context about the problem here. (Screenshots of errors, console, configuration changes, docker, bare-metal etc.)
41 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea to improve Frappe Drive
4 | labels: feature-request
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/general_query.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question about using Frappe Drive
3 | about: This is not the appropriate channel
4 | labels: query
5 | ---
6 |
7 | General non technical queries are better handled at [discuss.frappe.io](https://discuss.frappe.io/c/frappe-drive/80). Be it about design, installation, configuration, or customization. All of it is better on the forum.
8 |
9 | For documentation, use the [Frappe Drive Documentation](https://docs.frappe.io/drive)
10 |
--------------------------------------------------------------------------------
/.github/file-preview-modified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/file-preview-modified.png
--------------------------------------------------------------------------------
/.github/file_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/file_preview.png
--------------------------------------------------------------------------------
/.github/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/grid.png
--------------------------------------------------------------------------------
/.github/grid_context.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/grid_context.png
--------------------------------------------------------------------------------
/.github/home-modified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/home-modified.png
--------------------------------------------------------------------------------
/.github/list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/list.png
--------------------------------------------------------------------------------
/.github/new_logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/og_1200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/og_1200.png
--------------------------------------------------------------------------------
/.github/search-modified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/search-modified.png
--------------------------------------------------------------------------------
/.github/share-modified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/share-modified.png
--------------------------------------------------------------------------------
/.github/share_menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/share_menu.png
--------------------------------------------------------------------------------
/.github/text_editor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/text_editor.png
--------------------------------------------------------------------------------
/.github/text_editor_realtime.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/text_editor_realtime.png
--------------------------------------------------------------------------------
/.github/upload-modified.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/.github/upload-modified.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.pyc
3 | *.egg-info
4 | *.swp
5 | tags
6 | drive/docs/current
7 | drive/public/frontend
8 | node_modules
9 | frontend/node_modules
10 | drive/public/node_modules
11 | drive/www/drive.html
12 | .yarn-integrity
13 | **/__pycache__
14 | node_modules/
15 | experiments
16 | *.sql
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "frappe-ui"]
2 | path = frappe-ui
3 | url = https://github.com/frappe/frappe-ui
4 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include MANIFEST.in
2 | include requirements.txt
3 | include *.json
4 | include *.md
5 | include *.py
6 | include *.txt
7 | recursive-include drive *.css
8 | recursive-include drive *.csv
9 | recursive-include drive *.html
10 | recursive-include drive *.ico
11 | recursive-include drive *.js
12 | recursive-include drive *.json
13 | recursive-include drive *.md
14 | recursive-include drive *.png
15 | recursive-include drive *.py
16 | recursive-include drive *.svg
17 | recursive-include drive *.txt
18 | recursive-exclude drive *.pyc
--------------------------------------------------------------------------------
/docker/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.7"
2 | services:
3 | mariadb:
4 | image: mariadb:10.8
5 | command:
6 | - --character-set-server=utf8mb4
7 | - --collation-server=utf8mb4_unicode_ci
8 | - --skip-character-set-client-handshake
9 | - --skip-innodb-read-only-compressed # Temporary fix for MariaDB 10.6
10 | environment:
11 | MYSQL_ROOT_PASSWORD: 123
12 | volumes:
13 | - mariadb-data:/var/lib/mysql
14 |
15 | redis:
16 | image: redis:alpine
17 |
18 | frappe:
19 | image: frappe/bench:latest
20 | command: bash /workspace/init.sh
21 | environment:
22 | - SHELL=/bin/bash
23 | working_dir: /home/frappe
24 | volumes:
25 | - .:/workspace
26 | ports:
27 | - 8000:8000
28 | - 9000:9000
29 |
30 | volumes:
31 | mariadb-data:
32 |
--------------------------------------------------------------------------------
/docker/init.sh:
--------------------------------------------------------------------------------
1 | #!bin/bash
2 |
3 | if [ -d "/home/frappe/frappe-bench/apps/frappe" ]; then
4 | echo "Bench already exists, skipping init"
5 | cd frappe-bench
6 | bench start
7 | else
8 | echo "Creating new bench..."
9 | fi
10 |
11 | bench init --skip-redis-config-generation frappe-bench --version version-15
12 |
13 | cd frappe-bench
14 |
15 | # Use containers instead of localhost
16 | bench set-mariadb-host mariadb
17 | bench set-redis-cache-host redis:6379
18 | bench set-redis-queue-host redis:6379
19 | bench set-redis-socketio-host redis:6379
20 |
21 | # Remove redis, watch from Procfile
22 | sed -i '/redis/d' ./Procfile
23 | sed -i '/watch/d' ./Procfile
24 |
25 | bench get-app drive --branch main
26 |
27 | bench new-site drive.localhost \
28 | --force \
29 | --mariadb-root-password 123 \
30 | --admin-password admin \
31 | --no-mariadb-socket
32 |
33 | bench --site drive.localhost install-app drive
34 | bench --site drive.localhost set-config developer_mode 1
35 | bench --site drive.localhost clear-cache
36 | bench --site drive.localhost set-config mute_emails 1
37 | bench use drive.localhost
38 |
39 | bench start
--------------------------------------------------------------------------------
/drive/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = "0.1.1"
2 |
--------------------------------------------------------------------------------
/drive/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/api/__init__.py
--------------------------------------------------------------------------------
/drive/config/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/config/__init__.py
--------------------------------------------------------------------------------
/drive/config/desktop.py:
--------------------------------------------------------------------------------
1 | from frappe import _
2 |
3 |
4 | def get_data():
5 | return [
6 | {
7 | "module_name": "Drive",
8 | "color": "grey",
9 | "icon": "octicon octicon-file-directory",
10 | "type": "module",
11 | "label": _("Drive"),
12 | }
13 | ]
14 |
--------------------------------------------------------------------------------
/drive/config/docs.py:
--------------------------------------------------------------------------------
1 | """
2 | Configuration for docs
3 | """
4 |
5 |
6 | def get_context(context):
7 | context.brand_html = "Drive"
8 |
--------------------------------------------------------------------------------
/drive/drive/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/account_request/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/account_request/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/account_request/account_request.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Account Request", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/account_request/test_account_request.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestAccountRequest(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_document/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_document/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_document/drive_document.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Document", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_document/drive_document.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveDocument(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_document/test_drive_document.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestDriveDocument(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_document_version/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_document_version/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_document_version/drive_document_version.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Document Version", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_document_version/drive_document_version.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveDocumentVersion(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_document_version/test_drive_document_version.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestDriveDocumentVersion(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_activity_log/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_entity_activity_log/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_activity_log/drive_entity_activity_log.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Entity Activity Log", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_activity_log/drive_entity_activity_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveEntityActivityLog(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_activity_log/patches/initialize_creation.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | all_entities = frappe.db.get_list("Drive File", fields=["name", "title", "owner", "creation"])
6 |
7 | for i in all_entities:
8 | doc = frappe.new_doc("Drive Entity Activity Log")
9 | doc.entity = i.name
10 | doc.action_type = "create"
11 | doc.message = f"Created {i.title}"
12 | doc.save()
13 | frappe.db.set_value("Drive Entity Activity Log", doc.name, "owner", i.owner)
14 | frappe.db.set_value("Drive Entity Activity Log", doc.name, "creation", i.creation)
15 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_activity_log/test_drive_entity_activity_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestDriveEntityActivityLog(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_log/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_entity_log/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_log/drive_entity_log.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Entity Log", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_log/drive_entity_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveEntityLog(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_log/test_drive_entity_log.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestDriveEntityLog(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_tag/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_entity_tag/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_tag/drive_entity_tag.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "creation": "2023-03-08 23:57:09.297424",
4 | "doctype": "DocType",
5 | "editable_grid": 1,
6 | "engine": "InnoDB",
7 | "field_order": ["tag"],
8 | "fields": [
9 | {
10 | "fieldname": "tag",
11 | "fieldtype": "Link",
12 | "label": "Tag",
13 | "options": "Drive Tag"
14 | }
15 | ],
16 | "index_web_pages_for_search": 1,
17 | "istable": 1,
18 | "links": [],
19 | "modified": "2023-08-23 17:37:09.877214",
20 | "modified_by": "Administrator",
21 | "module": "Drive",
22 | "name": "Drive Entity Tag",
23 | "owner": "Administrator",
24 | "permissions": [],
25 | "sort_field": "modified",
26 | "sort_order": "DESC",
27 | "states": []
28 | }
29 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_entity_tag/drive_entity_tag.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveEntityTag(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_favourite/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_favourite/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_favourite/drive_favourite.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Favourite", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_favourite/drive_favourite.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "autoname": "autoincrement",
4 | "creation": "2022-11-25 11:51:10.412352",
5 | "doctype": "DocType",
6 | "engine": "InnoDB",
7 | "field_order": ["user", "entity"],
8 | "fields": [
9 | {
10 | "fieldname": "user",
11 | "fieldtype": "Link",
12 | "in_list_view": 1,
13 | "label": "User",
14 | "options": "User",
15 | "reqd": 1
16 | },
17 | {
18 | "fieldname": "entity",
19 | "fieldtype": "Link",
20 | "in_list_view": 1,
21 | "label": "Drive File",
22 | "options": "Drive File",
23 | "reqd": 1
24 | }
25 | ],
26 | "links": [],
27 | "modified": "2025-02-13 15:11:38.610661",
28 | "modified_by": "Administrator",
29 | "module": "Drive",
30 | "name": "Drive Favourite",
31 | "naming_rule": "Autoincrement",
32 | "owner": "Administrator",
33 | "permissions": [
34 | {
35 | "create": 1,
36 | "delete": 1,
37 | "email": 1,
38 | "export": 1,
39 | "print": 1,
40 | "read": 1,
41 | "report": 1,
42 | "role": "All",
43 | "share": 1,
44 | "write": 1
45 | }
46 | ],
47 | "sort_field": "modified",
48 | "sort_order": "DESC",
49 | "states": []
50 | }
51 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_favourite/drive_favourite.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveFavourite(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_favourite/test_drive_favourite.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestDriveFavourite(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_file/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_file/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_file/drive_file.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | frappe.ui.form.on("Drive File", {});
5 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_file/test_drive_file.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase, UnitTestCase
6 |
7 |
8 | # On IntegrationTestCase, the doctype test records and all
9 | # link-field test record dependencies are recursively loaded
10 | # Use these module variables to add/remove to/from that list
11 | EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
12 | IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
13 |
14 |
15 | class UnitTestDriveFile(UnitTestCase):
16 | """
17 | Unit tests for DriveFile.
18 | Use this class for testing individual functions and methods.
19 | """
20 |
21 | pass
22 |
23 |
24 | class IntegrationTestDriveFile(IntegrationTestCase):
25 | """
26 | Integration tests for DriveFile.
27 | Use this class for testing interactions between multiple components.
28 | """
29 |
30 | pass
31 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_notification/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_notification/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_notification/drive_notification.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Notification", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_notification/drive_notification.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveNotification(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_notification/test_drive_notification.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestDriveNotification(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_permission/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_permission/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_permission/drive_permission.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Permission", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_permission/drive_permission.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | import frappe
5 | from frappe.model.document import Document
6 | from drive.api.notifications import notify_share
7 |
8 |
9 | class DrivePermission(Document):
10 | def after_insert(self):
11 | if self.user:
12 | frappe.enqueue(
13 | notify_share,
14 | queue="long",
15 | job_id=f"fdocperm_{self.name}",
16 | deduplicate=True,
17 | timeout=None,
18 | now=False,
19 | at_front=False,
20 | entity_name=self.entity,
21 | docperm_name=self.name,
22 | )
23 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_permission/test_drive_permission.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase, UnitTestCase
6 |
7 |
8 | # On IntegrationTestCase, the doctype test records and all
9 | # link-field test record dependencies are recursively loaded
10 | # Use these module variables to add/remove to/from that list
11 | EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
12 | IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
13 |
14 |
15 | class UnitTestDrivePermission(UnitTestCase):
16 | """
17 | Unit tests for DrivePermission.
18 | Use this class for testing individual functions and methods.
19 | """
20 |
21 | pass
22 |
23 |
24 | class IntegrationTestDrivePermission(IntegrationTestCase):
25 | """
26 | Integration tests for DrivePermission.
27 | Use this class for testing interactions between multiple components.
28 | """
29 |
30 | pass
31 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_s3_settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_s3_settings/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_s3_settings/drive_s3_settings.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive S3 Settings", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_s3_settings/drive_s3_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveS3Settings(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_s3_settings/test_drive_s3_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase, UnitTestCase
6 |
7 |
8 | # On IntegrationTestCase, the doctype test records and all
9 | # link-field test record dependencies are recursively loaded
10 | # Use these module variables to add/remove to/from that list
11 | EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
12 | IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
13 |
14 |
15 | class UnitTestDriveS3Settings(UnitTestCase):
16 | """
17 | Unit tests for DriveS3Settings.
18 | Use this class for testing individual functions and methods.
19 | """
20 |
21 | pass
22 |
23 |
24 | class IntegrationTestDriveS3Settings(IntegrationTestCase):
25 | """
26 | Integration tests for DriveS3Settings.
27 | Use this class for testing interactions between multiple components.
28 | """
29 |
30 | pass
31 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_settings/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_settings/drive_settings.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Settings", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_settings/drive_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveSettings(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_settings/test_drive_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase, UnitTestCase
6 |
7 |
8 | # On IntegrationTestCase, the doctype test records and all
9 | # link-field test record dependencies are recursively loaded
10 | # Use these module variables to add/remove to/from that list
11 | EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
12 | IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
13 |
14 |
15 | class UnitTestDriveSettings(UnitTestCase):
16 | """
17 | Unit tests for DriveSettings.
18 | Use this class for testing individual functions and methods.
19 | """
20 |
21 | pass
22 |
23 |
24 | class IntegrationTestDriveSettings(IntegrationTestCase):
25 | """
26 | Integration tests for DriveSettings.
27 | Use this class for testing interactions between multiple components.
28 | """
29 |
30 | pass
31 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_site_settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_site_settings/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_site_settings/drive_site_settings.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Site Settings", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_site_settings/drive_site_settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2025-05-27 14:25:36.760538",
5 | "doctype": "DocType",
6 | "engine": "InnoDB",
7 | "field_order": ["jwt_key"],
8 | "fields": [
9 | {
10 | "description": "Never share this publicly! This gives complete read access to all files in your site.",
11 | "fieldname": "jwt_key",
12 | "fieldtype": "Password",
13 | "in_list_view": 1,
14 | "label": "JWT Key",
15 | "reqd": 1
16 | }
17 | ],
18 | "grid_page_length": 50,
19 | "index_web_pages_for_search": 1,
20 | "issingle": 1,
21 | "links": [],
22 | "modified": "2025-05-30 15:23:21.155154",
23 | "modified_by": "Administrator",
24 | "module": "Drive",
25 | "name": "Drive Site Settings",
26 | "owner": "Administrator",
27 | "permissions": [
28 | {
29 | "create": 1,
30 | "delete": 1,
31 | "email": 1,
32 | "print": 1,
33 | "read": 1,
34 | "role": "System Manager",
35 | "share": 1,
36 | "write": 1
37 | }
38 | ],
39 | "row_format": "Dynamic",
40 | "sort_field": "creation",
41 | "sort_order": "DESC",
42 | "states": []
43 | }
44 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_site_settings/drive_site_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveSiteSettings(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_site_settings/test_drive_site_settings.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase, UnitTestCase
6 |
7 |
8 | # On IntegrationTestCase, the doctype test records and all
9 | # link-field test record dependencies are recursively loaded
10 | # Use these module variables to add/remove to/from that list
11 | EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
12 | IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
13 |
14 |
15 | class UnitTestDriveSiteSettings(UnitTestCase):
16 | """
17 | Unit tests for DriveSiteSettings.
18 | Use this class for testing individual functions and methods.
19 | """
20 |
21 | pass
22 |
23 |
24 | class IntegrationTestDriveSiteSettings(IntegrationTestCase):
25 | """
26 | Integration tests for DriveSiteSettings.
27 | Use this class for testing interactions between multiple components.
28 | """
29 |
30 | pass
31 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_tag/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_tag/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_tag/drive_tag.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Tag", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_tag/drive_tag.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2023-03-08 23:56:05.264166",
5 | "default_view": "List",
6 | "doctype": "DocType",
7 | "editable_grid": 1,
8 | "engine": "InnoDB",
9 | "field_order": ["title", "color"],
10 | "fields": [
11 | {
12 | "fieldname": "title",
13 | "fieldtype": "Data",
14 | "in_list_view": 1,
15 | "label": "Title",
16 | "reqd": 1
17 | },
18 | {
19 | "fieldname": "color",
20 | "fieldtype": "Data",
21 | "label": "Color"
22 | }
23 | ],
24 | "links": [],
25 | "modified": "2025-03-05 17:10:23.811211",
26 | "modified_by": "Administrator",
27 | "module": "Drive",
28 | "name": "Drive Tag",
29 | "owner": "Administrator",
30 | "permissions": [
31 | {
32 | "create": 1,
33 | "export": 1,
34 | "read": 1,
35 | "role": "All",
36 | "share": 1,
37 | "write": 1
38 | }
39 | ],
40 | "sort_field": "modified",
41 | "sort_order": "DESC",
42 | "states": []
43 | }
44 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_tag/drive_tag.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveTag(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_tag/test_drive_tag.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestDriveTag(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_team/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_team/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_team/drive_team.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive Team", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_team/test_drive_team.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests import IntegrationTestCase, UnitTestCase
6 |
7 |
8 | # On IntegrationTestCase, the doctype test records and all
9 | # link-field test record dependencies are recursively loaded
10 | # Use these module variables to add/remove to/from that list
11 | EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
12 | IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
13 |
14 |
15 | class UnitTestDriveTeam(UnitTestCase):
16 | """
17 | Unit tests for DriveTeam.
18 | Use this class for testing individual functions and methods.
19 | """
20 |
21 | pass
22 |
23 |
24 | class IntegrationTestDriveTeam(IntegrationTestCase):
25 | """
26 | Integration tests for DriveTeam.
27 | Use this class for testing interactions between multiple components.
28 | """
29 |
30 | pass
31 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_team_member/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_team_member/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_team_member/drive_team_member.json:
--------------------------------------------------------------------------------
1 | {
2 | "actions": [],
3 | "allow_rename": 1,
4 | "creation": "2025-01-23 13:08:15.285320",
5 | "doctype": "DocType",
6 | "editable_grid": 1,
7 | "engine": "InnoDB",
8 | "field_order": ["user", "is_admin"],
9 | "fields": [
10 | {
11 | "fieldname": "user",
12 | "fieldtype": "Link",
13 | "in_list_view": 1,
14 | "label": "User",
15 | "options": "User"
16 | },
17 | {
18 | "default": "0",
19 | "fieldname": "is_admin",
20 | "fieldtype": "Check",
21 | "label": "Is Admin"
22 | }
23 | ],
24 | "index_web_pages_for_search": 1,
25 | "istable": 1,
26 | "links": [],
27 | "modified": "2025-02-28 11:26:24.271128",
28 | "modified_by": "Administrator",
29 | "module": "Drive",
30 | "name": "Drive Team Member",
31 | "owner": "Administrator",
32 | "permissions": [],
33 | "sort_field": "creation",
34 | "sort_order": "DESC",
35 | "states": []
36 | }
37 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_team_member/drive_team_member.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
2 | # For license information, please see license.txt
3 |
4 | # import frappe
5 | from frappe.model.document import Document
6 |
7 |
8 | class DriveTeamMember(Document):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_user_invitation/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/drive/doctype/drive_user_invitation/__init__.py
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_user_invitation/drive_user_invitation.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2 | // For license information, please see license.txt
3 |
4 | // frappe.ui.form.on("Drive User Invitation", {
5 | // refresh(frm) {
6 |
7 | // },
8 | // });
9 |
--------------------------------------------------------------------------------
/drive/drive/doctype/drive_user_invitation/test_drive_user_invitation.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and Contributors
2 | # See license.txt
3 |
4 | # import frappe
5 | from frappe.tests.utils import FrappeTestCase
6 |
7 |
8 | class TestDriveUserInvitation(FrappeTestCase):
9 | pass
10 |
--------------------------------------------------------------------------------
/drive/install.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def after_install():
5 | index_check = frappe.db.sql(
6 | """SHOW INDEX FROM `tabDrive File` WHERE Key_name = 'drive_file_title_fts_idx'"""
7 | )
8 | if not index_check:
9 | frappe.db.sql(
10 | """ALTER TABLE `tabDrive File` ADD FULLTEXT INDEX drive_file_title_fts_idx (title)"""
11 | )
12 |
--------------------------------------------------------------------------------
/drive/modules.txt:
--------------------------------------------------------------------------------
1 | Drive
--------------------------------------------------------------------------------
/drive/patches.txt:
--------------------------------------------------------------------------------
1 | [pre_model_sync]
2 | drive.patches.team_restructure #8
3 |
4 | [post_model_sync]
5 | drive.patches.folder_size #3
6 | drive.patches.settings
7 |
--------------------------------------------------------------------------------
/drive/patches/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/patches/__init__.py
--------------------------------------------------------------------------------
/drive/patches/folder_size.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def scan(folder):
5 | folder = frappe.get_doc("Drive File", folder)
6 | child_folders = frappe.get_list(
7 | "Drive File", {"parent_entity": folder.name, "is_group": 1}, pluck="name"
8 | )
9 | for child in child_folders:
10 | scan(child)
11 | sizes = frappe.get_list(
12 | "Drive File", {"parent_entity": folder.name, "is_active": 1}, pluck="file_size"
13 | )
14 | frappe.db.set_value("Drive File", folder.name, "file_size", sum(sizes), update_modified=False)
15 |
16 |
17 | def execute():
18 | roots = frappe.get_list("Drive File", {"parent_entity": ""}, pluck="name")
19 | for root in roots:
20 | scan(root)
21 |
--------------------------------------------------------------------------------
/drive/patches/settings.py:
--------------------------------------------------------------------------------
1 | import frappe
2 |
3 |
4 | def execute():
5 | for user in frappe.db.get_list("User", pluck="name"):
6 | teams = frappe.get_all(
7 | "Drive Team Member",
8 | pluck="parent",
9 | filters=[
10 | ["parenttype", "=", "Drive Team"],
11 | ["user", "=", user],
12 | ],
13 | )
14 | if teams:
15 | if not frappe.db.exists("Drive Settings", {"user": user}):
16 | frappe.get_doc(
17 | {
18 | "doctype": "Drive Settings",
19 | "user": user,
20 | "single_click": 1,
21 | "default_team": teams[0],
22 | }
23 | ).insert()
24 |
--------------------------------------------------------------------------------
/drive/public/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/public/.gitkeep
--------------------------------------------------------------------------------
/drive/templates/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/templates/__init__.py
--------------------------------------------------------------------------------
/drive/templates/emails/drive_invitation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | You've been invited to join
4 | {{ team_name }} on Frappe Drive!
5 |
6 |
7 |
10 | {{ user }} has invited to you to join {{ team_name }} on
11 | Frappe Drive. Click below to get started.
12 |
13 |
14 |
15 |
27 | Accept Invitation
28 |
29 |
30 |
31 |
32 | If you didn’t request this, feel free to ignore this email.
33 |
34 |
35 |
--------------------------------------------------------------------------------
/drive/templates/emails/drive_share.html:
--------------------------------------------------------------------------------
1 |
2 |
Share from {{ team_name }}
3 |
4 |
7 | {{message}}
8 |
9 |
10 |
11 |
23 | Open {{ type }}
24 |
25 |
26 |
27 |
28 | If you didn’t request this, feel free to ignore this email.
29 |
30 |
31 |
--------------------------------------------------------------------------------
/drive/templates/emails/otp.html:
--------------------------------------------------------------------------------
1 |
2 |
Sign in to your account:
3 |
4 |
5 |
8 |
{{ otp }}
9 |
10 |
11 |
12 | If you didn’t request this, feel free to ignore this email.
13 |
14 |
15 |
--------------------------------------------------------------------------------
/drive/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/utils/__init__.py
--------------------------------------------------------------------------------
/drive/utils/dev.py:
--------------------------------------------------------------------------------
1 | from functools import wraps
2 | from time import time
3 |
4 |
5 | def timing(f):
6 | @wraps(f)
7 | def wrap(*args, **kw):
8 | ts = time()
9 | result = f(*args, **kw)
10 | te = time()
11 | print(
12 | " %2.4f s: func:%r "
13 | % (
14 | te - ts,
15 | f.__name__,
16 | )
17 | )
18 | return result
19 |
20 | return wrap
21 |
--------------------------------------------------------------------------------
/drive/www/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/drive/www/__init__.py
--------------------------------------------------------------------------------
/frontend/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | node: true,
4 | },
5 | extends: ["eslint:recommended", "plugin:vue/vue3-recommended", "prettier"],
6 | rules: {
7 | // override/add rules settings here, such as:
8 | // 'vue/no-unused-vars': 'error'
9 | // "vue/require-default-prop": "off",
10 | // Frappe ui
11 | "vue/no-reserved-component-names": "off",
12 | "vue/multi-word-component-names": "off",
13 | },
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | ../../env/bin/black drive/
5 |
6 | cd frontend/
7 |
8 | npm run precommit
9 |
--------------------------------------------------------------------------------
/frontend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false
3 | }
4 |
--------------------------------------------------------------------------------
/frontend/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "jsx": "react"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/frontend/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/frontend/public/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | #ffffff
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/frontend/public/color-circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/color-circle.png
--------------------------------------------------------------------------------
/frontend/public/favicon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-114x114.png
--------------------------------------------------------------------------------
/frontend/public/favicon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-120x120.png
--------------------------------------------------------------------------------
/frontend/public/favicon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-128x128.png
--------------------------------------------------------------------------------
/frontend/public/favicon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-144x144.png
--------------------------------------------------------------------------------
/frontend/public/favicon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-150x150.png
--------------------------------------------------------------------------------
/frontend/public/favicon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-152x152.png
--------------------------------------------------------------------------------
/frontend/public/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-16x16.png
--------------------------------------------------------------------------------
/frontend/public/favicon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-180x180.png
--------------------------------------------------------------------------------
/frontend/public/favicon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-192x192.png
--------------------------------------------------------------------------------
/frontend/public/favicon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-310x310.png
--------------------------------------------------------------------------------
/frontend/public/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-32x32.png
--------------------------------------------------------------------------------
/frontend/public/favicon-384x384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-384x384.png
--------------------------------------------------------------------------------
/frontend/public/favicon-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-512x512.png
--------------------------------------------------------------------------------
/frontend/public/favicon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-57x57.png
--------------------------------------------------------------------------------
/frontend/public/favicon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-60x60.png
--------------------------------------------------------------------------------
/frontend/public/favicon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-70x70.png
--------------------------------------------------------------------------------
/frontend/public/favicon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-72x72.png
--------------------------------------------------------------------------------
/frontend/public/favicon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-76x76.png
--------------------------------------------------------------------------------
/frontend/public/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon-96x96.png
--------------------------------------------------------------------------------
/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frappe/drive/e052a5318b6ef0338a4d09c44fa0f13517116023/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Frappe Drive",
3 | "description": "An easy to use, document sharing and management solution",
4 | "short_name": "Drive",
5 | "icons": [
6 | {
7 | "src": "/favicon-72x72.png",
8 | "type": "image/png",
9 | "sizes": "72x72",
10 | "purpose": "any maskable"
11 | },
12 | {
13 | "src": "/favicon-96x96.png",
14 | "type": "image/png",
15 | "sizes": "96x96",
16 | "purpose": "any maskable"
17 | },
18 | {
19 | "src": "/favicon-128x128.png",
20 | "type": "image/png",
21 | "sizes": "128x128",
22 | "purpose": "any maskable"
23 | },
24 | {
25 | "src": "/favicon-144x144.png",
26 | "type": "image/png",
27 | "sizes": "144x144",
28 | "purpose": "any maskable"
29 | },
30 | {
31 | "src": "/favicon-152x152.png",
32 | "type": "image/png",
33 | "sizes": "152x152",
34 | "purpose": "any maskable"
35 | },
36 | {
37 | "src": "/favicon-192x192.png",
38 | "type": "image/png",
39 | "sizes": "192x192",
40 | "purpose": "any maskable"
41 | },
42 | {
43 | "src": "/favicon-384x384.png",
44 | "type": "image/png",
45 | "sizes": "384x384",
46 | "purpose": "any maskable"
47 | },
48 | {
49 | "src": "/favicon-512x512.png",
50 | "type": "image/png",
51 | "sizes": "512x512",
52 | "purpose": "any maskable"
53 | }
54 | ],
55 | "scope": "/",
56 | "start_url": "/",
57 | "display": "standalone",
58 | "theme_color": "#ffffff",
59 | "background_color": "#ffffff"
60 | }
61 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/Link.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/after effects.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/application.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/archive.svg:
--------------------------------------------------------------------------------
1 |
19 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/audio.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/code.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/document.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/excel.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/folder.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/image.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/logo.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/markdown.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/page-break.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/photoshop.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/presentation.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/shared-folder.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/sketch.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/spreadsheet.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/text.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/unknown.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/video.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/frontend/src/assets/images/icons/word.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/components/NewManualSnapshotDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
39 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/DetailsExtension/DetailsExtension/details-item.ts:
--------------------------------------------------------------------------------
1 | import { mergeAttributes, Node } from "@tiptap/core"
2 |
3 | export interface DetailContentOptions {
4 | readonly HTMLAttributes: Record
5 | }
6 |
7 | export const DetailsContent = Node.create({
8 | name: `detailsContent`,
9 |
10 | content: `block+`,
11 |
12 | group: `block`,
13 |
14 | allowGapCursor: true,
15 |
16 | parseHTML() {
17 | return [
18 | {
19 | tag: `div[data-type="details-content"]`,
20 | },
21 | ]
22 | },
23 |
24 | renderHTML({ HTMLAttributes }) {
25 | return [
26 | `div`,
27 | mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
28 | "data-type": `details-content`,
29 | }),
30 | 0,
31 | ]
32 | },
33 | })
34 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/DetailsExtension/DetailsExtension/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./details"
2 | export * from "./details-item"
3 | export * from "./summary"
4 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/DetailsExtension/DetailsExtension/summary.ts:
--------------------------------------------------------------------------------
1 | import { mergeAttributes, Node } from "@tiptap/core"
2 |
3 | export interface SummaryOptions {
4 | readonly HTMLAttributes: Record
5 | }
6 |
7 | export const DetailsSummary = Node.create({
8 | name: `summary`,
9 |
10 | addOptions() {
11 | return {
12 | HTMLAttributes: {},
13 | }
14 | },
15 |
16 | content: `paragraph`,
17 |
18 | group: `block`,
19 |
20 | parseHTML() {
21 | return [
22 | {
23 | tag: `summary`,
24 | },
25 | ]
26 | },
27 |
28 | renderHTML({ HTMLAttributes }) {
29 | return [
30 | `summary`,
31 | mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
32 | 0,
33 | ]
34 | },
35 | })
36 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/InsDelMark.ts:
--------------------------------------------------------------------------------
1 | import { Mark, mergeAttributes } from "@tiptap/core"
2 |
3 | export const Ins = Mark.create({
4 | name: "ins",
5 | parseHTML() {
6 | return [
7 | {
8 | tag: "ins",
9 | priority: 600,
10 | getAttrs: (node) => {
11 | if (node.closest("code, table")) {
12 | return false
13 | }
14 | return true
15 | },
16 | },
17 | ]
18 | },
19 | renderHTML({ HTMLAttributes }) {
20 | return ["ins", mergeAttributes(HTMLAttributes), 0]
21 | },
22 | })
23 |
24 | export const Del = Mark.create({
25 | name: "del",
26 | parseHTML() {
27 | return [
28 | {
29 | tag: "del",
30 | priority: 600,
31 | getAttrs: (node) => {
32 | if (node.closest("code, table")) {
33 | return false
34 | }
35 | return true
36 | },
37 | },
38 | ]
39 | },
40 | renderHTML({ HTMLAttributes }) {
41 | return ["del", mergeAttributes(HTMLAttributes), 0]
42 | },
43 | })
44 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/InsDelNode.ts:
--------------------------------------------------------------------------------
1 | import { Node, mergeAttributes } from "@tiptap/core"
2 |
3 | export const InsNode = Node.create({
4 | name: "ins",
5 | inline: true,
6 | group: "inline*",
7 | parseHTML() {
8 | return [{ tag: "ins" }]
9 | },
10 | renderHTML({ HTMLAttributes }) {
11 | return ["ins", mergeAttributes(HTMLAttributes), 0]
12 | },
13 | addAttributes() {
14 | return {
15 | class: {
16 | default: null,
17 | },
18 | }
19 | },
20 | })
21 |
22 | export const DelNode = Node.create({
23 | name: "del",
24 | inline: true,
25 | group: "inline*",
26 | parseHTML() {
27 | return [{ tag: "del" }]
28 | },
29 | renderHTML({ HTMLAttributes }) {
30 | return ["del", mergeAttributes(HTMLAttributes), 0]
31 | },
32 | addAttributes() {
33 | return {
34 | class: {
35 | default: null,
36 | },
37 | }
38 | },
39 | })
40 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/createDiffMark.ts:
--------------------------------------------------------------------------------
1 | import { Mark, mergeAttributes } from "@tiptap/core"
2 | import { DiffType } from "./diffType"
3 |
4 | export const DiffMarkExtension = Mark.create({
5 | name: "diffMark",
6 |
7 | addAttributes() {
8 | return {
9 | type: {
10 | renderHTML: ({ type }) => {
11 | const color = {
12 | [DiffType.Inserted]: "#bcf5bc",
13 | [DiffType.Deleted]: "#ff8989",
14 | }[type]
15 | return {
16 | style: "background-color: " + color,
17 | }
18 | },
19 | },
20 | }
21 | },
22 |
23 | renderHTML({ HTMLAttributes }) {
24 | return [
25 | "span",
26 | mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
27 | 0,
28 | ]
29 | },
30 | })
31 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/diffType.js:
--------------------------------------------------------------------------------
1 | export const DiffType = {
2 | Unchanged: 0,
3 | Deleted: -1,
4 | Inserted: 1,
5 | }
6 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/document.ts:
--------------------------------------------------------------------------------
1 | import { Node } from "@tiptap/core"
2 |
3 | /**
4 | * The default document node which represents the top level node of the editor.
5 | * @see https://tiptap.dev/api/nodes/document
6 | */
7 | export const Document = Node.create({
8 | name: "doc",
9 | topNode: true,
10 | content: "block+",
11 | })
12 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/paragraph.ts:
--------------------------------------------------------------------------------
1 | import { mergeAttributes, Node } from "@tiptap/core"
2 |
3 | export interface ParagraphOptions {
4 | /**
5 | * The HTML attributes for a paragraph node.
6 | * @default {}
7 | * @example { class: 'foo' }
8 | */
9 | HTMLAttributes: Record
10 | }
11 |
12 | declare module "@tiptap/core" {
13 | interface Commands {
14 | paragraph: {
15 | /**
16 | * Toggle a paragraph
17 | * @example editor.commands.toggleParagraph()
18 | */
19 | setParagraph: () => ReturnType
20 | }
21 | }
22 | }
23 |
24 | /**
25 | * This extension allows you to create paragraphs.
26 | * @see https://www.tiptap.dev/api/nodes/paragraph
27 | */
28 | export const Paragraph = Node.create({
29 | name: "paragraph",
30 |
31 | priority: 1000,
32 |
33 | addOptions() {
34 | return {
35 | HTMLAttributes: {},
36 | }
37 | },
38 |
39 | group: "block",
40 |
41 | content: "inline*",
42 |
43 | parseHTML() {
44 | return [{ tag: "p" }]
45 | },
46 |
47 | renderHTML({ HTMLAttributes }) {
48 | return [
49 | "p",
50 | mergeAttributes(this.options.HTMLAttributes, HTMLAttributes),
51 | 0,
52 | ]
53 | },
54 |
55 | addCommands() {
56 | return {
57 | setParagraph:
58 | () =>
59 | ({ commands }) => {
60 | return commands.setNode(this.name)
61 | },
62 | }
63 | },
64 |
65 | addKeyboardShortcuts() {
66 | return {
67 | "Mod-Alt-0": () => this.editor.commands.setParagraph(),
68 | }
69 | },
70 | })
71 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/resizenode/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./resizableMedia"
2 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/suggestion/suggestionExtension.js:
--------------------------------------------------------------------------------
1 | import { Extension } from "@tiptap/core"
2 | import Suggestion from "@tiptap/suggestion"
3 |
4 | export default Extension.create({
5 | name: "slash-commands",
6 |
7 | addOptions() {
8 | return {
9 | suggestion: {
10 | char: "/",
11 | command: ({ editor, range, props }) => {
12 | props.command({ editor, range })
13 | },
14 | },
15 | }
16 | },
17 |
18 | addProseMirrorPlugins() {
19 | return [
20 | Suggestion({
21 | editor: this.editor,
22 | ...this.options.suggestion,
23 | }),
24 | ]
25 | },
26 | })
27 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/table/index.ts:
--------------------------------------------------------------------------------
1 | import { TableHeader } from "./header"
2 | import type { TableHeaderOptions } from "./header"
3 |
4 | import { TableRow } from "./row"
5 | import type { TableRowOptions } from "@tiptap/extension-table-row"
6 |
7 | import { TableCell } from "./cell"
8 | import type { TableCellOptions } from "./cell"
9 |
10 | import { Table } from "./table"
11 | import type { TableOptions } from "./table"
12 |
13 | export {
14 | Table,
15 | TableOptions,
16 | TableCell,
17 | TableCellOptions,
18 | TableRow,
19 | TableRowOptions,
20 | TableHeader,
21 | TableHeaderOptions,
22 | TableCellBackground,
23 | TableCellBackgroundOptions,
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/table/row.ts:
--------------------------------------------------------------------------------
1 | import TiptapTableRow from "@tiptap/extension-table-row"
2 |
3 | export const TableRow = TiptapTableRow.extend({
4 | allowGapCursor: false,
5 | })
6 |
7 | export default TableRow
8 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/table/table.ts:
--------------------------------------------------------------------------------
1 | import TiptapTable from "@tiptap/extension-table"
2 | import TableRow from "./row"
3 | import TableHeader from "./header"
4 | import { TableCell } from "./cell"
5 |
6 | import type { TableRowOptions } from "@tiptap/extension-table-row"
7 | import type { TableHeaderOptions } from "./header"
8 | import type { TableCellOptions } from "./cell"
9 | import { GeneralOptions } from "@/type"
10 |
11 | export interface TableOptions extends GeneralOptions {
12 | HTMLAttributes: Record
13 | resizable: boolean
14 | handleWidth: number
15 | cellMinWidth: number
16 | lastColumnResizable: boolean
17 | allowTableNodeSelection: boolean
18 | /** options for table rows */
19 | tableRow: Partial
20 | /** options for table headers */
21 | tableHeader: Partial
22 | /** options for table cells */
23 | tableCell: Partial
24 | /** options for table cell background */
25 | }
26 | export const Table = TiptapTable.extend({
27 | addOptions() {
28 | return {
29 | ...this.parent?.(),
30 | HTMLAttributes: {},
31 | resizable: true,
32 | lastColumnResizable: true,
33 | allowTableNodeSelection: false,
34 | }
35 | },
36 | addExtensions() {
37 | return [
38 | TableRow.configure(this.options.tableRow),
39 | TableHeader.configure(this.options.tableHeader),
40 | TableCell.configure(this.options.tableCell),
41 | ]
42 | },
43 | })
44 |
45 | export default Table
46 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/extensions/text.ts:
--------------------------------------------------------------------------------
1 | import { Node } from "@tiptap/core"
2 |
3 | /**
4 | * This extension allows you to create text nodes.
5 | * @see https://www.tiptap.dev/api/nodes/text
6 | */
7 | export const Text = Node.create({
8 | name: "text",
9 | group: "inline",
10 | })
11 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/AlignCenter.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/AlignJustify.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/AlignLeft.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/AlignRight.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Bold.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Check.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Details.vue:
--------------------------------------------------------------------------------
1 |
2 |
39 |
40 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Image.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Indent.vue:
--------------------------------------------------------------------------------
1 |
2 |
35 |
36 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Italic.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/List.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Mention.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/NewAnnotation.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/NewLink.vue:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Outdent.vue:
--------------------------------------------------------------------------------
1 |
2 |
35 |
36 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/PageBreak.vue:
--------------------------------------------------------------------------------
1 |
2 |
39 |
40 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/ToggleHeaderCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
55 |
56 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Underline.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/Video.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/align-center.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/align-item-center.vue:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/align-item-left.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/align-item-right.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/align-left.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/align-right.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/delete.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/float-item-left.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/float-item-right.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/float-left.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/icons/float-right.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/index.js:
--------------------------------------------------------------------------------
1 | export { default } from "./TextEditor.vue"
2 | export { default as TextEditor } from "./TextEditor.vue"
3 | export { default as PreviewEditor } from "./PreviewEditor.vue"
4 | export { default as TextEditorBubbleMenu } from "./TextEditorBubbleMenu.vue"
5 | export { default as TextEditorFixedMenu } from "./TextEditorFixedMenu.vue"
6 | export { default as TextEditorFloatingMenu } from "./TextEditorFloatingMenu.vue"
7 | export { EditorContent as TextEditorContent } from "@tiptap/vue-3"
8 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/utils.js:
--------------------------------------------------------------------------------
1 | import commands from "./commands"
2 |
3 | export function createEditorButton(option) {
4 | if (option instanceof Array) {
5 | return option.map(createEditorButton)
6 | }
7 | if (typeof option == "object") {
8 | return option
9 | }
10 | return commands[option]
11 | }
12 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/utils/deleteNodes.ts:
--------------------------------------------------------------------------------
1 | import { CommandProps } from "@tiptap/core"
2 | import { EditorState } from "prosemirror-state"
3 |
4 | export function deleteNode(
5 | state: EditorState,
6 | dispatch: CommandProps["dispatch"],
7 | nodeName: string
8 | ): boolean {
9 | const position = state.selection.$anchor
10 |
11 | for (let depth = position.depth; depth > 0; depth--) {
12 | const node = position.node(depth)
13 |
14 | if (node.type.name === nodeName) {
15 | if (dispatch) {
16 | dispatch(
17 | state.tr
18 | .delete(position.before(depth), position.after(depth))
19 | .scrollIntoView()
20 | )
21 | }
22 |
23 | return true
24 | }
25 | }
26 |
27 | return false
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/utils/getNestedNodes.ts:
--------------------------------------------------------------------------------
1 | import { Attrs, Node as NodeElement } from "prosemirror-model"
2 |
3 | export function getNestedNodes(
4 | node: NodeElement
5 | ): Array> {
6 | const nodes: Array> = []
7 |
8 | // @note: the content field is not array type
9 | node.content.forEach((child) => {
10 | if (child instanceof NodeElement) {
11 | nodes.push([child.type.name, child.attrs])
12 | }
13 | })
14 |
15 | return nodes
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/components/DocEditor/utils/getSelectedContent.ts:
--------------------------------------------------------------------------------
1 | import { getHTMLFromFragment } from "@tiptap/core"
2 | import { EditorState } from "prosemirror-state"
3 |
4 | export function getSelectedContent(
5 | state: EditorState,
6 | current?: string
7 | ): string {
8 | const currentNodeContent = current ?? state.selection.$head.parent.textContent
9 | const selected = state.doc.cut(state.selection.from, state.selection.to)
10 |
11 | return selected.content.size
12 | ? getHTMLFromFragment(selected.content, state.schema)
13 | : currentNodeContent
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Check.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/ChevronDown.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Clock.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Cloud.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Colour-picker.vue:
--------------------------------------------------------------------------------
1 |
2 |
34 |
35 |
36 |
41 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Comment.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Diamond.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/DownArrow.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Download.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Edit.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/File-upload.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/File.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Filter.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Folder-upload.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Folder.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Info.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Link.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Lock.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Move-2.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Move.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/MyDrive.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/NewFile.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/NewFolder.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
23 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Open.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Preview.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Printer.vue:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Recent.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Rename.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
25 |
30 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Share.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/ShareNew.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Sort.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/Star.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/User.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/View.vue:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
24 |
29 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/ViewGrid.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/EspressoIcons/ViewList.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/FilePreview.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
42 |
--------------------------------------------------------------------------------
/frontend/src/components/FileTypePreview/PDFPreview.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
13 |
14 |
15 |
28 |
--------------------------------------------------------------------------------
/frontend/src/components/FolderContentsError.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
10 |
Uh oh!
11 |
15 |
16 |
21 |
26 |
27 |
28 |
29 |
30 |
34 |
--------------------------------------------------------------------------------
/frontend/src/components/FrappeDriveLogo.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
--------------------------------------------------------------------------------
/frontend/src/components/FrappeFileLine.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/FrappeFolder.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
--------------------------------------------------------------------------------
/frontend/src/components/FrappeFolderLine.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/FrappeLogo.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/Loader.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
19 |
Loading...
20 |
21 |
22 |
--------------------------------------------------------------------------------
/frontend/src/components/MimeIcons/Audio.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
--------------------------------------------------------------------------------
/frontend/src/components/MimeIcons/Document.vue:
--------------------------------------------------------------------------------
1 |
2 |
22 |
23 |
--------------------------------------------------------------------------------
/frontend/src/components/MimeIcons/Folder.vue:
--------------------------------------------------------------------------------
1 |
2 |
21 |
22 |
--------------------------------------------------------------------------------
/frontend/src/components/MimeIcons/Image.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/MimeIcons/Presentation.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
--------------------------------------------------------------------------------
/frontend/src/components/MimeIcons/Spreadsheet.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/MimeIcons/Unknown.vue:
--------------------------------------------------------------------------------
1 |
2 |
41 |
42 |
--------------------------------------------------------------------------------
/frontend/src/components/MimeIcons/Video.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
--------------------------------------------------------------------------------
/frontend/src/components/MobileSidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
42 |
--------------------------------------------------------------------------------
/frontend/src/components/NoFilesSection.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
20 |
{{ primaryMessage }}
21 |
{{ secondaryMessage }}
22 |
23 |
24 |
43 |
--------------------------------------------------------------------------------
/frontend/src/components/ProgressRing.vue:
--------------------------------------------------------------------------------
1 |
2 |
23 |
24 |
62 |
--------------------------------------------------------------------------------
/frontend/src/components/ShareDialog/AccessButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
25 |
--------------------------------------------------------------------------------
/frontend/src/components/VideoPlayer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
39 |
--------------------------------------------------------------------------------
/frontend/src/components/arrow-down-to-line-off.vue:
--------------------------------------------------------------------------------
1 |
2 |
38 |
39 |
--------------------------------------------------------------------------------
/frontend/src/components/message-circle-off.vue:
--------------------------------------------------------------------------------
1 |
2 |
24 |
25 |
--------------------------------------------------------------------------------
/frontend/src/emitter.js:
--------------------------------------------------------------------------------
1 | import mitt from "mitt"
2 |
3 | const emitter = mitt()
4 | export default emitter
5 |
--------------------------------------------------------------------------------
/frontend/src/index.css:
--------------------------------------------------------------------------------
1 | /* frappe ui includes Inter*/
2 | @import "frappe-ui/src/style.css";
3 | @tailwind base;
4 | @tailwind components;
5 | @tailwind utilities;
6 |
7 | * {
8 | scrollbar-width: thin;
9 | scrollbar-color: #c0c6cc #ebeef0;
10 | }
11 |
12 | html {
13 | scrollbar-width: auto;
14 | }
15 |
16 | *::-webkit-scrollbar-thumb {
17 | background: #c0c6cc;
18 | border-radius: 6px;
19 | }
20 |
21 | *::-webkit-scrollbar-track,
22 | *::-webkit-scrollbar-corner {
23 | background: #ebeef0;
24 | }
25 |
26 | *::-webkit-scrollbar {
27 | width: 6px;
28 | height: 6px;
29 | }
30 |
31 | body::-webkit-scrollbar {
32 | width: 12px;
33 | height: 12px;
34 | }
35 |
36 | body {
37 | overflow: hidden;
38 | }
39 |
40 | .fade-in-enter-active {
41 | transition: opacity 300ms cubic-bezier(0.55, 0.085, 0.68, 0.53);
42 | }
43 |
44 | .fade-in-leave-active {
45 | transition: opacity 225ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
46 | }
47 |
48 | .fade-in-enter,
49 | .fade-in-leave-to {
50 | opacity: 0;
51 | }
52 |
--------------------------------------------------------------------------------
/frontend/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from "vue"
2 | import {
3 | FrappeUI,
4 | Button,
5 | onOutsideClickDirective,
6 | setConfig,
7 | frappeRequest,
8 | } from "frappe-ui"
9 | import store from "./store"
10 | import translationPlugin from "./translation"
11 | import router from "./router"
12 | import App from "./App.vue"
13 | import emitter from "@/emitter"
14 | import "./index.css"
15 | import VueTippy from "vue-tippy"
16 | import { initSocket, RealTimeHandler } from "./socket"
17 |
18 | const app = createApp(App)
19 | setConfig("resourceFetcher", frappeRequest)
20 | app.config.unwrapInjectedRef = true
21 | app.config.globalProperties.emitter = emitter
22 | app.provide("emitter", emitter)
23 | app.use(translationPlugin)
24 | app.use(router)
25 | app.use(store)
26 |
27 | app.use(FrappeUI, { socketio: false })
28 | const socket = initSocket()
29 | const realtime = new RealTimeHandler(socket)
30 | app.provide("realtime", realtime)
31 | app.config.globalProperties.$realtime = realtime
32 | app.directive("on-outside-click", onOutsideClickDirective)
33 | app.use(
34 | VueTippy,
35 | // optional
36 | {
37 | directive: "tippy", // => v-tippy
38 | component: "tippy", // =>
39 | }
40 | )
41 | app.directive("focus", {
42 | mounted: (el) => el.focus(),
43 | })
44 |
45 | setConfig("resourceFetcher", (options) => {
46 | return frappeRequest({
47 | ...options,
48 | onError(err) {
49 | if (err.messages && err.messages[0]) {
50 | return
51 | }
52 | },
53 | })
54 | })
55 | app.component("Button", Button)
56 | app.mount("#app")
57 |
--------------------------------------------------------------------------------
/frontend/src/pages/Favourites.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
15 |
--------------------------------------------------------------------------------
/frontend/src/pages/Personal.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
18 |
--------------------------------------------------------------------------------
/frontend/src/pages/Recents.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
46 |
--------------------------------------------------------------------------------
/frontend/src/pages/Shared.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
28 |
--------------------------------------------------------------------------------
/frontend/src/pages/Team.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
27 |
--------------------------------------------------------------------------------
/frontend/src/pages/Trash.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/frontend/src/translation.js:
--------------------------------------------------------------------------------
1 | import { createResource } from "frappe-ui"
2 |
3 | export default function translationPlugin(app) {
4 | app.config.globalProperties.__ = translate
5 | window.__ = translate
6 | if (!window.translatedMessages) fetchTranslations()
7 | }
8 |
9 | function translate(message) {
10 | let translatedMessages = window.translatedMessages || {}
11 | let translatedMessage = translatedMessages[message] || message
12 |
13 | const hasPlaceholders = /{\d+}/.test(message)
14 | if (!hasPlaceholders) {
15 | return translatedMessage
16 | }
17 | return {
18 | format: function (...args) {
19 | return translatedMessage.replace(/{(\d+)}/g, function (match, number) {
20 | return typeof args[number] != "undefined" ? args[number] : match
21 | })
22 | },
23 | }
24 | }
25 |
26 | function fetchTranslations() {
27 | createResource({
28 | url: "drive.api.product.get_translations",
29 | cache: "translations",
30 | auto: true,
31 | transform: (data) => {
32 | window.translatedMessages = data
33 | },
34 | })
35 | }
36 |
--------------------------------------------------------------------------------
/frontend/src/utils/dragSelect.js:
--------------------------------------------------------------------------------
1 | export function calculateRectangle(coordinates) {
2 | const x3 = Math.min(coordinates.x1, coordinates.x2)
3 | const x4 = Math.max(coordinates.x1, coordinates.x2)
4 | const y3 = Math.min(coordinates.y1, coordinates.y2)
5 | const y4 = Math.max(coordinates.y1, coordinates.y2)
6 | return {
7 | left: x3 + "px",
8 | top: y3 + "px",
9 | width: x4 - x3 + "px",
10 | height: y4 - y3 + "px",
11 | }
12 | }
13 |
14 | export function handleDragSelect(entityElements, coordinates) {
15 | const selectedEntities = new Set()
16 | entityElements.forEach((element) => {
17 | const elementRect = element.getBoundingClientRect()
18 | const maxX = Math.max(coordinates.x1, coordinates.x2)
19 | const minX = Math.min(coordinates.x1, coordinates.x2)
20 | const maxY = Math.max(coordinates.y1, coordinates.y2)
21 | const minY = Math.min(coordinates.y1, coordinates.y2)
22 | if (
23 | ((elementRect.top >= minY && elementRect.top <= maxY) ||
24 | (elementRect.bottom >= minY && elementRect.bottom <= maxY) ||
25 | (minY >= elementRect.top && minY <= elementRect.bottom)) &&
26 | ((elementRect.left >= minX && elementRect.left <= maxX) ||
27 | (elementRect.right >= minX && elementRect.right <= maxX) ||
28 | (minX >= elementRect.left && minX <= elementRect.right))
29 | ) {
30 | //element.classList.add("bg-gray-100", "border-gray-300");
31 | selectedEntities.add(element.id)
32 | } else {
33 | // element.classList.remove("bg-gray-100", "border-gray-300");
34 | }
35 | })
36 | return selectedEntities
37 | }
38 |
--------------------------------------------------------------------------------
/frontend/src/utils/file-to-base64.js:
--------------------------------------------------------------------------------
1 | export default (file) => {
2 | return new Promise((resolve) => {
3 | let reader = new FileReader()
4 | reader.onloadend = () => {
5 | resolve(reader.result)
6 | }
7 | reader.readAsDataURL(file)
8 | })
9 | }
10 |
--------------------------------------------------------------------------------
/frontend/src/utils/fuzzySearcher.js:
--------------------------------------------------------------------------------
1 | import fuzzysort from "fuzzysort"
2 |
3 | export default function getFilteredEntities(search, entities) {
4 | return fuzzysort
5 | .go(search, entities, {
6 | limit: 5,
7 | threshold: -100000,
8 | key: "title",
9 | all: true,
10 | })
11 | .map((result) => result.obj)
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/src/utils/getIconUrl.js:
--------------------------------------------------------------------------------
1 | export function getIconUrl(file_type) {
2 | return new URL(
3 | `/src/assets/images/icons/${file_type.toLowerCase()}.svg`,
4 | import.meta.url
5 | )
6 | }
7 |
8 | export function getThumbnailUrl(name, file_type) {
9 | const HTML_THUMBNAILS = ["Markdown", "Code", "Text", "Document"]
10 | const IMAGE_THUMBNAILS = ["Image", "Video", "PDF", "Presentation"]
11 | const is_image = IMAGE_THUMBNAILS.includes(file_type)
12 | const iconURL = getIconUrl(file_type.toLowerCase())
13 | if (!is_image && !HTML_THUMBNAILS.includes(file_type))
14 | return [null, iconURL, true]
15 | return [
16 | `/api/method/drive.api.files.get_thumbnail?entity_name=${name}`,
17 | iconURL,
18 | is_image,
19 | ]
20 | }
21 |
22 | async function get_thumbnail_content(entity_name) {
23 | const fileUrl = ``
24 |
25 | const content = await fetch(fileUrl)
26 | const blob = await content.blob()
27 | if (content.ok && blob.size) {
28 | return blob
29 | } else {
30 | throw new Error(`Request failed with status ${content.status}`)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/frontend/src/utils/getLink.js:
--------------------------------------------------------------------------------
1 | import { toast } from "@/utils/toasts.js"
2 | import router from "../router.js"
3 |
4 | export function getLinkStem(entity) {
5 | return `${
6 | {
7 | true: "file",
8 | [new Boolean(entity.is_group)]: "folder",
9 | [new Boolean(entity.document)]: "document",
10 | }[true]
11 | }/${entity.name}`
12 | }
13 |
14 | export function getLink(entity, copy = true, withDomain = true) {
15 | const team = router.currentRoute.value.params.team
16 | let link = entity.is_link
17 | ? entity.path
18 | : `${
19 | withDomain ? window.location.origin + "/drive" : ""
20 | }/t/${team}/${getLinkStem(entity)}`
21 |
22 | if (!copy) return link
23 | try {
24 | copyToClipboard(link).then(() => toast("Copied link"))
25 | } catch (err) {
26 | if (err.name === "NotAllowedError") {
27 | toast({
28 | icon: "alert-triangle",
29 | iconClasses: "text-red-700",
30 | title: "Clipboard permission denied",
31 | position: "bottom-right",
32 | })
33 | } else {
34 | console.error("Failed to copy link:", err)
35 | }
36 | }
37 | }
38 |
39 | const copyToClipboard = (str) => {
40 | if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
41 | return navigator.clipboard.writeText(str)
42 | } else {
43 | // Fallback to the legacy clipboard API
44 | const textArea = document.createElement("textarea")
45 | textArea.value = str
46 | document.body.appendChild(textArea)
47 | textArea.select()
48 | document.execCommand("copy")
49 | document.body.removeChild(textArea)
50 | return Promise.resolve()
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/frontend/src/utils/markdown.js:
--------------------------------------------------------------------------------
1 | import showdown from "showdown"
2 |
3 | export function markdownToHTML(text) {
4 | const converter = new showdown.Converter()
5 | return converter.makeHtml(text)
6 | }
7 |
8 | export function htmlToMarkdown(text) {
9 | const converter = new showdown.Converter()
10 | return converter.makeMarkdown(text)
11 | }
12 |
13 | export function detectMarkdown(text) {
14 | const lines = text.split("\n")
15 | const markdown = lines.filter(
16 | (line) =>
17 | line.startsWith("![") ||
18 | line.startsWith("#") ||
19 | line.startsWith("> ") ||
20 | line.startsWith("*") ||
21 | line.startsWith("- ") ||
22 | line.startsWith("1. ") ||
23 | line.startsWith("```") ||
24 | line.startsWith("`") ||
25 | line.startsWith("[") ||
26 | line.startsWith("---")
27 | )
28 | return markdown.length > 0
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/src/utils/random-color.js:
--------------------------------------------------------------------------------
1 | const colors = {
2 | blue: "#0000ff",
3 | cyan: "#00ffff",
4 | darkblue: "#00008b",
5 | darkcyan: "#008b8b",
6 | darkgrey: "#a9a9a9",
7 | darkkhaki: "#bdb76b",
8 | darksalmon: "#e9967a",
9 | darkviolet: "#9400d3",
10 | gold: "#ffd700",
11 | green: "#008000",
12 | lightblue: "#add8e6",
13 | lightgreen: "#90ee90",
14 | magenta: "#ff00ff",
15 | maroon: "#800000",
16 | navy: "#000080",
17 | orange: "#ffa500",
18 | pink: "#ffc0cb",
19 | purple: "#800080",
20 | red: "#ff0000",
21 | yellow: "#ffff00",
22 | }
23 |
24 | const colorArray = Object.values(colors)
25 | export function getRandomColor() {
26 | const randomIndex = Math.floor(Math.random() * colorArray.length)
27 | return colorArray[randomIndex].trim()
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/src/utils/theme.js:
--------------------------------------------------------------------------------
1 | import resolveConfig from "tailwindcss/resolveConfig"
2 | import tailwindConfig from "tailwind.config.js"
3 |
4 | export const config = resolveConfig(tailwindConfig)
5 | export const theme = config.theme
6 |
--------------------------------------------------------------------------------
/frontend/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite"
2 | import vue from "@vitejs/plugin-vue"
3 | import path from "path"
4 | import frappeui from "frappe-ui/vite"
5 |
6 | // https://vitejs.dev/config/
7 | export default defineConfig({
8 | plugins: [
9 | frappeui({
10 | frappeProxy: true, // Setup proxy to Frappe backend
11 | lucideIcons: true, // Configure Lucide icons
12 | jinjaBootData: true, // Inject server-side boot data
13 | // Production build config for asset paths and HTML output
14 | buildConfig: {
15 | indexHtmlPath: "../drive/www/drive.html",
16 | },
17 | }),
18 | vue(),
19 | ],
20 | define: {
21 | "process.env.IS_PREACT": JSON.stringify("true"),
22 | },
23 | resolve: {
24 | alias: {
25 | "@": path.resolve(__dirname, "src"),
26 | "tailwind.config.js": path.resolve(__dirname, "tailwind.config.js"),
27 | },
28 | },
29 | build: {
30 | sourcemap: true,
31 | outDir: `../${path.basename(path.resolve(".."))}/public/frontend`,
32 | emptyOutDir: true,
33 | target: "esnext",
34 | commonjsOptions: {
35 | include: [/tailwind.config.js/, /node_modules/],
36 | },
37 | },
38 | server: {
39 | allowedHosts: ["drive.localhost"],
40 | },
41 | ssr: {
42 | external: { html2canvas: "html2canvas", dompurify: "dompurify" },
43 | },
44 | optimizeDeps: {
45 | esbuildOptions: { target: "esnext" },
46 | include: ["feather-icons", "showdown", "tailwind.config.js", "lowlight"],
47 | },
48 | })
49 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "workspaces": [
4 | "frontend",
5 | "frappe-ui"
6 | ],
7 | "scripts": {
8 | "postinstall": "cd frontend && yarn install",
9 | "dev": "cd frontend && yarn dev",
10 | "build": "cd frontend && yarn build"
11 | },
12 | "dependencies": {}
13 | }
14 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "drive"
3 | authors = [
4 | { name = "Frappe Technologies Pvt Ltd", email = "developers@frappe.io" },
5 | ]
6 | description = "An easy to use, document sharing and management solution."
7 | requires-python = ">=3.10"
8 | readme = "README.md"
9 | dynamic = ["version"]
10 | dependencies = [
11 | "Pillow>=10.0.0,<11.0.0",
12 | "opencv-python-headless>=4.10.0.84",
13 | "python-magic==0.4.27",
14 | "mimemapper==0.4.1",
15 | "unoconv>=0.9.0",
16 | "PyJWT>=2.8.0",
17 | "thumbnail>=1.5.0",
18 | "boto3==1.37.31",
19 | ]
20 |
21 | [build-system]
22 | requires = ["flit_core >=3.4,<4"]
23 | build-backend = "flit_core.buildapi"
24 |
25 | [tool.black]
26 | line-length = 99
27 |
28 | [tool.isort]
29 | line_length = 99
30 | multi_line_output = 3
31 | include_trailing_comma = true
32 | force_grid_wrap = 0
33 | use_parentheses = true
34 | ensure_newline_before_comments = true
35 | indent = "\t"
36 |
37 | # press reads this on install
38 | [deploy.dependencies.apt]
39 | packages = [
40 | "ffmpeg",
41 | ]
--------------------------------------------------------------------------------
/realtime/handlers.js:
--------------------------------------------------------------------------------
1 | // same room evals as frappe
2 | const doc_room = (doctype, docname) => "doc:" + doctype + "/" + docname;
3 | const open_doc_room = (doctype, docname) =>
4 | "open_doc:" + doctype + "/" + docname;
5 | const doctype_room = (doctype) => "doctype:" + doctype;
6 | const task_room = (task_id) => "task_progress:" + task_id;
7 | const user_room = (user) => "user:" + user;
8 |
9 | let drive_handlers = (socket) => {
10 | socket.on(
11 | "document_version_change_emit",
12 | (doctype, document, user, user_image, clientID) => {
13 | let room = doc_room(doctype, document);
14 | socket.nsp.to(room).emit("document_version_change_recv", {
15 | doctype: doctype,
16 | docname: document,
17 | author: user,
18 | author_image: user_image,
19 | author_id: clientID,
20 | });
21 | }
22 | );
23 | };
24 |
25 | module.exports = drive_handlers;
26 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | black
2 | Pillow
3 | opencv-python
4 | mimemapper
5 | unoconv
6 | thumbnail
7 | boto3
8 | PyJWT
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 |
3 | with open("requirements.txt") as f:
4 | install_requires = f.read().strip().split("\n")
5 |
6 | # get version from __version__ variable in drive/__init__.py
7 | from drive import __version__ as version
8 |
9 | setup(
10 | name="drive",
11 | version=version,
12 | description="An easy to use, document sharing and management solution.",
13 | author="Frappe Technologies Pvt. Ltd.",
14 | author_email="hello@frappe.io",
15 | packages=find_packages(),
16 | zip_safe=False,
17 | include_package_data=True,
18 | install_requires=install_requires
19 | )
20 |
--------------------------------------------------------------------------------