Compare commits

...

356 Commits

Author SHA1 Message Date
Aaryan Khandelwal
1e17c30e37 refactor: editor warnings 2025-07-09 13:20:42 +05:30
Aaryan Khandelwal
a4ec80ceca [WIKI-530] regression: page version history dropdown item (#7360) 2025-07-08 16:07:03 +05:30
Sangeetha
16332e0f6d [WEB-4380] chore: work item link sentry error (#7316)
* chore: add warning param in log_exception:''

* fix: logging the exception
2025-07-08 15:43:42 +05:30
Prateek Shourya
f40dda8fdc [WEB-4454] fix: check project publish status using anchor field from publish settings 2025-07-08 15:22:00 +05:30
M. Palanikannan
13ab0624d0 [WIKI-510] feat: enhance issue description input with unsaved changes tracking (#7357) 2025-07-08 14:58:41 +05:30
M. Palanikannan
388588c588 fix: turbo dev command (#7358)
* chore: add dependencies for dev and develop scripts in turbo.json

* update persistence

* chore: remove develop command

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-07-08 13:59:54 +05:30
Aaron Heckmann
c0f986cf95 fix(partial): get dev env working (#7356)
part of #7355
2025-07-08 13:33:12 +05:30
Vipin Chaudhary
ab79a5da10 [WIKI-524] fix: emoji fall back image (#7354) 2025-07-08 03:21:03 +05:30
Prateek Shourya
a2a62e2731 [WEB-4453] fix: enable revalidation on focus and stale data for current user fetch to handle 401 errors (#7353) 2025-07-07 19:52:18 +05:30
Aaryan Khandelwal
e306a92adb [WIKI-523] refactor: assets item component (#7346) 2025-07-07 18:04:12 +05:30
Prateek Shourya
0f0c4b5293 [WEB-4443] fix: remove scroll-behaviour smooth causing Gantt chart continuous scroll (#7351) 2025-07-07 16:09:52 +05:30
Vipin Chaudhary
28375c46e5 [WIKI-521] fix : emoji unexpectedly scroll (#7344)
* fix: emoji modal scroll

* refactor: emoji list

* fix: escape behavior

* fix: minor type fixes
2025-07-04 18:35:23 +05:30
Aaryan Khandelwal
b909416c74 [WIKI-519] regression: page creator and version info #7341 2025-07-04 17:10:03 +05:30
sriram veeraghanta
509db32267 chore: updated node version to 22 and python version to 3.12.10 (#7343)
* chore: updated node version to 22 and python version to 3.12.10

* chore: remove unneccessary comments

* chore: remove nodejs-current dependency
2025-07-04 16:28:30 +05:30
sriram veeraghanta
fdbe4c2ca6 chore: rename server to api (#7342) 2025-07-04 15:32:21 +05:30
sriramveeraghanta
6bee97eb26 chore: remove unused files 2025-07-04 15:08:25 +05:30
sriram veeraghanta
ba884d1e4d feat: adding standard scripts for lint and format check (#7326)
* feat: adding standard scripts for lint and format check

* fix: update packages scripts

* fix: adding tsup config to utils package

* chore: updated build scripts in logger pacakge
2025-07-04 14:23:18 +05:30
sriram veeraghanta
f2a87e8f15 feat: Adding Docker CMD in all Dockerfiles (#7339)
* fix: adding cmd to dockerfiles

* fix: adding cmd to live docker file
2025-07-04 13:59:14 +05:30
sriramveeraghanta
4f5272c8af sync: canary cahnges to preview 2025-07-04 13:57:40 +05:30
Nikhil
805cfed1a3 refactor: update paths and structure for server services in Docker and documentation (#7333)
- Changed references from 'apiserver' to 'apps/server' in Docker configurations and environment setup.
- Updated contributing documentation to reflect the new service structure.
- Adjusted setup script to accommodate the new directory layout.
- Removed obsolete files related to the previous structure.
2025-07-03 18:42:14 +05:30
sriram veeraghanta
1de95ef0d0 feat: optimize docker builds for live server (#7334)
* feat: optimize docker builds for live server

* chore: removed package.json from dockerfile
2025-07-03 18:38:15 +05:30
Vamsi Krishna
618fcf934f refactor: string url path (#7335) 2025-07-03 18:07:02 +05:30
sriramveeraghanta
2f22ca0aea chore: package version upgrade 2025-07-03 15:42:35 +05:30
Bavisetti Narayan
b97d4c4def [WEB-4435] bug: trigger event for work item comment #7331 2025-07-03 15:12:10 +05:30
Vamsi Krishna
635d550d88 [WEB-4432] fix: webhooks translation #7332 2025-07-03 15:12:10 +05:30
Vamsi Krishna
4333cfbd11 [WEB-4432] fix: workspace analytics translation #7330 2025-07-03 15:12:10 +05:30
Vamsi Krishna
9789e176d2 [WEB-4427] fix: header alignments #7311 2025-07-03 15:12:10 +05:30
Bavisetti Narayan
59919d3874 [WEB-4435] bug: trigger event for work item comment #7331 2025-07-03 15:06:11 +05:30
Vamsi Krishna
75235f2ad5 [WEB-4432] fix: webhooks translation #7332 2025-07-03 15:05:13 +05:30
Aaryan Khandelwal
6f27ec031d [WIKI-466] refactor: remove rich text read only editor (#7241)
* refactor: remove rich text read only editor

* fix: type imports
2025-07-03 14:16:17 +05:30
Vamsi Krishna
7d141f26ad [WEB-4432] fix: workspace analytics translation #7330 2025-07-03 14:12:51 +05:30
Aaryan Khandelwal
71012d24ab [WEB-4436] fix: tailwind config #7329 2025-07-03 14:12:17 +05:30
sriram veeraghanta
7d417c5457 fix: update docker file paths and context in branch build workflow #7323 2025-07-03 01:26:40 +05:30
sriram veeraghanta
021b6eebdd fix: admin and space docker paths (#7322) 2025-07-03 01:08:49 +05:30
sriram veeraghanta
e184b646e6 Merge branch 'pratapalakshmi-preview' into preview 2025-07-03 00:53:34 +05:30
sriram veeraghanta
549a0009e7 Merge branch 'preview' of github.com:pratapalakshmi/plane into pratapalakshmi-preview 2025-07-03 00:53:05 +05:30
sriram veeraghanta
944b873184 chore: move all services inside the apps folder (#7321)
* chore: move all services inside the apps folder

* chore: rename apiserver to server
2025-07-03 00:44:13 +05:30
Mohamed Hayballa
6000639921 feat(tests): Add comprehensive test suite for the Project API (#7252)
* feat(tests): Add reusable workspace fixture

Introduces a new `workspace` fixture in `conftest.py` to provide a
consistent and reusable setup for tests that require a workspace.

* feat(tests): Add tests for project creation (POST)

This commit introduces a comprehensive test suite for the project creation API endpoint.

The suite covers a wide range of scenarios, including:
- Successful creation and verification of side-effects (default states, project members, user properties).
- Validation for invalid or missing data (400 Bad Request).
- Permission checks for different user roles (e.g., guests are forbidden).
- Authentication requirements (401 Unauthorized).
- Uniqueness constraints for project names and identifiers (409 Conflict).
- Successful creation with all optional fields populated.

It leverages the `workspace`, `session_client` and `create_user` fixtures for a consistent test setup.

* refactor(tests): Centralize project URL helper into a base class

To avoid code duplication in upcoming tests, this commit introduces a `TestProjectBase` class.

The `get_project_url` helper method is moved into this shared base class, and the existing `TestProjectAPIPost` class is updated to inherit from it. This ensures the URL generation logic is defined in a single place and preparing the suite for the upcoming GET tests.

* feat(tests): Add tests for project listing and retrieval (GET)

This commit adds a suite for the GET method. It leverages the previously created `TestProjectBase` class for URL generation.

The new test suite covers:
- Listing projects:
  - Verifies that administrators see all projects.
  - Confirms guests only see projects they are members of.
  - Tests the separate detailed project list endpoint.
- Retrieving a single project:
  - Checks for successful retrieval of a project by its ID.
  - Handles edge cases for non-existent and archived projects (404 Not Found).
- Authentication:
  - Ensures authentication is required (401 Unauthorized).

* feat(tests): Add tests for project update (PATCH) and deletion (DELETE)

Key scenarios tested for PATCH:
- Successful partial updates by project administrators.
- Forbidden access for non-admin members (403).
- Conflict errors for duplicate names or identifiers on update (409).
- Validation errors for invalid data (400).

Key scenarios tested for DELETE:
- Successful deletion by both project admins and workspace admins.
- Forbidden access for non-admin members (403).
- Authentication checks for unauthenticated users (401).

* Remove unnecessary print statement

* refactor(tests): Update workspace fixture to use ORM

Updates the `workspace` fixture to create the model instance directly via the ORM using the `Workspace` model instead of the API, as requested during code review.

* Refactor: Remove some unused imports

Removes imports that I added while working on the test suite for the Project API but were ultimately not used. Note that other unused imports still exist from the state of the codebase when this branch was created/forked.
2025-07-03 00:40:42 +05:30
Prateek Shourya
6ea24bfdcd [WEB-4429] fix: url path generation #7317 2025-07-02 19:57:10 +05:30
sriram veeraghanta
8cc23bc4a5 refactor: Admin App with better layouts and Meta Information (#7200)
* fix: layout structure in admin

* fix: layout structure in admin

* fix: delete layout files

* chore: updated form related info

* fix: admin import statements

* fix: general page unauthorized flickering issue

* chore: logs related

* chore: lock file updates

* fix: build errors

* fix: coderabbit suggestions
2025-07-02 19:43:44 +05:30
sriram veeraghanta
7153064ebb fix: live server runtime errors (#7314)
* fix: live tsconfig and tsup config

* fix: lock file updates

* feat: adding build process to constants and types packages

* chore: coderabbit suggestions
2025-07-02 18:20:18 +05:30
M. Palanikannan
5874636b0b [WIKI-508] fix: select all with table select #7285 2025-07-02 15:41:31 +05:30
Aaryan Khandelwal
f679628365 [WIKI-449] feat: image block download and alignment options (#7254)
* refactor: custom image extension

* refactor: extension config

* revert: image full screen component

* fix: undo operation

* chore: add download and alignment options

* chore: render image full screen modal in a portal

* chore: add missing attribute to image extension

* chore: minor bugs and improvements

* chore: add aria attributes

* chore: remove unnecessary file

* fix: full screen modal z-index
2025-07-02 15:36:06 +05:30
Vipin Chaudhary
ba6b822f60 [WIKI-402] feat: emoji support for all editors (#7275)
* feat: basic emoji

* feat:emoji slash command

* update slice command

* refactor: emoji storage

* refactor:types

* refactor: emoji list

* refactor: restructure extension

* chore: add comments

* chore: update comments

* fix: fallback image
2025-07-02 15:32:07 +05:30
Vamsi Krishna
757019bf43 [WEB-4427] fix: header alignments #7311 2025-07-02 15:30:40 +05:30
M. Palanikannan
295eb1ef72 [WIKI-506] fix: close the link view after 300ms of hovering out #7283 2025-07-02 15:29:32 +05:30
Aaryan Khandelwal
1fcffad7dd [WIKI-491] [WIKI-496] [WIKI-499] refactor: tables width and selection UI (#7274)
* refactor: tables width and selection UI

* fix: drag handle position

* refactor: selection decorator logic

* refactor: adjacent cells logic

* refactor: folder structure

* chore: default column width for new columns

* refactor: plugin location
2025-07-02 15:27:48 +05:30
Aaryan Khandelwal
0b159c4963 [WIKI-400] feat: page navigation pane (#7206)
* init: page navigation pane

* chore: outline and info tabs

* chore: asset download endpoint

* chore: realtime document info updates

* chore: add support for code splitting

* fix: formatting

* refactor: image block id generation

* chore: implement translation

* refactor: assets list storage logic

* fix: build errors

* fix: image extension name

* refactor: add support for additional asset items

* refactor: asset extraction logic

* chore: add translations

* fix: merge conflicts resolved from preview

* chore: remove version history option from the dropdown

* chore: query params handling

* chore: remove unnecessary logic

* refactor: empty state components

* fix: empty state asset path
2025-07-02 15:25:52 +05:30
Akshita Goyal
cfe169c6d7 [WEB-4423] refactor: event trackers (#7289)
* feat: event tracker helper

* feat: track click events for `data-ph-element`

* fix: handled click events

* fix: handled name

* chore: tracker element updates

* chore: remove export

* chore: tracker element type

* chore: track element and event helper.

* chore: minor improvements

* chore: minor refactors

* fix: workspace events

* fix: added slug

* fix: changes nomenclature

* fix: nomenclature

* chore: update event tracker helper types

* fix: data id

* refactor: cycle events (#7290)

* chore: update event tracker helper types

* refactor: cycle events

* refactor: cycle events

* refactor: cycle event tracker

* chore: update tracker elements

* chore: check for closest element with data-ph-element attribute

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>

* Refactor module events (#7291)

* chore: update event tracker helper types

* refactor: cycle events

* refactor: cycle events

* refactor: cycle event tracker

* refactor: module tracker event and element

* chore: update tracker element

* chore: revert unnecessary changes

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>

* refactor: global views, product tour, notifications, onboarding, users and sidebar related events

* chore: member tracker events (#7302)

* chore: member-tracker-events

* fix: constants

* refactor: update event tracker constants

* refactor: auth related event trackers (#7306)

* Chore: state events (#7307)

* chore: state events

* fix: refactor

* chore: project events (#7305)

* chore: project-events

* fix: refactor

* fix: removed hardcoded values

* fix: github redirection event

* chore: project page tracker events (#7304)

* added events for most page events

* refactor: simplify lock button event handling in PageLockControl

---------

Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>

* chore: minor cleanup and import fixes

* refactor: added tracker elements for buttons (#7308)

Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>

* fix: event type

* refactor: posthog group event

* chore: removed instances of event tracker (#7309)

* refactor: remove event tracker stores and hooks

* refactor: remove event tracker store

* fix: build errors

* clean up event tracker payloads

* fix: coderabbit suggestions

---------

Co-authored-by: Prateek Shourya <prateekshourya@Prateeks-MacBook-Pro.local>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>
Co-authored-by: Vamsi Krishna <46787868+vamsikrishnamathala@users.noreply.github.com>
2025-07-02 15:23:18 +05:30
sriram veeraghanta
fa9c63716c fix: circular dependencies between packages (#7277) 2025-07-01 19:19:44 +05:30
sriramveeraghanta
d3f1b511ad sync: canary changes to preview 2025-07-01 17:42:13 +05:30
Bavisetti Narayan
e624a17868 [WEB-4418]fix: fixed the pagination for issues #7301 2025-07-01 15:03:20 +05:30
Vamsi Krishna
670da9fa03 [WEB-4416]fix: Unnecessary border on Intake header #7297 2025-07-01 13:21:29 +05:30
Aaron
b03844ee2d [WEB-4417] chore: optimize package imports instead of transpile #7292 2025-07-01 12:54:39 +05:30
Dheeraj Kumar Ketireddy
f36d0691fe Chore: replace relation choices with TextChoices in IssueRelation model (#7295) 2025-07-01 12:36:27 +05:30
sriram veeraghanta
e7d888d817 chore: package version updated 2025-06-30 23:56:34 +05:30
Jayash Tripathy
2f6923fca0 fix: work item peek infinite loop (#7284)
* fix: removed t function from dependency array which was causing infinite loop

* fix: add eslint disable comment for exhaustive-deps warning in IssuePeekOverview
2025-06-30 16:10:50 +05:30
Vamsi Krishna
912246c592 [WEB-4365] fix: dates display properties toggle #7262 2025-06-30 16:10:06 +05:30
Aaryan Khandelwal
4a065e14d0 [WEB-4409] refactor: event constants (#7276)
* refactor: event constants

* fix: cycle event keys

* chore: store extension

* chore: update events naming convention

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-06-27 19:01:00 +05:30
Aaryan Khandelwal
e09aeab5b8 [WIKI-481] refactor: editor parser #7261 2025-06-27 16:05:38 +05:30
Akshita Goyal
25a6cd49fc fix: added @plane/services to the web dependencies (#7271) 2025-06-26 14:33:13 +05:30
JayashTripathy
b5538565c7 [WEB-4371] feat: bar chart component with lollipop shape variant (#7268)
* feat: enhance bar chart component with shape variants and custom tooltip

* Update packages/propel/src/charts/bar-chart/bar.tsx

removed the unknown props

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update packages/propel/src/charts/bar-chart/bar.tsx

removed console log

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* refactor: replace inline percentage text with PercentageText component in bar chart

* Added new variant - lollipop-dotted

* added some comments

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-06-25 23:43:10 +05:30
Nikhil
b8043f92b1 [WEB-4373]: optimize backend query for workspace views and Project gantt view (#7267)
* feat: add IssueListDetailSerializer for detailed issue representation

- Introduced IssueListDetailSerializer to enhance issue data representation with expanded fields.
- Updated issue detail endpoint to utilize the new serializer for improved data handling.
- Added methods for retrieving related module, label, and assignee IDs, along with support for expanded relations.

* feat: add ViewIssueListSerializer and enhance issue ordering

- Introduced ViewIssueListSerializer for improved issue representation, including assignee, label, and module IDs.
- Updated WorkspaceViewIssuesViewSet to utilize the new serializer and optimized queryset with prefetching.
- Enhanced order_issue_queryset to maintain consistent ordering by created_at alongside other fields.
- Modified pagination logic to support total count retrieval for better performance.

* fix: optimize issue filtering and pagination logic

- Updated WorkspaceViewIssuesViewSet to apply filters more efficiently in the issue query.
- Refined pagination logic in OffsetPaginator to ensure consistent behavior using limit instead of cursor.value, improving overall pagination accuracy.

* fix: improve pagination logic in OffsetPaginator

- Updated the next_cursor calculation to use the length of results instead of cursor.value, ensuring accurate pagination behavior.
- Added a comment to clarify the purpose of checking for additional results after the current page.

* Move the common permission filters into a separate method

* fix: handle deleted related issues in serializers

- Updated IssueListDetailSerializer to skip null related issues when building relations.
- Enhanced ViewIssueListSerializer to safely access state.group, returning None if state is not present.
- Removed unused User import in base.py for cleaner code.

---------

Co-authored-by: Dheeraj Kumar Ketireddy <dheeru0198@gmail.com>
2025-06-25 19:10:24 +05:30
Aaryan Khandelwal
0e91feacc3 [WIKI-74] fix: peek overview closing on escape key #7259 2025-06-25 19:09:54 +05:30
Prateek Shourya
40c0922726 [WEB-4387] fix: global layout when filter is set to list (#7264) 2025-06-24 20:25:26 +05:30
Aaryan Khandelwal
dee8f00a71 [WEB-4384] fix: power k page search redirection #7263 2025-06-24 20:24:35 +05:30
Aaryan Khandelwal
072f2e2cac [WEB-4363] regression: analytics tabs improvements #7260 2025-06-24 16:08:30 +05:30
Prateek Shourya
79c2dfd293 [WEB-4375] fix: minor issues in timeline layout (#7257) 2025-06-24 14:19:00 +05:30
JayashTripathy
22a9d48ca3 [WEB-4363]: Analytics tab improvements #7248
fix: padding in tabs
2025-06-24 14:17:40 +05:30
Vipin Chaudhary
fbcc8fc8a0 [WIKI-421] fix: Toolbar not reflecting strikethrough state (#7255)
* fix: strick through

* fix: bubble menu options types

---------

Co-authored-by: vipin chaudhary <vipinchaudhary@vipins-MacBook-Pro.local>
2025-06-24 14:16:07 +05:30
Aaryan Khandelwal
c1fa372c84 [WIKI-471] refactor: custom image extension (#7247)
* refactor: custom image extension

* refactor: extension config

* revert: image full screen component

* fix: undo operation
2025-06-24 14:05:11 +05:30
Prateek Shourya
7045a1f2af [WEB-4361] fix: add onChange to collaborative editor #7246 2025-06-20 17:24:49 +05:30
Prateek Shourya
f26b4d3d06 [WEB-4359] fix: application crash when creating work item via quick add (#7245) 2025-06-20 15:16:16 +05:30
Prateek Shourya
c3c1aef7a9 [WEB-4357] fix: remove trailing slash from asset url #7240 2025-06-19 19:09:59 +05:30
Vipin Chaudhary
24e57009af [WIKI-465] fix : Add new node on click of doc end (#7063)
* fix : handle last node

* fix : handle unexpected node

* remove logs

* feat: handle focus

---------

Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>
2025-06-19 17:17:56 +05:30
Anmol Singh Bhatia
2b7a17b484 [WEB-4050] feat: breadcrumbs revamp (#7188)
* chore: project feature enum added

* feat: revamp breadcrumb and add navigation dropdown component

* chore: custom search select component refactoring

* chore: breadcrumb stories added

* chore: switch label and breadcrumb link component refactor

* chore: project navigation helper function added

* chore: common breadcrumb component added

* chore: breadcrumb refactoring

* chore: code refactor

* chore: code refactor

* fix: build error

* fix: nprogress and button tooltip

* chore: code refactor

* chore: workspace view breadcrumb improvements

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

---------

Co-authored-by: vamsikrishnamathala <matalav55@gmail.com>
2025-06-19 17:17:14 +05:30
Vamsi Krishna
64fd0b2830 [WEB-4321]chore: workspace views refactor (#7214)
* chore: workspace views reafactor

* chore: resolved coderabbit suggestions

* chore: added project level workspace filter

* chore: added enum for roles

* chore: removed redundant type definition

* chore: optimised the query

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2025-06-19 16:26:32 +05:30
Aaryan Khandelwal
8988cf9a85 [WEB-462] refactor: editor props structure (#7233)
* refactor: editor props structure

* chore: add missing prop

* fix: space app build

* chore: export ce types
2025-06-19 16:25:52 +05:30
Aaryan Khandelwal
eb5ffebcc6 [WIKI-458] refactor: base page instance for additional properties (#7228)
* refactor: create a super class for base page

* fix: path

---------

Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
2025-06-19 16:00:18 +05:30
M. Palanikannan
414010688d [WIKI-384] chore: editor core refactor (#7235)
* fix: extra actions

* chore: page flags
2025-06-19 15:59:38 +05:30
JayashTripathy
171099667e [WEB-4339] fix: projects dropdown shows all projects (#7238)
* fix: projects drop only shows joined project

* refactor: removed unused things from header
2025-06-19 15:57:19 +05:30
Akshita Goyal
d65f0e264e [WEB-4327] Chore PAT permissions (#7224)
* chore: improved pat permissions

* fix: err message

* fix: removed permission from backend

* [WEB-4330] refactor: update API token endpoints to use user context instead of workspace slug

- Changed URL patterns for API token endpoints to use "users/api-tokens/" instead of "workspaces/<str:slug>/api-tokens/".
- Refactored ApiTokenEndpoint methods to remove workspace slug parameter and adjust database queries accordingly.
- Added new test cases for API token creation, retrieval, deletion, and updates, including support for bot users and minimal data submissions.

* fix: removed workspace slug from api-tokens

* fix: refactor

* chore: url.py code rabbit suggestion

* fix: APITokenService moved to package

---------

Co-authored-by: Dheeraj Kumar Ketireddy <dheeru0198@gmail.com>
Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-06-18 16:08:11 +05:30
Akshita Goyal
c7d17d00b7 [WEB-4017] fix: hooks and store refactoring for issue-details (#7107)
* fix: hooks and store splitting for issue-details

* fix: refactoring

* fix: refactoring

* fix: refactor

* fix: css
2025-06-18 15:59:26 +05:30
JayashTripathy
9cdfb2224a [WEB-4160]: Context menu close after clicking on menu item of project #7231 2025-06-18 15:33:06 +05:30
Sangeetha
8129f5f969 [WEB-4340] fix: duplicate assignees in user recents (#7216)
* fix: duplicate assignees in user recents

* chore: optimize filtering logic

* chore: filter with deleted_at field

* chore: tests for IssueRecentSerializer
2025-06-18 15:14:21 +05:30
Prateek Shourya
89b8cdbe6e [WEB-4335] improvement: optimize assignee grouping with improved member scope handling (#7227) 2025-06-17 17:17:04 +05:30
Prateek Shourya
53e6a62a12 fix: move lucide related constants to ui package (#7226)
* fix: move lucide related constants to ui package

* chore: update yarn.lock
2025-06-17 17:06:05 +05:30
Pratapa Lakshmi
59a682f6d9 fix: update Dockerfile for space application to correct static asset path 2025-06-17 15:58:43 +05:30
Pratapa Lakshmi
6fd448ddac refactor: update Dockerfile for space and web applications to correct asset paths and improve structure 2025-06-17 15:15:26 +05:30
Prateek Shourya
75f89c4c12 fix: docker build (#7220)
* fix: docker build

* fix: build
2025-06-17 14:08:50 +05:30
Pratapa Lakshmi
91c4047afd refactor: optimize Dockerfile for web and space applications by refining COPY commands for static assets 2025-06-17 12:47:00 +05:30
Anmol Singh Bhatia
0983e5f44d [WEB-4281] chore: project error message updated (#7190)
* chore: project error message updated

* fix: error message for project creation

* fix: incorrect error code

* chore: code refactor

* chore: code refactor

---------

Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
2025-06-16 17:19:44 +05:30
Prateek Shourya
2014400bed refactor: move web utils to packages (#7145)
* refactor: move web utils to packages

* fix: build and lint errors

* chore: update drag handle plugin

* chore: update table cell type to fix build errors

* fix: build errors

* chore: sync few changes

* fix: build errors

* chore: minor fixes related to duplicate assets imports

* fix: build errors

* chore: minor changes
2025-06-16 17:18:41 +05:30
sriram veeraghanta
dffcc6dc10 chore(deps): brace-expansion upgraded to 2.0.2 2025-06-16 17:10:08 +05:30
sriram veeraghanta
640b23fb1b chore(deps): nextjs upgrade to 14.2.30 2025-06-16 17:02:04 +05:30
JayashTripathy
e13d8aa4b3 [WEB-4231] Pie chart tooltip #7192 2025-06-16 14:03:07 +05:30
Prateek Shourya
cf595de7c7 [WEB-4311] fix: membership data handling and state reversal on error (#7205) 2025-06-16 14:02:47 +05:30
JayashTripathy
0fa9c8b015 [WEB-4323] refactor: Analytics refactor (#7213)
* chore: updated label for epics

* chore: improved export logic

* refactor: move csvConfig to export.ts and clean up export logic

* refactor: remove unused CSV export logic from WorkItemsInsightTable component

* refactor: streamline data handling in InsightTable component for improved rendering

* feat: add translation for "No. of {entity}" and update priority chart y-axis label to use new translation

* refactor: cleaned up some component and added utilitites

* feat: add "at_risk" translation to multiple languages in translations.json files

* refactor: update TrendPiece component to use new status variants for analytics

* fix: adjust TrendPiece component logic for on-track and off-track status

* refactor: use nullish coalescing operator for yAxis.dx in line and scatter charts

* feat: add "at_risk" translation to various languages in translations.json files

* feat: add "no_of" translation to various languages in translations.json files

* feat: update "at_risk" translation in Ukrainian, Vietnamese, and Chinese locales in translations.json files

* refactor: rename insightsFields to ANALYTICS_INSIGHTS_FIELDS and update analytics tab import to use getAnalyticsTabs function

* feat: update AnalyticsWrapper to use i18n for titles and add new translation for "no_of" in Russian

* fix: update yAxis labels and offsets in various charts to use new translation key and improve layout

* feat: define AnalyticsTab interface and refactor getAnalyticsTabs function for improved type safety

* fix: update AnalyticsTab interface to use TAnalyticsTabsBase for improved type safety

* fix: add whitespace-nowrap class to TableHead for improved header layout in DataTable component
2025-06-16 14:01:49 +05:30
Aaryan Khandelwal
6fe0415d66 [WEB-4316] chore: new endpoints to download an asset (#7207)
* chore: new endpoints to download an asset

* chore: add exception handling
2025-06-13 14:41:08 +05:30
sriram veeraghanta
ebc2bdcd3a feat: adding build process to logger package using tsup #7210 2025-06-13 01:50:44 +05:30
Aaron
11b222ece8 chore(deps): update TypeScript version across multiple packages to 5.8.3 (#7209) 2025-06-13 01:40:27 +05:30
JayashTripathy
c1a078ef3f [WEB-4246] Analytics minor improvements (#7194)
* chore: updated label for epics

* chore: improved export logic

* refactor: move csvConfig to export.ts and clean up export logic

* refactor: remove unused CSV export logic from WorkItemsInsightTable component

* refactor: streamline data handling in InsightTable component for improved rendering

* feat: add translation for "No. of {entity}" and update priority chart y-axis label to use new translation

* refactor: cleaned up some component and added utilitites

* feat: add "at_risk" translation to multiple languages in translations.json files

* refactor: update TrendPiece component to use new status variants for analytics

* fix: adjust TrendPiece component logic for on-track and off-track status

* refactor: use nullish coalescing operator for yAxis.dx in line and scatter charts

* feat: add "at_risk" translation to various languages in translations.json files

* feat: add "no_of" translation to various languages in translations.json files

* feat: update "at_risk" translation in Ukrainian, Vietnamese, and Chinese locales in translations.json files
2025-06-12 21:15:09 +05:30
Akshita Goyal
ad11a34efc [WEB-4236] fix: divided settings scroll for sidebar and main content (#7201)
* fix: divided settings scroll for sidebar and main content

* fix: handled icons

* fix: mobile css
2025-06-11 16:11:40 +05:30
Prateek Shourya
9c28db8b7b [WEB-4300] improvement: add allowedProjectIds to create work item modal (#7195) 2025-06-10 20:32:39 +05:30
dependabot[bot]
32d5fea3d3 chore(deps): bump requests (#7193)
Bumps the pip group with 1 update in the /apiserver/requirements directory: [requests](https://github.com/psf/requests).


Updates `requests` from 2.32.2 to 2.32.4
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.2...v2.32.4)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.4
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-10 17:39:48 +05:30
Prateek Shourya
6adc721b34 [WEB-4283] fix: update group key handling in issue store utilities for state groups (#7191)
* fix: update group key handling in issue store utilities for state groups

- Introduced a new function to determine the default group key based on the provided groupByKey.
- Updated references to use the new function for improved clarity and maintainability.
- Adjusted the mapping for "state_detail.group" in the ISSUE_GROUP_BY_KEY to ensure consistency.
- Enhanced the getArrayStringArray method to handle group values more effectively.

* refactor: clean up filters constants
2025-06-10 13:56:42 +05:30
Anmol Singh Bhatia
531748dcc3 [WEB-4288] fix: auth page tab index (#7189)
* fix: auth page tab index

* chore: code refactor
2025-06-10 01:47:59 +05:30
Sangmin Ahn
9965f48ba7 fix: prevent prematurely triggered Japanese label creation (#7084) 2025-06-09 16:07:42 +05:30
Saurabh Kumar
d15d7549f7 [SILO-303] Add external id and external source in project model #7182 2025-06-09 16:02:09 +05:30
Vamsi Krishna
8fcffd2338 [WEB-4196]fix: sub work item copy link message #7186 2025-06-09 15:46:57 +05:30
Vamsi Krishna
07e937cd8e [WEB-4094]chore: workspace notifications refactor (#7061)
* chore: workspace notifications refactor

* fix: url params

* fix: added null checks to avoid run time errors

* fix: notifications header color fix
2025-06-09 15:33:57 +05:30
Farahat Abdrabouh
1f1b421735 Docs: Correct numeric values in contributing guide #7184 2025-06-09 13:22:07 +05:30
sriram veeraghanta
5a43ec8411 chore: turbo repo version upgrade 2025-06-09 13:20:07 +05:30
sriram veeraghanta
c86e7e02bc chore: upgrade tar-fs package to fix vulnerabilities 2025-06-09 13:19:14 +05:30
sriram veeraghanta
d91d7a2f60 chore: tar-fs patch upgrade 2025-06-09 12:58:18 +05:30
sriram veeraghanta
b3b285b1e5 chore: upgrade django version to 4.2.22 2025-06-09 12:49:26 +05:30
Prateek Shourya
11debee402 fix: build errors related to project member list (#7185) 2025-06-09 00:31:27 +05:30
Vamsi Krishna
1608e4f122 [WEB-3374]feat: added merge date display (#7141)
* feat: added merge date display

* chore: moved formatter ti utils

* chore: removed unwanted props
2025-06-08 23:47:08 +05:30
Vamsi Krishna
edeeee1227 [WEB-4063]chore: updated work item email template (#7044)
* chore: updated work item email template

* chore: passed dynamic value for email template

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2025-06-08 23:46:12 +05:30
sriram veeraghanta
9ff238816b sync: canary changes to preview 2025-06-06 18:06:51 +05:30
sriram veeraghanta
6bd5caf008 chore: upgrade package version 2025-06-06 17:50:31 +05:30
sriram veeraghanta
c021aff58f chore: django version upgrade 2025-06-06 16:04:34 +05:30
sriram veeraghanta
683be55883 chore: upgrade nextjs version 2025-06-06 16:02:56 +05:30
Manish Gupta
970ce8cf26 [INFRA-183] feat: add restore-airgapped script to build workflow (#7170)
* [WEB-4260] chore: add restore-airgapped script to build workflow

* docs: update restore instructions in README for self-hosted and commercial air-gapped versions

* fix: update restore script filename and improve error handling in restore-airgapped script
2025-06-06 15:24:43 +05:30
Manish Gupta
cbbe1a4e4d refactor: Enhance backup and restore scripts for container data (#7055)
* refactor: enhance backup and restore scripts for container data management

* fix: ensure proper quoting in backup script to handle paths with spaces

* fix: ensure backup directory is only removed if tar command succeeds

* CodeRabbit fixes
2025-06-06 15:24:43 +05:30
Manish Gupta
6a74677cc9 fix: update API service startup check to use HTTP request instead of logs (#7054) 2025-06-06 15:24:43 +05:30
sriram veeraghanta
f6ea4f931d Merge branch 'canary' of github.com:makeplane/plane into preview 2025-06-06 15:23:10 +05:30
Aaryan Khandelwal
950fcfdb40 [WIKI-391] chore: handle deactivated user display name in version history #7171 2025-06-06 15:04:00 +05:30
Bavisetti Narayan
053c895120 [WEB 4252] chore: updated the favicon request for work item link (#7173)
* chore: added the favicon to link

* chore: added none validation for soup
2025-06-06 15:02:00 +05:30
Aaryan Khandelwal
245167e8aa refactor: unused components, hooks, constants (#7157)
* refactor: remove unused dashboard components and fetch keys

* refactor: remove unused hooks and wrappers

* chore: remove unused function
2025-06-06 14:09:56 +05:30
Vamsi Krishna
6be3f0ea73 [WEB-4208]chore: refactored work item quick actions (#7136)
* chore: refactored work item quick actions

* chore: update event handling for menu

* chore: reverted unwanted changes

* fix: update archive copy link

* chore: handled undefined function implementation
2025-06-06 13:21:00 +05:30
JayashTripathy
14d2d69120 [WEB-4230] refactor: Analytics code refacor, Removal of nivo charts dependencies and translations (#7131)
* chore: added code split for the analytics store

* chore: done some refactor

* refactor: update entity keys in analytics and translations

* chore: updated the translations

* refactor: simplify AnalyticsStoreV2 class by removing unnecessary constructor

* feat: add AnalyticsStoreV2 class and interface for enhanced analytics functionality

* feat: enhance WorkItemsModal and analytics store with isEpic functionality

* feat: integrate isEpic state into TotalInsights and WorkItemsModal components

* refactor: remove isEpic state from WorkItemsModalMainContent component

* refactor: removed old  analytics components and related services

* refactor: new analytics

* refactor: removed all nivo chart dependencies

* chore: resolved coderabbit comments

* fix: update processUrl to handle custom-work-items in peek view

* feat: implement CSV export functionality in InsightTable component

* feat: enhance analytics service with filter parameters and improve data handling in InsightTable

* feat: add new translation keys for various statuses across multiple languages

* [WEB-4246] fix: enhance analytics components to include 'isEpic' parameter for improved data fetching

* chore: update yarn.lock to remove deprecated @nivo packages and clean up unused dependencies
2025-06-06 01:53:38 +05:30
Anmol Singh Bhatia
570a9e319e [WEB-4257] chore: user profile setting options updated #7166 2025-06-06 01:47:31 +05:30
Anmol Singh Bhatia
469a027bb6 [WEB-4274] fix: metadata base url warning #7175 2025-06-05 22:51:56 +05:30
Prateek Shourya
8c99a7df88 [WEB-4273] fix: plans comparison scroll issue (#7176) 2025-06-05 22:51:05 +05:30
Prateek Shourya
f34f078bd2 [WEB-4272] fix: remove duplicate CommandPalette instances from settings layouts to prevent modal conflicts (#7174) 2025-06-05 20:48:36 +05:30
Anmol Singh Bhatia
0fe2549bc6 [WEB-4256] chore: add og image and update meta tags for social media compatibility (#7165)
* chore: og image added

* chore: meta config for cross-platform support
2025-06-05 19:32:11 +05:30
Prateek Shourya
118964de01 [WEB-4254] fix: ensure user details are available in project member details computation (#7162) 2025-06-05 19:31:07 +05:30
Manish Gupta
9f37f1ef0e [INFRA-183] feat: add restore-airgapped script to build workflow (#7170)
* [WEB-4260] chore: add restore-airgapped script to build workflow

* docs: update restore instructions in README for self-hosted and commercial air-gapped versions

* fix: update restore script filename and improve error handling in restore-airgapped script
2025-06-05 17:27:57 +05:30
Prateek Shourya
986f29d1f2 [WEB-4253] improvement: plan card enhancements (#7168)
* [WEB-4253] improvement: plan card enhancements

* improvement: pricing changes
2025-06-05 14:37:26 +05:30
Aaryan Khandelwal
1113f9fc19 [WIKI-412] regression: drop plugin logic #7161 2025-06-04 19:07:49 +05:30
Prateek Shourya
ef3ec7274c [WEB-4253] improvement: minor enhancements to billing page (#7160) 2025-06-04 17:29:45 +05:30
Akshita Goyal
a0a45b7916 [WEB-4249] fix: settings header css + cta on error page + project member list (#7159)
* fix: settings header css + cta on error page

* [WEB-4249] fix: filter out inactive workspace members from project member list

---------

Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
2025-06-04 16:38:35 +05:30
Aaryan Khandelwal
2792d48288 [WIKI-412] chore: improved rich text editor extensions handling (#7158)
* chore: code split for rich text editor extensions

* chore: update type

* chore: add missing prop
2025-06-04 15:32:54 +05:30
Anmol Singh Bhatia
b2ccca0567 [WEB-3931] chore: maintenance page ux copy (#7135)
* chore: maintenance ux copy translation added

* chore: maintenance ux copy updated

* chore: code refactor
2025-06-04 13:37:58 +05:30
Prateek Shourya
2e822b38e4 [WEB-4240] chore: bump local db version to 1.3 #7154 2025-06-04 13:01:29 +05:30
JayashTripathy
e570fe404f [WEB-4182] Fix work item links error messages (#7122)
* fix: backend error message toast when getting error

* fix: toast in small screens
2025-06-03 22:18:26 +05:30
Aaryan Khandelwal
48b613ae66 [WIKI-410] chore: editor translation files #7156 2025-06-03 22:13:56 +05:30
Prateek Shourya
e70105235b [WEB-4245] improvement: minor enhancements to project members settings page (#7153) 2025-06-03 15:09:54 +05:30
Nikhil
7766e8b5cf [WEB-3998]: clean up imports and remove cache decorators in workspace views to avoid stale data on browser cache #7150 2025-06-03 13:36:52 +05:30
Akshita Goyal
16d63abcdc [WEB-3998] fix: minor empty states changes + refactoring (#7151) 2025-06-02 15:50:57 +05:30
M. Palanikannan
0568b8d583 regression: building utils back to run live server (#7149) 2025-06-02 13:32:34 +05:30
Quang Hung Pham
64da29b0d9 chore: add select all/deselect all functionality when adding existing work item (#7045)
* chore: add select all/deselect all functionality

* chore: update button display logic by CR
2025-06-02 13:30:31 +05:30
Zero King
7c336a65c4 buid: add .venv to .dockerignore (#7146) 2025-05-31 12:32:25 +05:30
sriram veeraghanta
2242a85e5c chore: nextjs upgrade 2025-05-30 21:12:02 +05:30
Aaryan Khandelwal
323920a358 [WIKI-399] fix: add favorite action to page header #7144 2025-05-30 20:58:46 +05:30
Aaryan Khandelwal
151fc8389e [WIKI-181] chore: asset check endpoint added #7140 2025-05-30 20:58:06 +05:30
sriram veeraghanta
0f828fd5e0 chore: core component fixes 2025-05-30 20:57:35 +05:30
Prateek Shourya
67cbe94d4a [WEB-3964] refactor: permission layer (#7094)
* refactor: permission layer

* refactor: add original_role to project member serializer

* chore: minor fixes related to permission layer

* fix: strict type checking while checking user permissions
2025-05-30 19:57:07 +05:30
sriram veeraghanta
322af8c436 [WEB-4223] fix: remove build process from utils package #7138 2025-05-30 18:48:18 +05:30
Sangeetha
41c2aefad4 [WEB-3998] feat: settings page revamp (#6959)
* chore: return workspace name and logo in profile settings api

* chore: remove unwanted fields

* fix: backend

* feat: workspace settings

* feat: workspce settings + layouting

* feat: profile + workspace settings ui

* chore: project settings + refactoring

* routes

* fix: handled no project

* fix: css + build

* feat: profile settings internal screens upgrade

* fix: workspace settings internal screens

* fix: external scrolling allowed

* fix: css

* fix: css

* fix: css

* fix: preferences settings

* fix: css

* fix: mobile interface

* fix: profile redirections

* fix: dark theme

* fix: css

* fix: css

* feat: scroll

* fix: refactor

* fix: bug fixes

* fix: refactor

* fix: css

* fix: routes

* fix: first day of the week

* fix: scrolling

* fix: refactoring

* fix: project -> projects

* fix: refactoring

* fix: refactor

* fix: no authorized view consistency

* fix: folder structure

* fix: revert

* fix: handled redirections

* fix: scroll

* fix: deleted old routes

* fix: empty states

* fix: headings

* fix: settings description

* fix: build

---------

Co-authored-by: gakshita <akshitagoyal1516@gmail.com>
Co-authored-by: Akshita Goyal <36129505+gakshita@users.noreply.github.com>
2025-05-30 18:47:33 +05:30
sriram veeraghanta
445c819fbd [WEB-4172] feat: Crawl work item links for title and favicon (#7117)
* feat: added a python bg task to crawl work item links for title and description

* fix: return meta_data in the response

* fix: add validation for accessing IP ranges

* fix: remove json.dumps

* fix: handle exception by returning None

* refactor: call find_favicon_url inside fetch_and_encode_favicon function

* chore: type hints

* fix: Handle None

* fix: remove print statementsg

* chore: added favicon and title of links

* fix: return null if no title found

* Update apiserver/plane/bgtasks/work_item_link_task.py

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix: remove exception handling

* fix: reduce timeout seconds

* fix: handle timeout exception

* fix: remove request timeout handling

* feat: add Link icon to issue detail links and update rendering logic

* fix: use logger for exception

---------

Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
Co-authored-by: JayashTripathy <jayashtripathy371@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-05-30 18:44:53 +05:30
Aaryan Khandelwal
046a8a1bcf [WEB-4189] chore: add tailwind container-queries plugin #7125 2025-05-30 18:41:12 +05:30
Akshita Goyal
099a1cc12b [WEB-3863] fix: links error handling #7126 2025-05-30 18:24:01 +05:30
Sangeetha
a0a697401b [WEB-3787] fix: project joining date (#7127)
* fix: return project joining date

* fix: added project's joining date

* fix: set created_at as read_only_fields

---------

Co-authored-by: gakshita <akshitagoyal1516@gmail.com>
2025-05-30 18:23:19 +05:30
Aaryan Khandelwal
cb92108bf4 [WEB-4197] chore: auth forms semantics and accessibility #7128 2025-05-30 18:22:20 +05:30
Aaryan Khandelwal
01b685ea57 [WIKI-181] refactor: invalid file handling #7139 2025-05-30 18:18:05 +05:30
Vipin Chaudhary
b16a585102 [WIKI-343] [WIKI-312] Fix: html characters (#7049)
* fix: handle symbols and space

* chore: refactor
2025-05-30 18:17:03 +05:30
sriram veeraghanta
4a97d7c28c fix: adding url validations for workspace name and user name 2025-05-29 17:53:48 +05:30
Aaryan Khandelwal
141cb17e8a fix: Optimize image uploads in Editor (#7129)
* fix: memoize file upload functions

* chore: update extension name

* chore: update notation

* chore: resolve chokidar package

* fix: spelling mistakes
2025-05-28 19:03:14 +05:30
sriram veeraghanta
26b62c4a70 fix: tsup version 8.4.0 2025-05-28 02:17:23 +05:30
Aaryan Khandelwal
e388a9a279 [WIKI-181] refactor: file plugins and types (#7074)
* refactor: file plugins and types

* refactor: image extension storage types

* chore: update meta tag name

* chore: extension fileset storage key

* fix: build errors

* refactor: utility extension

* refactor: file plugins

* chore: remove standalone plugin extensions

* chore: refactoring out onCreate into a common utility

* refactor: work item embed extension

* chore: use extension enums

* fix: errors and warnings

* refactor: rename extension files

* fix: tsup reloading issue

* fix: image upload types and heading types

* fix: file plugin object reference

* fix: iseditable is hard coded

* fix: image extension names

* fix: collaborative editor editable value

* chore: add constants for editor meta as well

---------

Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
2025-05-28 01:43:01 +05:30
Aaryan Khandelwal
a3a580923c [WEB-4166] chore: projects app sidebar accessibility (#7115)
* chore: add ARIA attributes

* chore: add missing translations

* chore: add accessibility translations for multiple languages and configured store according to it

* chore: refactor translation file handling and introduce TranslationFiles enum

* fix: accessibility issues in workspace sidebar

---------

Co-authored-by: JayashTripathy <jayashtripathy371@gmail.com>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
2025-05-28 00:58:22 +05:30
Akshita Goyal
b4bc49971c [WEB-4130] fix: cycle charts minor optimizations (#7123) 2025-05-28 00:54:21 +05:30
dependabot[bot]
04c7c53e09 chore(deps): bump requests (#7120)
Bumps the pip group with 1 update in the /apiserver/requirements directory: [requests](https://github.com/psf/requests).


Updates `requests` from 2.31.0 to 2.32.2
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.31.0...v2.32.2)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.2
  dependency-type: direct:production
  dependency-group: pip
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-26 19:45:15 +05:30
Dheeraj Kumar Ketireddy
78cc32765b [WEB-3707] pytest based test suite for apiserver (#7010)
* pytest bases tests for apiserver

* Trimmed spaces

* Updated .gitignore for pytest local files
2025-05-26 15:26:26 +05:30
JayashTripathy
4e485d6402 [WEB-4160] fix: close the context menu after select #7113 2025-05-26 15:24:13 +05:30
JayashTripathy
5a208cb1b9 [WEB-2403] fix: alignment of project states in collapsed view #7114 2025-05-26 15:23:39 +05:30
JayashTripathy
0eafbb698a [WEB-3494] fix: size of created at value #7112 2025-05-26 15:22:16 +05:30
sriram veeraghanta
193ae9bfc8 fix: yarn lock file 2025-05-26 14:58:26 +05:30
Vamsi Krishna
7cb5a9120a [WEB-4173]fix: fixed layout overflow issue #7119 2025-05-26 14:28:56 +05:30
Vamsi Krishna
84fc81dd98 [WEB-4118]fix: adjusted sub work item properties for a better visibility (#7079)
* fix: adjusted sub work item properties for a better visibility

* fix: removed projects from sub work item filters
2025-05-23 16:14:35 +05:30
JayashTripathy
2d0c0c7f8a [WEB-4115] fix: update issue count status query to handle null values #7080 2025-05-23 16:13:48 +05:30
JayashTripathy
5c9bdb1cea [WEB-4133] fix: analytics release bugs (#7086)
* fix: header text of insight table search

* fix: made the active project list scrollable

* chore: added xAxis label to table header

* chore: removed the intake issues

* fix: made the headerText necessary

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
2025-05-23 16:13:09 +05:30
Aaron Heckmann
f8ca1e46b1 [WEB-4098] feat: noindex/nofollow (#7088)
* feat: noindex/nofollow

- On login: nofollow
- On app pages: noindex, nofollow

https://app.plane.so/plane/browse/WEB-4098/

- https://nextjs.org/docs/app/api-reference/file-conventions/layout
- https://nextjs.org/docs/app/building-your-application/routing/route-groups#creating-multiple-root-layouts
- https://nextjs.org/docs/app/api-reference/functions/generate-metadata#link-relpreload

* chore: address PR feedback
2025-05-23 16:12:04 +05:30
Vamsi Krishna
a3b9152a9b [WEB-4123]feat: language support for sub-work item empty states #7092 2025-05-23 15:36:47 +05:30
Aaryan Khandelwal
5223bd01e8 [WEB-4153] chore: extend custom font family in tailwind config (#7093)
* chore: remove unwanted font family

* chore: add font family to extend object
2025-05-23 15:35:47 +05:30
Aaryan Khandelwal
6eb0b5ddb0 [WEB-4137] chore: restrict SVG file selection (#7095)
* chore: update accepted file mime types

* chore: update accepted file mime types
2025-05-23 15:33:56 +05:30
Anmol Singh Bhatia
cd200169b6 [WEB-4107] chore: redirect user to the newly created project view after creation #7098 2025-05-23 15:32:41 +05:30
Nikhil
037bb88b53 [WEB-4144] fix: api logger to handle content decode errors #7099 2025-05-23 15:31:40 +05:30
Bavisetti Narayan
643390e723 [WEB-4145] chore: added validation for project deletion #7101 2025-05-23 15:30:42 +05:30
Aaryan Khandelwal
731c4e8fcd [WEB-4161] fix: eslint config for library config file #7103 2025-05-23 15:29:37 +05:30
Prateek Shourya
6216ad77f4 [WEB-4146] fix: AI environment variables configuration in GodMode (#7104)
* [WEB-4146] fix: artificial intelligence environment variables configuration

* chore: update llm configuration keys
2025-05-23 15:06:58 +05:30
Bavisetti Narayan
9812129ad3 [WEB-4133] chore: optimised the analytics endpoints (#7105)
* chore: optimised the analytics endpoints

* chore: segregated peek view endpoints

* chore: added analytics values validation

* chore: added project validation

* chore: reverted the changes

---------

Co-authored-by: JayashTripathy <jayashtripathy371@gmail.com>
2025-05-23 15:05:57 +05:30
JayashTripathy
5226b17f90 [WEB-4159] feat: add 'restricted_entity' translation key across multiple languages #7106 2025-05-23 15:05:37 +05:30
Vamsi Krishna
b376e5300a [WEB-3155]fix: email notification comments overflow #7110 2025-05-23 15:04:50 +05:30
Prateek Shourya
4460529b37 [WEB-4154] fix: dropdown container classname (#7085)
* fix: dropdown container classname

* improvement: update string utils for joinWithConjunction

* improvement: add more string utils
2025-05-23 13:53:16 +05:30
Nikhil
0a8cc24da5 chore: add validation fields in users (#7102)
* chore: add validation fields in users

* chore: make is email valid default value False
2025-05-21 20:34:52 +05:30
Sangeetha
2f4aa843fc [WEB-4122] fix: estimate in project export #7091 2025-05-20 12:56:30 +05:30
sriram veeraghanta
cfac8ce350 fix: ruff file formatting based on config file pyproject (#7082) 2025-05-19 17:34:46 +05:30
sriram veeraghanta
75a11ba31a fix: polynomial regular expression used on uncontrolled data (#7083)
* fix: polynomial regular expression used on uncontrolled data

* fix: optimize the function to handle both operations
2025-05-19 17:14:26 +05:30
sriram veeraghanta
1fc3709731 chore: Strict Null Check in Admin app (#7081)
* chore: upgrade to latest version of turbo repo

* fix: tsconfig changes

* chore: adding format script to package json

* fix: formatting of files
2025-05-19 16:25:46 +05:30
Akshita Goyal
7e21618762 [WEB-3461] fix: profile activity rendering issue (#7059)
* fix: profile activity

* fix: icon

* fix: handled conversion case

* fix: handled conversion case
2025-05-19 15:20:57 +05:30
Aaryan Khandelwal
2d475491e9 [WEB-4117] refactor: work item widgets code split (#7078)
* refactor: work item widget code split

* fix: types
2025-05-19 15:20:40 +05:30
Aaryan Khandelwal
2a2feaf88e [WIKI-181] chore: editor extension storage utility code split (#7071)
* chore: storage extension code split

* chore: use storage extension utility
2025-05-19 13:12:52 +05:30
Anmol Singh Bhatia
e48b2da623 [WEB-4056] fix: archived work item validation #7060 2025-05-18 15:28:47 +05:30
Anmol Singh Bhatia
9c9952a823 [WEB-3866] fix: work item attachment activity #7062 2025-05-18 15:28:00 +05:30
Akshita Goyal
906ce8b500 [WEB-4104] fix: project loading state #7065 2025-05-18 15:19:05 +05:30
Anmol Singh Bhatia
6c483fad2f [WEB-4041] chore: modal outside click behaviour #7072 2025-05-18 15:18:09 +05:30
Bavisetti Narayan
5b776392bd chore: revamped the analytics for cycle and module in peek view. (#7075)
* chore: added cycles and modules in analytics peek view

* chore: added cycles and modules analytics

* chore: added project filter for work items

* chore: added a peekview flag and based on that table columns

* chore: added peek view

* chore: added check for display name

* chore: cleaned up some code

* chore: fixed export csv data

* chore: added distinct work items

* chore: assignee in peek view

* updated csv fields

* chore: updated workitems peek with assignee

* fix: removed type assersions for workspaceslug

* chore: added day wise filter in cycles and modules

* chore: added extra validations

---------

Co-authored-by: JayashTripathy <jayashtripathy371@gmail.com>
2025-05-17 17:11:26 +05:30
Aaryan Khandelwal
ba158d5d6e [WEB-4109] chore: remove analytics duration filter (#7073)
* chore: remove analytics duration filter

* removed subtitle from title and date_filter from service call

* chore: removed the date filter

* bottom text of insight trend card

* chore: changed issue manager

* fix: limited items in table

* fix: removed unnecessary props from data-table

---------

Co-authored-by: JayashTripathy <jayashtripathy371@gmail.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2025-05-16 19:16:30 +05:30
JayashTripathy
084cc75726 [WEB-4092] fix:broken detailed empty state layout #7056 2025-05-14 18:01:36 +05:30
Nikhil
534f5c7dd0 [WEB-4088] fix: issue exports when cycles are not present (#7057)
* fix: issue exports when cycles are not present

* fix: type check
2025-05-14 18:00:49 +05:30
Manish Gupta
080cf70e3f refactor: Enhance backup and restore scripts for container data (#7055)
* refactor: enhance backup and restore scripts for container data management

* fix: ensure proper quoting in backup script to handle paths with spaces

* fix: ensure backup directory is only removed if tar command succeeds

* CodeRabbit fixes
2025-05-14 12:33:53 +05:30
Manish Gupta
4c3f7f27a5 fix: update API service startup check to use HTTP request instead of logs (#7054) 2025-05-14 10:02:21 +05:30
sriram veeraghanta
803f6cc62a chore: yarn lock file updates 2025-05-13 16:20:08 +05:30
Vamsi Krishna
3a6d0c11fb fix: set accordion to expand by default (#7053) 2025-05-13 16:18:13 +05:30
JayashTripathy
75d81f9e95 [WEB-3781] Analytics page enhancements (#7005)
* chore: analytics endpoint

* added anlytics v2

* updated status icons

* added area chart in workitems and en translations

* active projects

* chore: created analytics chart

* chore: validation errors

* improved radar-chart , added empty states , added projects summary

* chore: added a new graph in advance analytics

* integrated priority chart

* chore: added csv exporter

* added priority dropdown

* integrated created vs resolved chart

* custom x and y axis label in bar and area chart

* added wrapper styles to legends

* added filter components

* fixed temp data imports

* integrated filters in priority charts

* added label to priority chart and updated duration filter

* refactor

* reverted to void onchange

* fixed some contant exports

* fixed type issues

* fixed some type and build issues

* chore: updated the filtering logic for analytics

* updated default value to last_30_days

* percentage value whole number and added some rules for axis options

* fixed some translations

* added - custom tick for radar, calc of insight cards, filter labels

* chore: opitmised the analytics endpoint

* replace old analytics path with new , updated labels of insight card, done some store fixes

* chore: updated the export request

* Enhanced ProjectSelect to support multi-select, improved state management, and optimized data fetching and component structure.

* fix: round completion percentage calculation in ActiveProjectItem

* added empty states in project insights

* Added loader and empty state in created/resolved chart

* added loaders

* added icons in filters

* added custom colors in customised charts

* cleaned up some code

* added some responsiveness

* updated translations

* updated serrchbar for the table

* added work item modal in project analytics

* fixed some of the layput issues in the peek view

* chore: updated the base function for viewsets

* synced tab to url

* code cleanup

* chore: updated the export logic

* fixed project_ids filter

* added icon in projectdropdown

* updated export button position

* export csv and emptystates icons

* refactor

* code refactor

* updated loaders, moved color pallete to contants, added nullish collasece operator in neccessary places

* removed uneccessary cn

* fixed formatting issues

* fixed empty project_ids in payload

* improved null checks

* optimized charts

* modified relevant variables to observable.ref

* fixed the duration type

* optimized some code

* updated query key in project-insight

* updated query key in project-insight

* updated formatting

* chore: replaced analytics route with new one and done some optimizations

* removed the old analytics

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2025-05-12 20:50:33 +05:30
Aaryan Khandelwal
0d5c7c6653 [WEB-4051] regression: update font size of comment editor #7048 2025-05-12 19:47:44 +05:30
Anmol Singh Bhatia
079c3a3a99 [WEB-3978] chore: cmd k search result redirection improvements (#7012)
* fix: work item tab highlight

* chore: projectListOpen state and toggle method added to command palette store

* chore: openProjectAndScrollToSidebar helper function and highlight keyframes added

* chore: SidebarProjectsListItem updated

* chore: openProjectAndScrollToSidebar implementation

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor
2025-05-12 19:15:39 +05:30
Sangeetha
5f8d5ea388 [WEB-4054] chore: search-issues endpoint code refactoring (#7029)
* chore: moved some code to seperate function

* fix: function name typo
2025-05-12 19:14:10 +05:30
Anmol Singh Bhatia
8613a80b16 [WEB-3523] feat: start of week preference (#7033)
* chore: startOfWeek constant and types updated

* chore: startOfWeek updated in profile store

* chore: StartOfWeekPreference added to profile appearance settings

* chore: calendar layout startOfWeek implementation

* chore: date picker startOfWeek implementation

* chore: gantt layout startOfWeek implementation

* chore: code refactor

* chore: code refactor

* chore: code refactor
2025-05-12 19:13:39 +05:30
Aaryan Khandelwal
dc16f2862e [WIKI-181] refactor: make file handling generic in editor (#7046)
* refactor: make file handling generic

* fix: useeffect dependency array

* chore: remove mime type to extension conversion
2025-05-12 18:37:36 +05:30
Vamsi Krishna
e68d344410 [WEB-4074]fix: removed sub-work item filters at nested levels #7047 2025-05-12 18:21:05 +05:30
Aaron Heckmann
26c8cba322 [WEB-4008] fix: handle when settings are None #7016
https://app.plane.so/plane/browse/WEB-4008/
2025-05-12 13:16:30 +05:30
Bavisetti Narayan
b435ceedfc [WEB-3782] chore: analytics endpoints (#6973)
* chore: analytics endpoint

* chore: created analytics chart

* chore: validation errors

* chore: added a new graph in advance analytics

* chore: added csv exporter

* chore: updated the filtering logic for analytics

* chore: opitmised the analytics endpoint

* chore: updated the base function for viewsets

* chore: updated the export logic

* chore: added type hints

* chore: added type hints
2025-05-12 13:15:17 +05:30
Sangeetha
13c46e0fdf [WEB-3987] chore: project export funtionality enhancement (#7002)
* chore: comment details of work item

* chore: attachment count and attachment name

* chore: issue link and subscriber count

* chore: list of assignees

* chore: asset_url as attachment_links

* chore: code refactor

* fix: cannot export Excel

* chore: remove print statements

* fix: filtering in list

* chore: optimize attachment_count and attachment_link query

* chore: optimize fetching issue details for multiple select

* chore: use Prefetch to avoid duplicates
2025-05-09 21:09:13 +05:30
sriram veeraghanta
02bccb44d6 chore: adding robots txt file for not indexing the server 2025-05-09 21:07:24 +05:30
Surya Prashanth
b5634f5fa1 chore: add disable_auto_set_user flag on base model save method (#7041)
- when disable_auto_set_user flag is set, user fields like created_by
are derived from payload instead of crum
2025-05-09 21:05:05 +05:30
Aaryan Khandelwal
64aae0a2ac [WEB-4051] fix: comment editor list items font size #7034 2025-05-09 18:49:43 +05:30
Henit Chobisa
a263bfc01f chore: added external id and source to page model (#7040)
* chore: added external id and source to page model

* chore: added migration

* fix: added blank field
2025-05-09 17:23:49 +05:30
Anmol Singh Bhatia
50082f0843 [WEB-4002] fix: sidebar tab highlight (#7011)
* fix: work item tab highlight

* chore: code refactor

* chore: code refactor

* chore: code refactor
2025-05-09 16:53:51 +05:30
Prateek Shourya
30db59534d [WEB-3985] feat: common postcss config and local fonts across all plane applications (#6998)
* [WEB-3985] feat: common postcss config and local fonts across all plane applications

* improvement: split fonts into a separate exports
2025-05-09 14:26:29 +05:30
Vamsi Krishna
e401c9d6e4 [WEB-4028] feat: sub work item filters and grouping (#6997)
* feat: added filters for sub issues

* feat: added list groups for sub issues

* chore: updated order for sub work item properties

* feat: filters for sub work items

* feat: added filtering and ordering at frontend

* chore: reverted backend filters

* feat: added empty states

* chore: code improvemnt

---------

Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
2025-05-09 14:24:06 +05:30
Bavisetti Narayan
39b5736c83 [WEB-4057] chore: updated the logger for bgtasks #7025 2025-05-09 14:23:23 +05:30
Vamsi Krishna
2785419d12 [WEB-4052]fix: sub work item copy link (#7036)
* fix: sub work item copy link

* fix: copy url to clipboard
2025-05-09 14:22:34 +05:30
sriram veeraghanta
ac5b974d67 chore: Upgrade Django version to 4.2.21 2025-05-08 21:29:26 +05:30
Anmol Singh Bhatia
14ebaf0799 [WEB-3942] chore: intake url pattern (#7006)
* chore: intake url pattern updated

* chore: code refactor

* chore: removed unused components

---------

Co-authored-by: vamsikrishnamathala <matalav55@gmail.com>
2025-05-07 21:19:24 +05:30
Sangeetha
7cdb622663 [WEB-3930] chore: change source in-app to IN_APP #7008 2025-05-07 18:46:10 +05:30
JayashTripathy
855e4a3218 [WEB-4016] updated project and workitem form (#7019)
* updated project and workitem form

* added translation for other languages also

* Update packages/i18n/src/locales/zh-CN/translations.json

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-05-07 18:44:04 +05:30
Anmol Singh Bhatia
d456767492 [WEB-3955] chore: work item parent select modal params #7021 2025-05-07 18:41:28 +05:30
Bavisetti Narayan
6faff1d556 [WEB-3877] fix: changed logic to calculate cycle duration (#7024)
* chore: cycle running days

* chore: removed the module filter
2025-05-07 18:40:37 +05:30
Aaryan Khandelwal
bc2936dcd3 [WEB-3906] fix: page table of content overlap with the page content #7018 2025-05-07 00:51:51 +05:30
Aaryan Khandelwal
d366ac1581 [WEB-2508] fix: page favorite item title mutation (#7020)
* fix: remove page favorite item title fallback value

* refactor: use nullish coalescing operator
2025-05-07 00:28:43 +05:30
Nikhil
0a01e0eb41 [WEB-4013] chore: correct live url #7014 2025-05-06 01:21:53 +05:30
Nikhil
b4cc2d83fe [WEB-4014] fix: check access when duplicating pages #7015 2025-05-06 01:20:33 +05:30
Nikhil
42e2b787f0 [WEB-4013]chore: publish login and standardize urls in common settings (#7013)
* chore: handling base path and urls

* chore: uniformize urls in common settings

* correct live url

* chore: use url join to correctly join urls

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
2025-05-05 18:58:24 +05:30
Anmol Singh Bhatia
fbca9d9a7a [WEB-3996] fix: attachment icon rendering and added support for rar and zip icons (#7007)
* chore: zip and rar file icon

* chore: zip and rar file icon

* fix: attachment icon

* chore: application/x-rar type added

* fix: compressed file extensions

* chore: updated file upload extensions

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
2025-05-02 16:53:06 +05:30
Sangeetha
dbc00e4add [WEB-3992] chore: support for x-zip-compressed type #7001 2025-05-01 19:22:00 +05:30
Aaron Heckmann
28f9733d1b [WEB-3991] chore: local dev improvements (#6991)
* chore: local dev improvements

* chore: pr feedback

* chore: fix setup

* fix: env variables updated in .env.example files

* fix(local): sign in to admin and web

* chore: update minio deployment to create an bucket automatically on startup.

* chore: resolve merge conflict

* chore: updated api env with live base path

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2025-04-30 21:46:59 +05:30
Sangeetha
1e46290727 [WEB-3958] chore: allow members and admins to create api tokens (#6979)
* chore: allow members and admins to create api tokens

* chore: change permission for service api token
2025-04-30 19:51:04 +05:30
Anmol Singh Bhatia
5a1df8b496 [WEB-3560] chore: work item modal code refactor #6996 2025-04-30 14:56:38 +05:30
Anmol Singh Bhatia
f23a2f0780 [WEB-3973] chore: space app state icon size #6995 2025-04-29 20:13:55 +05:30
sriram veeraghanta
d10bb0b638 chore: yarn lock updates 2025-04-29 15:49:14 +05:30
sriram veeraghanta
c4ddff5419 chore: nextjs dependencies upgrade 2025-04-29 15:48:52 +05:30
sriram veeraghanta
10f5b4e9b8 fix: turbo repo upgrade 2025-04-29 15:34:12 +05:30
sriram veeraghanta
cdca5a4126 chore: build fixes 2025-04-29 15:33:03 +05:30
Vamsi Krishna
14dc6a56bc [WEB-3838]feat:sub work items sorting (#6967)
* refactor: sub-work items components, hooks and types

* feat: added orderby and display properties toggle for sub work items

* fix: build errors

* chore: removed issue type from filters

* chore: added null check

* fix: added null check

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2025-04-29 15:23:10 +05:30
Sangeetha
55340f9f48 [WEB-3957] chore: IntakeIssues with iexact 'in-app' changed to 'IN_APP' (#6977)
* migration: data with iexact 'in-app' changed to 'IN_APP'

* chore: add start_of_week field in profile

* chore: define variables for choices

* chore: merge migration files
2025-04-29 15:22:42 +05:30
Prateek Shourya
efa64fc4b8 [WEB-3968] improvement: added few missing translation keys #6993 2025-04-29 15:14:31 +05:30
Anmol Singh Bhatia
f5449c8f93 [WEB-3751] chore: work item state icon improvement (#6960)
* chore: return order based on group

* chore: order for workspace stats endpoint

* chore: state response updated

* chore: state icon types updated

* chore: state icon updated

* chore: state settings new icon implementation

* chore: icon implementation

* chore: code refactor

* chore: code refactor

* chore: code refactor

* fix: order field type

---------

Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
2025-04-29 14:33:53 +05:30
Bavisetti Narayan
baabb82669 [WEB-3926] chore: removed the duplicated webhook task and updated the webhook task to handle exceptions correctly (#6951)
* chore: removed the duplicated webhook function

* chore: update webhook send task to handle errors

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2025-04-29 14:04:00 +05:30
Nikhil
298e3dc9ca [WEB-3945] chore: update workspace onboarding to add default project (#6964)
* chore: add json files and initial job to push data to workspace

* chore: update seed data location

* chore: update seed data to use assets from static urls

* chore: update seed data to use updated labels

* chore: add logging and update label name

* chore: add created_by for project member

* chore: add created_by_id for issue user property

* chore: add workspace seed task logs

* chore: update log message to return task name

* chore: add warning log for workspace seed task

* chore: add validation for issue seed data
2025-04-29 14:01:22 +05:30
Bavisetti Narayan
190300bc6c [WEB-3877] chore: changed the logic to end cycle (#6971)
* chore: changed the logic to end cycle

* chore: added issue deleted filter

* chore: added check for progress snapshot
2025-04-29 14:00:54 +05:30
Dheeraj Kumar Ketireddy
550fe547e2 [WEB-3967] feat: Optimized module patch endpoint to reduce duplicate db calls (#6983) 2025-04-29 13:51:46 +05:30
sriram veeraghanta
461e099bbc release: v0.26.0 #6962 2025-04-28 18:24:37 +05:30
Akshat Jain
f278a284c4 chore: comment out APP_RELEASE variable update in build-branch workflow (#6989) 2025-04-28 17:45:44 +05:30
sriram veeraghanta
2bcf6c76cd chore: remove dockerhub user varible from compose 2025-04-28 16:28:48 +05:30
Akshat Jain
fb3e022042 [INFRA-134] fix: Setup and Swarm scripts for DOCKERHUB_USERNAME #6988 2025-04-28 14:37:51 +05:30
Akshat Jain
e3fbb7b073 [INFRA-134]: Update Docker images to use new artifact repository path #6978 2025-04-25 18:09:43 +05:30
Anmol Singh Bhatia
cce6dd581c [WEB-3948] chore: recent work item improvement (#6976)
* chore: issue entity data type updated

* chore: HomePeekOverviewsRoot component added

* chore: recent work item improvement and code refactor
2025-04-25 15:08:10 +05:30
Akshita Goyal
d86ac368a4 [WEB-3863] fix: handled error handling for link editing #6968 2025-04-25 14:31:35 +05:30
Akshita Goyal
101994840a [WEB-3944] fix: Error Toast message content update while uploading images (#6969)
* fix: handled svg uploads

* chore: proper error message with all allowed types

---------

Co-authored-by: sangeethailango <sangeethailango21@gmail.com>
2025-04-25 14:30:12 +05:30
Anmol Singh Bhatia
f60f57ef11 [WEB-3494] chore: platform ux copy changes (#6970)
* chore: project quick action option ux copy updated

* chore: project tour copy updated
2025-04-25 14:29:09 +05:30
Prateek Shourya
546217f09b [WEB-3953] fix: issue description assets upload when project id is switched (#6975) 2025-04-25 14:27:40 +05:30
sriram veeraghanta
6df8323665 fix: add gzip upload support 2025-04-24 17:50:37 +05:30
Sangeetha
77d022df71 [WEB-3919] chore: support .sql file attachment #6966 2025-04-24 17:39:16 +05:30
M. Palanikannan
797f150ec4 [WIKI-331] fix: editor ref issues while locking/unlocking page #6965 2025-04-24 17:38:41 +05:30
sriram veeraghanta
b54f54999e chore: bump up the package version 2025-04-24 17:37:50 +05:30
Sangeetha
dff176be8f [WEB-3930] chore: set IN_APP as default source value for intake issue (#6963)
* chore: chore: only allow intake issues with source IN_APP to be created

* chore: set IN_APP as default intake issue
2025-04-24 16:25:15 +05:30
Sangeetha
2bbaaed3ea [WEB-3918] fix: api tokens is_active (#6941)
* fix: is_active always returning true
chore: formate expired_at to iso date

* Display exact expiration timestamp for API tokens

* chore: remove conversion to iso

* chore: remove unwanted imports

* fix: added timestamp for api token expiry

* fix: handle none value in expired_at

* fix: fix: handle none value in expired_at

* chore: add type hints

* fix: refactor

---------

Co-authored-by: Alaaeddine bousselmi <alaaeddine.bousselmi@medtech.tn>
Co-authored-by: gakshita <akshitagoyal1516@gmail.com>
Co-authored-by: Akshita Goyal <36129505+gakshita@users.noreply.github.com>
2025-04-24 01:28:29 +05:30
Prateek Shourya
b5ceb94fb2 [WEB-3930] fix: application crash on accessing intake work items (#6958) 2025-04-23 15:12:54 +05:30
alaabousselmi
feb6243065 docs: document minimum RAM requirement and issue naming conventions (#6954) 2025-04-22 18:00:19 +05:30
Anmol Singh Bhatia
5dacba74c9 [WEB-3923] fix: applied filters list #6957 2025-04-22 17:58:16 +05:30
bIaO
0efb0c239c feat: improve setup.sh script with better error handling and user feedback (#6758) 2025-04-22 17:56:34 +05:30
Vamsi Krishna
c8be836d6c [WEB-3920]fix: estimate activity #6950 2025-04-22 17:45:15 +05:30
Nikhil
833b82e247 [WEB-3927] chore: add logging to support json logging (#6955)
* chore: update logging to json based logging

* chore: add logging to file
2025-04-22 17:41:58 +05:30
Akshita Goyal
280aa7f671 [WEB-3399] fix: progress data for cycle list item #6956 2025-04-22 17:41:06 +05:30
Aaryan Khandelwal
eac1115566 [WIKI-320] refactor: page header actions (#6946)
* refactor: page header actions

* chore: update toolbar component

* chore: update archived and lock badge colors

* chore: added observer to favorite control
2025-04-17 20:52:33 +05:30
sriram veeraghanta
8166a757a7 fix: removed @plane alias from ui package 2025-04-17 20:51:52 +05:30
Anmol Singh Bhatia
be5d77d978 [WEB-3892] chore: link item improvements (#6944)
* chore: code refactor

* chore: global link block component added

* chore: link item improvement and code refactor
2025-04-17 20:08:53 +05:30
Anmol Singh Bhatia
18fb3b8450 [WEB-3904] fix: sub work item fetching #6945 2025-04-17 20:07:13 +05:30
sriram veeraghanta
ef5616905e chore: upgrade turbo repo version 2025-04-17 17:51:59 +05:30
Sangeetha
aeb41e603c [WEB-3826] feat: estimate activitites #6937 2025-04-17 17:16:57 +05:30
Vamsi Krishna
55eea1a8b7 [WEB-3872]chore: header switcher enhancements (#6935)
* * chore: alignment and size for header
* fix: switcher close on click

* chore: moved acces icon component to components
2025-04-17 17:15:53 +05:30
Aaryan Khandelwal
fa87ff14b7 [WIKI-319] chore: remove bottom border when toolbar is hidden (#6943)
* chore: remove border when toolbar is hidden

* chore: add stricter conditions
2025-04-17 17:13:21 +05:30
khalilzitouni2058
7d91b5f8df [WEB-3892] feat: add icon to Quicklinks (#6927)
* [feature]: add icon to Quicklinks

* fix: moving  getIconForLink to utils packages
2025-04-17 17:11:57 +05:30
Anmol Singh Bhatia
3ce40dfa2f [WIKI-316] fix: list item overflow #6942 2025-04-17 17:08:13 +05:30
Anmol Singh Bhatia
f65253c994 [WEB-2561] chore: favicon icon updated #6938 (#6940)
* chore: favicon icon updated

* chore: code refactor
2025-04-17 15:38:42 +05:30
Anmol Singh Bhatia
97fcfaa653 [WEB-2561] chore: favicon icon updated #6938 2025-04-16 20:34:12 +05:30
Anmol Singh Bhatia
0e1ebff978 [WEB-3871] fix: sidebar label property #6934 2025-04-15 19:42:02 +05:30
Anmol Singh Bhatia
642dabfe35 [WEB-3870] fix: sidebar comment scroll #6932 2025-04-15 17:47:22 +05:30
Aaryan Khandelwal
48557cb670 [WEB-3868] fix: issue detail widget modals #6933 2025-04-15 17:46:45 +05:30
Bavisetti Narayan
608da1465c [WEB-3860] chore: added deleted filter in the grouper (#6931)
* chore: added deleted filter in the grouper

* chore: added type hints for the function
2025-04-15 17:42:45 +05:30
Anmol Singh Bhatia
dbcc7bedb4 [WEB-3855] feat: Turkish language support (#6922)
* add Turkish language support (#6874)

* add turkish language support

* fix indentation

* chore: extended core translation added

* chore: code refactor

---------

Co-authored-by: Farahat Abdrabouh <88924701+fasdjkherig@users.noreply.github.com>
2025-04-15 16:36:02 +05:30
Vamsi Krishna
c401b26dd4 [WEB-3856]chore: refactor work item activity (#6923)
* chore: refactor work item activity

* chore: added estimate render for notifications
2025-04-15 16:35:28 +05:30
Aaryan Khandelwal
a4bca0c39c [WEB-3859] fix: work item links #6930 2025-04-15 13:46:29 +05:30
Saurabh Kumar
24899887b2 chore: Add workspace slug to should render setting link method (#6886)
* add workspace slug to setting link function

* add params in the function
2025-04-14 17:41:47 +05:30
sriram veeraghanta
c6953ff878 fix: db modeling changes in pages 2025-04-12 16:22:13 +05:30
Prateek Shourya
06be9ab81b [WEB-3854] feat: billing and plans new design (#6920)
* [WEB-3854] feat: billing and plans new design

* chore: add missing styles
2025-04-11 20:37:25 +05:30
Akshita Goyal
ed8d00acb1 [WEB-3849] chore: added intake source in the list (#6919)
* chore: added intake source in the list

* fix: refactor
2025-04-11 19:49:35 +05:30
Aaryan Khandelwal
915e374485 [WIKI-307]chore: update page icon placement #6916 2025-04-11 18:07:03 +05:30
Vamsi Krishna
1d5b93cebd [WEB-3853] fix: untitled page name issue #6918 2025-04-11 18:06:26 +05:30
sriram veeraghanta
df65b8c34a fix: adding request logger middleware 2025-04-11 17:59:19 +05:30
Akshita Goyal
4c688b1d25 [WEB-3529] fix: fixed the comment create box position in common comments component (#6915) 2025-04-11 14:00:54 +05:30
Nikhil
bfc6ed839f fix: uuid validation, status and webhook errors (#6896)
* fix: uuid validation and function parameter handling for external apis

* chore: update status 410 Gone to 409 conflicts

* chore: add webhook trigger for issue created through apis

* chore: remove pks from post

* chore: remove issue id from module post
2025-04-11 01:47:00 +05:30
Surya Prashanth
b68396a4b2 [WEB-3831] chore: add validation for project_id in cycle serializer #6908 2025-04-11 01:42:53 +05:30
Vamsi Krishna
b4fc715aba [WEB-3826] fix: estimate dropdown formatting (#6906)
* * fix: time conversion for estimate dropdown in browse
* chore: updated puncutations for estimates.

* chore: estimate activiy formatting

* chore: estimate activity refactor
2025-04-11 01:41:43 +05:30
Anmol Singh Bhatia
33a1b916cb [WEB-3837] fix: mutation of child work item added via Cmd+K with parent context #6910 2025-04-11 01:40:29 +05:30
Akshita Goyal
2818310619 [WEB-3529] fix: comment reset + edit comment font size + comment box position (#6909)
* fix: comment reset + edit comment font size

* fix: dynamically setting the position of the comment box

* fix: refactor

* fix: nomenclature
2025-04-11 01:40:05 +05:30
Anmol Singh Bhatia
882520b3c7 [WEB-3841] fix: create issue modal now correctly uses current project context #6911 2025-04-11 01:35:27 +05:30
Aaryan Khandelwal
20132e7544 [WEB-3839] fix: peek overview description version history (#6912)
* fix: handle undefined created_at

* chore: add created_by, updated_by updated_at and created_at fields in
relation apis

* chore: handle undefined date

* fix: project typo

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2025-04-10 16:22:26 +05:30
Aaryan Khandelwal
0ae57b49d2 [WEB-3829]fix: update workspace store action (#6905) 2025-04-09 20:31:52 +05:30
M. Palanikannan
d347269afb [WEB-3819] fix: images now restore in read only mode as well (#6904) 2025-04-09 20:06:15 +05:30
Aaryan Khandelwal
a3fd616ec4 [WEB-3827] refactor: work item widget components (#6902) 2025-04-09 19:58:16 +05:30
Akshita Goyal
9eeff158d5 [WEB-3811] fix: cycle charts issues (#6901) 2025-04-09 19:57:47 +05:30
Aaryan Khandelwal
ef20b5814e [WEB-3792, 3823] fix: intake form version history (#6898)
* chore: intake form version history

* fix: remove autofocus from the copy markdown button

* chore: add logic to display deactivated user
2025-04-09 19:56:59 +05:30
Vamsi Krishna
14914e8716 [WEB-3759]chore: updated module and pages detail header (#6903)
* chore: added panel collapse and quick action menu for module detail header

* fix: updated pages header swithcer
2025-04-09 19:36:15 +05:30
Vamsi Krishna
b738e39a4a [WEB-3798]chore: updated language support to estimates (#6900) 2025-04-09 19:34:01 +05:30
Vamsi Krishna
993c7899b6 [WEB-3759] chore: header revamp for cycles, modules, pages and views (#6875)
* chore: header revamp for cycles, modules, pages and views

* chore: moved list fetch to layout level
2025-04-09 14:56:57 +05:30
Vipin Chaudhary
2b411de1e3 [WIKI-306] fix: handle editor click behavior on the last node #6879 2025-04-09 14:51:58 +05:30
Prateek Shourya
1f9222065e [WEB-3788] improvement: enhance project properties related components modularity (#6882)
* improvement: work item modal data preload and parent work item details

* improvement: collapsible button title

* improvement: project creation form and modal

* improvement: emoji helper

* improvement: enhance labels component modularity

* improvement: enable state group and state list components modularity

* improvement: project settings feature list

* improvement: common utils
2025-04-09 14:50:43 +05:30
Akshita Goyal
670134562f [WEB-3808] fix: replaced the profile charts with propel components #6892 2025-04-09 14:50:23 +05:30
Akshita Goyal
144c793e9e [WEB-3803] fix: duplicate comments issue (#6893)
* fix: duplicate comments issue

* fix: refactor
2025-04-09 14:49:54 +05:30
Anmol Singh Bhatia
0a924e4824 [WEB-3693] chore: cmd-k work item actions improvements (#6891) 2025-04-09 09:25:57 +05:30
Aaryan Khandelwal
08702a5381 [WEB-3766] fix: user avatar in description version history dropdown item (#6888)
* fix: avatar url

* chore: update version modal width
2025-04-08 18:05:14 +05:30
sriram veeraghanta
270f282c3c fix: copy url util build error 2025-04-08 15:44:07 +05:30
Aaryan Khandelwal
37699362ad [WEB-3797] fix: remove leading slash from URL to copy (#6890)
* fix: remove prefix slash if present

* chore: make use of URL class to generate a valid URL
2025-04-08 15:22:23 +05:30
Vamsi Krishna
27cec64c56 [WEB-3794]chore: set project states to expand by default #6885 2025-04-08 14:38:08 +05:30
Akshita Goyal
782b09eeaf [WEB-3711] fix: relations delete issue (#6887)
* fix: relations delete issue

* fix: removed unnecessary type casting
2025-04-08 14:37:00 +05:30
Akshita Goyal
5ac5892fe5 [WEB-3586] fix: recents dropdown in home #6889 2025-04-08 14:32:08 +05:30
Bavisetti Narayan
96c403ff0b chore: changed inbox to intake (#6884) 2025-04-08 12:46:20 +05:30
Nikhil
543552f492 [WEB-3786] fix: issue date update when converting when dates are passed as string for comparison #6880
for comparison
2025-04-07 19:08:19 +05:30
Akshita Goyal
c3cfcc1b92 [WEB-3753] fix: font size for comment box changed #6881 2025-04-07 19:06:04 +05:30
Anmol Singh Bhatia
ac84d6ecf0 [WEB-3540] chore: icon color picker enhancements #6878 2025-04-07 15:53:02 +05:30
Vamsi Krishna
475b7a8396 [WEB-3737]chore: updated translations for estimates #6871 2025-04-07 15:50:15 +05:30
Nikhil
00f78bd6a1 [WEB-3728] fix: duplicate sequence ids being generated due to race condition (#6877)
* fix: race condition which is creating duplicate sequence ids

* chore: add management command to fix duplicate sequences

* chore: update command to take a lock and optimize the script to use dict
instead of loops

* chore: update the script to use transaction
2025-04-07 15:48:43 +05:30
Aaryan Khandelwal
34337f90c1 [WEB-3748, 3749] feat: work item description version history (#6863)
* chore: work item description versions

* chore: intake issue description

* chore: intake work item description versions

* chore: add missing translations

* chore: endpoint for intake description version

* chore: renamed key to work item

* chore: changed the paginator class

* chore: authorization added

* chore: added the enum validation

* chore: removed extra validations

* chore: added extra validations

* chore: modal position

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com>
2025-04-04 20:09:02 +05:30
Prateek Shourya
4f68aaafa6 fix: web build (#6870) 2025-04-04 20:07:12 +05:30
Vamsi Krishna
9c10235fca [WEB-3737]chore: estimates code refactor and translations (#6857)
* * chore: refactored estimates components.
* chore: added translations for estimates components.

* fix: translation key update
2025-04-04 16:59:12 +05:30
Lorenzo Palaia
9c1b158291 feat: hide create account button on ENABLE_SIGNUP=0 (#6841) 2025-04-04 16:52:59 +05:30
Prateek Shourya
2d0a15efd6 [WEB-3762] improvement: redirect logged in user to the workspace after accepting the invitation (#6869) 2025-04-04 16:52:09 +05:30
sriram veeraghanta
45e25ce18b release: v0.25.3 #6788 2025-03-21 17:26:55 +05:30
sriram veeraghanta
4d88dbaf49 release: v0.25.2 (#6736) 2025-03-11 16:01:20 +05:30
sriram veeraghanta
e61ff879c4 release: v0.25.1
* fix: issue activity for project id validation (#6668)

* fix: work item attachment count mutation (#6670)

* updated the action to modify the release build assets (#6669)

* feat: russian translation (#6666)

* chore: ru translation updated (#6672)

* fix: state drop down refactor

* fix: intake work item creation refactor

* fix: cleanup for deprecated functions

* fix: date range picker on cycles and modules list (#6676)

* fix: Handled workspace switcher closing on click

* fix: replaced date range picker with date picker at some places

* chore: add common translation keys (#6688)

* chore: add missing translation keys

* chore: add russian translation keys

* fix: issue activity task (#6689)

* changed github workflow action ubuntu version to `ubuntu-22.04` (#6683)

* chore: update russian translation (#6682)

* chore: update russian translation

* chore: rename issues to work items in russian translation

* [PE-275] chore: editor line spacing variables (#6678)

* chore: variable editor line spacing

* chore: variable list spacing

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>

* [WEB-3475] fix: cycle dates dropdown (#6690)

* fix: Handled workspace switcher closing on click

* fix: Cycle date picker

* fix: Made onSelect optional in range range component

* fix: module date picker (#6691)

* fix: Handled workspace switcher closing on click

* fix: reverted module date picker changes

* chore: extended sidebar improvement (#6693)

* feat: italian translations (#6692)

* Create translations.json - ITALIAN translation (#6667)

* chore: italian translation updated

* feat: italian translation added

* fix: module end date translation

---------

Co-authored-by: Nicolas Bossi <nicolasbossi@gmail.com>
Co-authored-by: gakshita <akshitagoyal1516@gmail.com>

* fix: attachment item created by (#6695)

* fix: module flicker issue on property updation (#6699)

* [WEB-3477] fix: mutation issue on moving work items for a manually ended cycle (#6696)

* fix: package version update

* fix: esbuild version fix

* fix: package license repliation

* [WEB-3488] improvement: assignee validation for work item creation (#6701)

* fix: work item assignee update validation (#6704)

---------

Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: Manish Gupta <59428681+mguptahub@users.noreply.github.com>
Co-authored-by: Nikita Mitasov <32384814+ch4og@users.noreply.github.com>
Co-authored-by: Akshita Goyal <36129505+gakshita@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: Akshat Jain <akshatjain9782@gmail.com>
Co-authored-by: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: Nicolas Bossi <nicolasbossi@gmail.com>
Co-authored-by: gakshita <akshitagoyal1516@gmail.com>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
2025-03-05 19:15:33 +05:30
sriram veeraghanta
adeb7d977d Merge pull request #6665 from makeplane/canary
fix: package version update
2025-02-24 20:40:25 +05:30
4191 changed files with 53035 additions and 32546 deletions

View File

@@ -2,6 +2,7 @@
*.pyc
.env
venv
.venv
node_modules/
**/node_modules/
npm-debug.log
@@ -14,4 +15,4 @@ build/
out/
**/out/
dist/
**/dist/
**/dist/

View File

@@ -133,7 +133,7 @@ jobs:
docker-image-owner: makeplane
docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_admin }}
build-context: .
dockerfile-path: ./admin/Dockerfile.admin
dockerfile-path: ./apps/admin/Dockerfile.admin
buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }}
buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }}
buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }}
@@ -155,7 +155,7 @@ jobs:
docker-image-owner: makeplane
docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_web }}
build-context: .
dockerfile-path: ./web/Dockerfile.web
dockerfile-path: ./apps/web/Dockerfile.web
buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }}
buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }}
buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }}
@@ -177,7 +177,7 @@ jobs:
docker-image-owner: makeplane
docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_space }}
build-context: .
dockerfile-path: ./space/Dockerfile.space
dockerfile-path: ./apps/space/Dockerfile.space
buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }}
buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }}
buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }}
@@ -199,13 +199,13 @@ jobs:
docker-image-owner: makeplane
docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_live }}
build-context: .
dockerfile-path: ./live/Dockerfile.live
dockerfile-path: ./apps/live/Dockerfile.live
buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }}
buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }}
buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }}
buildx-endpoint: ${{ needs.branch_build_setup.outputs.gh_buildx_endpoint }}
branch_build_push_apiserver:
branch_build_push_api:
name: Build-Push API Server Docker Image
runs-on: ubuntu-22.04
needs: [branch_build_setup]
@@ -220,8 +220,8 @@ jobs:
dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
docker-image-owner: makeplane
docker-image-name: ${{ needs.branch_build_setup.outputs.dh_img_backend }}
build-context: ./apiserver
dockerfile-path: ./apiserver/Dockerfile.api
build-context: ./apps/api
dockerfile-path: ./apps/api/Dockerfile.api
buildx-driver: ${{ needs.branch_build_setup.outputs.gh_buildx_driver }}
buildx-version: ${{ needs.branch_build_setup.outputs.gh_buildx_version }}
buildx-platforms: ${{ needs.branch_build_setup.outputs.gh_buildx_platforms }}
@@ -260,7 +260,7 @@ jobs:
branch_build_push_web,
branch_build_push_space,
branch_build_push_live,
branch_build_push_apiserver,
branch_build_push_api,
branch_build_push_proxy,
]
env:
@@ -273,7 +273,7 @@ jobs:
run: |
cp ./deploy/selfhost/install.sh deploy/selfhost/setup.sh
sed -i 's/${APP_RELEASE:-stable}/${APP_RELEASE:-'${REL_VERSION}'}/g' deploy/selfhost/docker-compose.yml
sed -i 's/APP_RELEASE=stable/APP_RELEASE='${REL_VERSION}'/g' deploy/selfhost/variables.env
# sed -i 's/APP_RELEASE=stable/APP_RELEASE='${REL_VERSION}'/g' deploy/selfhost/variables.env
- name: Create Release
id: create_release
@@ -290,5 +290,6 @@ jobs:
${{ github.workspace }}/deploy/selfhost/setup.sh
${{ github.workspace }}/deploy/selfhost/swarm.sh
${{ github.workspace }}/deploy/selfhost/restore.sh
${{ github.workspace }}/deploy/selfhost/restore-airgapped.sh
${{ github.workspace }}/deploy/selfhost/docker-compose.yml
${{ github.workspace }}/deploy/selfhost/variables.env

View File

@@ -6,7 +6,7 @@ on:
types: ["opened", "synchronize", "ready_for_review"]
jobs:
lint-apiserver:
lint-server:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
@@ -17,10 +17,10 @@ jobs:
python-version: "3.x" # Specify the Python version you need
- name: Install Pylint
run: python -m pip install ruff
- name: Install Apiserver Dependencies
run: cd apiserver && pip install -r requirements.txt
- name: Lint apiserver
run: ruff check --fix apiserver
- name: Install Server Dependencies
run: cd apps/server && pip install -r requirements.txt
- name: Lint apps/server
run: ruff check --fix apps/server
lint-admin:
if: github.event.pull_request.draft == false

3
.gitignore vendored
View File

@@ -1,5 +1,6 @@
node_modules
.next
.yarn
### NextJS ###
# Dependencies
@@ -52,6 +53,8 @@ mediafiles
.env
.DS_Store
logs/
htmlcov/
.coverage
node_modules/
assets/dist/

1
.yarnrc.yml Normal file
View File

@@ -0,0 +1 @@
nodeLinker: node-modules

View File

@@ -15,20 +15,40 @@ Without said minimal reproduction, we won't be able to investigate all [issues](
You can open a new issue with this [issue form](https://github.com/makeplane/plane/issues/new).
### Naming conventions for issues
When opening a new issue, please use a clear and concise title that follows this format:
- For bugs: `🐛 Bug: [short description]`
- For features: `🚀 Feature: [short description]`
- For improvements: `🛠️ Improvement: [short description]`
- For documentation: `📘 Docs: [short description]`
**Examples:**
- `🐛 Bug: API token expiry time not saving correctly`
- `📘 Docs: Clarify RAM requirement for local setup`
- `🚀 Feature: Allow custom time selection for token expiration`
This helps us triage and manage issues more efficiently.
## Projects setup and Architecture
### Requirements
- Node.js version v16.18.0
- Docker Engine installed and running
- Node.js version 20+ [LTS version](https://nodejs.org/en/about/previous-releases)
- Python version 3.8+
- Postgres version v14
- Redis version v6.2.7
- **Memory**: Minimum **12 GB RAM** recommended
> ⚠️ Running the project on a system with only 8 GB RAM may lead to setup failures or memory crashes (especially during Docker container build/start or dependency install). Use cloud environments like GitHub Codespaces or upgrade local RAM if possible.
### Setup the project
The project is a monorepo, with backend api and frontend in a single repo.
The backend is a django project which is kept inside apiserver
The backend is a django project which is kept inside apps/api
1. Clone the repo
@@ -50,6 +70,17 @@ chmod +x setup.sh
docker compose -f docker-compose-local.yml up
```
4. Start web apps:
```bash
yarn dev
```
5. Open your browser to http://localhost:3001/god-mode/ and register yourself as instance admin
6. Open up your browser to http://localhost:3000 then log in using the same credentials from the previous step
Thats it! Youre all set to begin coding. Remember to refresh your browser if changes dont auto-reload. Happy contributing! 🎉
## Missing a Feature?
If a feature is missing, you can directly _request_ a new one [here](https://github.com/makeplane/plane/issues/new?assignees=&labels=feature&template=feature_request.yml&title=%F0%9F%9A%80+Feature%3A+). You also can do the same by choosing "🚀 Feature" when raising a [New Issue](https://github.com/makeplane/plane/issues/new/choose) on our GitHub Repository.
@@ -75,11 +106,13 @@ To ensure consistency throughout the source code, please keep these rules in min
- **Improve documentation** - fix incomplete or missing [docs](https://docs.plane.so/), bad wording, examples or explanations.
## Contributing to language support
This guide is designed to help contributors understand how to add or update translations in the application.
This guide is designed to help contributors understand how to add or update translations in the application.
### Understanding translation structure
#### File organization
Translations are organized by language in the locales directory. Each language has its own folder containing JSON files for translations. Here's how it looks:
```
@@ -90,9 +123,11 @@ packages/i18n/src/locales/
├── fr/
│ └── translations.json
└── [language]/
└── translations.json
└── translations.json
```
#### Nested structure
To keep translations organized, we use a nested structure for keys. This makes it easier to manage and locate specific translations. For example:
```json
@@ -107,32 +142,37 @@ To keep translations organized, we use a nested structure for keys. This makes i
```
### Translation formatting guide
We use [IntlMessageFormat](https://formatjs.github.io/docs/intl-messageformat/) to handle dynamic content, such as variables and pluralization. Here's how to format your translations:
#### Examples
- **Simple variables**
```json
{
"greeting": "Hello, {name}!"
}
```
- **Pluralization**
```json
{
- **Simple variables**
```json
{
"greeting": "Hello, {name}!"
}
```
- **Pluralization**
```json
{
"items": "{count, plural, one {Work item} other {Work items}}"
}
```
}
```
### Contributing guidelines
#### Updating existing translations
1. Locate the key in `locales/<language>/translations.json`.
2. Update the value while ensuring the key structure remains intact.
3. Preserve any existing ICU formats (e.g., variables, pluralization).
#### Adding new translation keys
1. When introducing a new key, ensure it is added to **all** language files, even if translations are not immediately available. Use English as a placeholder if needed.
2. Keep the nesting structure consistent across all languages.
@@ -140,48 +180,50 @@ We use [IntlMessageFormat](https://formatjs.github.io/docs/intl-messageformat/)
3. If the new key requires dynamic content (e.g., variables or pluralization), ensure the ICU format is applied uniformly across all languages.
### Adding new languages
Adding a new language involves several steps to ensure it integrates seamlessly with the project. Follow these instructions carefully:
1. **Update type definitions**
Add the new language to the TLanguage type in the language definitions file:
1. **Update type definitions**
Add the new language to the TLanguage type in the language definitions file:
```typescript
// types/language.ts
export type TLanguage = "en" | "fr" | "your-lang";
```
```typescript
// types/language.ts
export type TLanguage = "en" | "fr" | "your-lang";
```
2. **Add language configuration**
Include the new language in the list of supported languages:
2. **Add language configuration**
Include the new language in the list of supported languages:
```typescript
// constants/language.ts
export const SUPPORTED_LANGUAGES: ILanguageOption[] = [
{ label: "English", value: "en" },
{ label: "Your Language", value: "your-lang" }
];
```
```typescript
// constants/language.ts
export const SUPPORTED_LANGUAGES: ILanguageOption[] = [
{ label: "English", value: "en" },
{ label: "Your Language", value: "your-lang" }
];
```
3. **Create translation files**
1. Create a new folder for your language under locales (e.g., `locales/your-lang/`).
3. **Create translation files**
1. Create a new folder for your language under locales (e.g., `locales/your-lang/`).
2. Add a `translations.json` file inside the folder.
3. Copy the structure from an existing translation file and translate all keys.
4. **Update import logic**
Modify the language import logic to include your new language:
4. **Update import logic**
Modify the language import logic to include your new language:
```typescript
private importLanguageFile(language: TLanguage): Promise<any> {
switch (language) {
case "your-lang":
return import("../locales/your-lang/translations.json");
// ...
}
}
```
```typescript
private importLanguageFile(language: TLanguage): Promise<any> {
switch (language) {
case "your-lang":
return import("../locales/your-lang/translations.json");
// ...
}
}
```
### Quality checklist
Before submitting your contribution, please ensure the following:
- All translation keys exist in every language file.
@@ -192,6 +234,7 @@ Before submitting your contribution, please ensure the following:
- There are no missing or untranslated keys.
#### Pro tips
- When in doubt, refer to the English translations for context.
- Verify pluralization works with different numbers.
- Ensure dynamic values (e.g., `{name}`) are correctly interpolated.

View File

@@ -1,88 +0,0 @@
# Environment Variables
Environment variables are distributed in various files. Please refer them carefully.
## {PROJECT_FOLDER}/.env
File is available in the project root folder
```
# Database Settings
POSTGRES_USER="plane"
POSTGRES_PASSWORD="plane"
POSTGRES_DB="plane"
PGDATA="/var/lib/postgresql/data"
# Redis Settings
REDIS_HOST="plane-redis"
REDIS_PORT="6379"
# AWS Settings
AWS_REGION=""
AWS_ACCESS_KEY_ID="access-key"
AWS_SECRET_ACCESS_KEY="secret-key"
AWS_S3_ENDPOINT_URL="http://plane-minio:9000"
# Changing this requires change in the nginx.conf for uploads if using minio setup
AWS_S3_BUCKET_NAME="uploads"
# Maximum file upload limit
FILE_SIZE_LIMIT=5242880
# GPT settings
OPENAI_API_BASE="https://api.openai.com/v1" # deprecated
OPENAI_API_KEY="sk-" # deprecated
GPT_ENGINE="gpt-3.5-turbo" # deprecated
# Settings related to Docker
DOCKERIZED=1 # deprecated
# set to 1 If using the pre-configured minio setup
USE_MINIO=1
# Nginx Configuration
NGINX_PORT=80
```
## {PROJECT_FOLDER}/apiserver/.env
```
# Backend
# Debug value for api server use it as 0 for production use
DEBUG=0
CORS_ALLOWED_ORIGINS="http://localhost"
# Database Settings
POSTGRES_USER="plane"
POSTGRES_PASSWORD="plane"
POSTGRES_HOST="plane-db"
POSTGRES_DB="plane"
POSTGRES_PORT=5432
DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}
# Redis Settings
REDIS_HOST="plane-redis"
REDIS_PORT="6379"
REDIS_URL="redis://${REDIS_HOST}:6379/"
# AWS Settings
AWS_REGION=""
AWS_ACCESS_KEY_ID="access-key"
AWS_SECRET_ACCESS_KEY="secret-key"
AWS_S3_ENDPOINT_URL="http://plane-minio:9000"
# Changing this requires change in the nginx.conf for uploads if using minio setup
AWS_S3_BUCKET_NAME="uploads"
# Maximum file upload limit
FILE_SIZE_LIMIT=5242880
# Settings related to Docker
DOCKERIZED=1 # deprecated
# set to 1 If using the pre-configured minio setup
USE_MINIO=1
# Nginx Configuration
NGINX_PORT=80
# Email redirections and minio domain settings
WEB_URL="http://localhost"
# Gunicorn Workers
GUNICORN_WORKERS=2
# Base URLs
ADMIN_BASE_URL=
SPACE_BASE_URL=
APP_BASE_URL=
SECRET_KEY="gxoytl7dmnc1y37zahah820z5iq3iozu38cnfjtu3yaau9cd9z"
```
## Updates
- The naming convention for containers and images has been updated.
- The plane-worker image will no longer be maintained, as it has been merged with plane-backend.
- The Tiptap pro-extension dependency has been removed, eliminating the need for Tiptap API keys.
- The image name for Plane deployment has been changed to plane-space.

View File

@@ -47,10 +47,10 @@ Meet [Plane](https://plane.so/), an open-source project management tool to track
Getting started with Plane is simple. Choose the setup that works best for you:
- **Plane Cloud**
- **Plane Cloud**
Sign up for a free account on [Plane Cloud](https://app.plane.so)—it's the fastest way to get up and running without worrying about infrastructure.
- **Self-host Plane**
- **Self-host Plane**
Prefer full control over your data and infrastructure? Install and run Plane on your own servers. Follow our detailed [deployment guides](https://developers.plane.so/self-hosting/overview) to get started.
| Installation methods | Docs link |
@@ -62,22 +62,22 @@ Prefer full control over your data and infrastructure? Install and run Plane on
## 🌟 Features
- **Issues**
- **Issues**
Efficiently create and manage tasks with a robust rich text editor that supports file uploads. Enhance organization and tracking by adding sub-properties and referencing related issues.
- **Cycles**
- **Cycles**
Maintain your teams momentum with Cycles. Track progress effortlessly using burn-down charts and other insightful tools.
- **Modules**
Simplify complex projects by dividing them into smaller, manageable modules.
- **Modules**
Simplify complex projects by dividing them into smaller, manageable modules.
- **Views**
- **Views**
Customize your workflow by creating filters to display only the most relevant issues. Save and share these views with ease.
- **Pages**
- **Pages**
Capture and organize ideas using Plane Pages, complete with AI capabilities and a rich text editor. Format text, insert images, add hyperlinks, or convert your notes into actionable items.
- **Analytics**
- **Analytics**
Access real-time insights across all your Plane data. Visualize trends, remove blockers, and keep your projects moving forward.
- **Drive** (_coming soon_): The drive helps you share documents, images, videos, or any other files that make sense to you or your team and align on the problem/solution.
@@ -85,38 +85,7 @@ Access real-time insights across all your Plane data. Visualize trends, remove b
## 🛠️ Local development
### Pre-requisites
- Ensure Docker Engine is installed and running.
### Development setup
Setting up your local environment is simple and straightforward. Follow these steps to get started:
1. Clone the repository:
```
git clone https://github.com/makeplane/plane.git
```
2. Navigate to the project folder:
```
cd plane
```
3. Create a new branch for your feature or fix:
```
git checkout -b <feature-branch-name>
```
4. Run the setup script in the terminal:
```
./setup.sh
```
5. Open the project in an IDE such as VS Code.
6. Review the `.env` files in the relevant folders. Refer to [Environment Setup](./ENV_SETUP.md) for details on the environment variables used.
7. Start the services using Docker:
```
docker compose -f docker-compose-local.yml up -d
```
Thats it! Youre all set to begin coding. Remember to refresh your browser if changes dont auto-reload. Happy contributing! 🎉
See [CONTRIBUTING](./CONTRIBUTING.md)
## ⚙️ Built with
[![Next JS](https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white)](https://nextjs.org/)
@@ -194,7 +163,7 @@ Feel free to ask questions, report bugs, participate in discussions, share ideas
If you discover a security vulnerability in Plane, please report it responsibly instead of opening a public issue. We take all legitimate reports seriously and will investigate them promptly. See [Security policy](https://github.com/makeplane/plane/blob/master/SECURITY.md) for more info.
To disclose any security issues, please email us at security@plane.so.
To disclose any security issues, please email us at security@plane.so.
## 🤝 Contributing
@@ -219,4 +188,4 @@ Please read [CONTRIBUTING.md](https://github.com/makeplane/plane/blob/master/CON
## License
This project is licensed under the [GNU Affero General Public License v3.0](https://github.com/makeplane/plane/blob/master/LICENSE.txt).
This project is licensed under the [GNU Affero General Public License v3.0](https://github.com/makeplane/plane/blob/master/LICENSE.txt).

View File

@@ -1,3 +0,0 @@
NEXT_PUBLIC_API_BASE_URL=""
NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode"
NEXT_PUBLIC_WEB_BASE_URL=""

View File

@@ -1,49 +0,0 @@
"use client";
import { ReactNode } from "react";
import { ThemeProvider, useTheme } from "next-themes";
import { SWRConfig } from "swr";
// ui
import { ADMIN_BASE_PATH, DEFAULT_SWR_CONFIG } from "@plane/constants";
import { Toast } from "@plane/ui";
import { resolveGeneralTheme } from "@plane/utils";
// constants
// helpers
// lib
import { InstanceProvider } from "@/lib/instance-provider";
import { StoreProvider } from "@/lib/store-provider";
import { UserProvider } from "@/lib/user-provider";
// styles
import "./globals.css";
const ToastWithTheme = () => {
const { resolvedTheme } = useTheme();
return <Toast theme={resolveGeneralTheme(resolvedTheme)} />;
};
export default function RootLayout({ children }: { children: ReactNode }) {
const ASSET_PREFIX = ADMIN_BASE_PATH;
return (
<html lang="en">
<head>
<link rel="apple-touch-icon" sizes="180x180" href={`${ASSET_PREFIX}/favicon/apple-touch-icon.png`} />
<link rel="icon" type="image/png" sizes="32x32" href={`${ASSET_PREFIX}/favicon/favicon-32x32.png`} />
<link rel="icon" type="image/png" sizes="16x16" href={`${ASSET_PREFIX}/favicon/favicon-16x16.png`} />
<link rel="manifest" href={`${ASSET_PREFIX}/site.webmanifest.json`} />
<link rel="shortcut icon" href={`${ASSET_PREFIX}/favicon/favicon.ico`} />
</head>
<body className={`antialiased`}>
<ThemeProvider themes={["light", "dark"]} defaultTheme="system" enableSystem>
<ToastWithTheme />
<SWRConfig value={DEFAULT_SWR_CONFIG}>
<StoreProvider>
<InstanceProvider>
<UserProvider>{children}</UserProvider>
</InstanceProvider>
</StoreProvider>
</SWRConfig>
</ThemeProvider>
</body>
</html>
);
}

View File

@@ -1,30 +0,0 @@
import { Metadata } from "next";
// components
import { InstanceSignInForm } from "@/components/login";
// layouts
import { DefaultLayout } from "@/layouts/default-layout";
export const metadata: Metadata = {
title: "Plane | Simple, extensible, open-source project management tool.",
description:
"Open-source project management tool to manage work items, sprints, and product roadmaps with peace of mind.",
openGraph: {
title: "Plane | Simple, extensible, open-source project management tool.",
description:
"Open-source project management tool to manage work items, sprints, and product roadmaps with peace of mind.",
url: "https://plane.so/",
},
keywords:
"software development, customer feedback, software, accelerate, code management, release management, project management, work items tracking, agile, scrum, kanban, collaboration",
twitter: {
site: "@planepowers",
},
};
export default async function LoginPage() {
return (
<DefaultLayout>
<InstanceSignInForm />
</DefaultLayout>
);
}

View File

@@ -1,70 +0,0 @@
import { observer } from "mobx-react";
import Image from "next/image";
import { useTheme } from "next-themes";
// types
import {
TGetBaseAuthenticationModeProps,
TInstanceAuthenticationMethodKeys,
TInstanceAuthenticationModes,
} from "@plane/types";
// components
import { AuthenticationMethodCard } from "@/components/authentication";
// helpers
import { getBaseAuthenticationModes } from "@/lib/auth-helpers";
// plane admin components
import { UpgradeButton } from "@/plane-admin/components/common";
// images
import OIDCLogo from "@/public/logos/oidc-logo.svg";
import SAMLLogo from "@/public/logos/saml-logo.svg";
export type TAuthenticationModeProps = {
disabled: boolean;
updateConfig: (key: TInstanceAuthenticationMethodKeys, value: string) => void;
};
// Authentication methods
export const getAuthenticationModes: (props: TGetBaseAuthenticationModeProps) => TInstanceAuthenticationModes[] = ({
disabled,
updateConfig,
resolvedTheme,
}) => [
...getBaseAuthenticationModes({ disabled, updateConfig, resolvedTheme }),
{
key: "oidc",
name: "OIDC",
description: "Authenticate your users via the OpenID Connect protocol.",
icon: <Image src={OIDCLogo} height={22} width={22} alt="OIDC Logo" />,
config: <UpgradeButton />,
unavailable: true,
},
{
key: "saml",
name: "SAML",
description: "Authenticate your users via the Security Assertion Markup Language protocol.",
icon: <Image src={SAMLLogo} height={22} width={22} alt="SAML Logo" className="pl-0.5" />,
config: <UpgradeButton />,
unavailable: true,
},
];
export const AuthenticationModes: React.FC<TAuthenticationModeProps> = observer((props) => {
const { disabled, updateConfig } = props;
// next-themes
const { resolvedTheme } = useTheme();
return (
<>
{getAuthenticationModes({ disabled, updateConfig, resolvedTheme }).map((method) => (
<AuthenticationMethodCard
key={method.key}
name={method.name}
description={method.description}
icon={method.icon}
config={method.config}
disabled={disabled}
unavailable={method.unavailable}
/>
))}
</>
);
});

View File

@@ -1,5 +0,0 @@
export * from "./root";
export * from "./help-section";
export * from "./sidebar-menu";
export * from "./sidebar-dropdown";
export * from "./sidebar-menu-hamburger-toogle";

View File

@@ -1,20 +0,0 @@
"use client";
import { FC } from "react";
import { observer } from "mobx-react";
// hooks
import { Menu } from "lucide-react";
import { useTheme } from "@/hooks/store";
// icons
export const SidebarHamburgerToggle: FC = observer(() => {
const { isSidebarCollapsed, toggleSidebar } = useTheme();
return (
<div
className="w-7 h-7 rounded flex justify-center items-center bg-custom-background-80 transition-all hover:bg-custom-background-90 cursor-pointer group md:hidden"
onClick={() => toggleSidebar(!isSidebarCollapsed)}
>
<Menu size={14} className="text-custom-text-200 group-hover:text-custom-text-100 transition-all" />
</div>
);
});

View File

@@ -1,7 +0,0 @@
export * from "./auth-banner";
export * from "./email-config-switch";
export * from "./password-config-switch";
export * from "./authentication-method-card";
export * from "./gitlab-config";
export * from "./github-config";
export * from "./google-config";

View File

@@ -1,10 +0,0 @@
export * from "./breadcrumb-link";
export * from "./confirm-discard-modal";
export * from "./controller-input";
export * from "./copy-field";
export * from "./password-strength-meter";
export * from "./banner";
export * from "./empty-state";
export * from "./logo-spinner";
export * from "./page-header";
export * from "./code-block";

View File

@@ -1,3 +0,0 @@
export * from "./instance-not-ready";
export * from "./instance-failure-view";
export * from "./setup-form";

View File

@@ -1 +0,0 @@
export * from "./sign-in-form";

View File

@@ -1,194 +0,0 @@
"use client";
import { FC, useEffect, useMemo, useState } from "react";
import { useSearchParams } from "next/navigation";
import { Eye, EyeOff } from "lucide-react";
// plane internal packages
import { API_BASE_URL, EAdminAuthErrorCodes, TAuthErrorInfo } from "@plane/constants";
import { AuthService } from "@plane/services";
import { Button, Input, Spinner } from "@plane/ui";
// components
import { Banner } from "@/components/common";
// helpers
import { authErrorHandler } from "@/lib/auth-helpers";
// local components
import { AuthBanner } from "../authentication";
// service initialization
const authService = new AuthService();
// error codes
enum EErrorCodes {
INSTANCE_NOT_CONFIGURED = "INSTANCE_NOT_CONFIGURED",
REQUIRED_EMAIL_PASSWORD = "REQUIRED_EMAIL_PASSWORD",
INVALID_EMAIL = "INVALID_EMAIL",
USER_DOES_NOT_EXIST = "USER_DOES_NOT_EXIST",
AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED",
}
type TError = {
type: EErrorCodes | undefined;
message: string | undefined;
};
// form data
type TFormData = {
email: string;
password: string;
};
const defaultFromData: TFormData = {
email: "",
password: "",
};
export const InstanceSignInForm: FC = (props) => {
const {} = props;
// search params
const searchParams = useSearchParams();
const emailParam = searchParams.get("email") || undefined;
const errorCode = searchParams.get("error_code") || undefined;
const errorMessage = searchParams.get("error_message") || undefined;
// state
const [showPassword, setShowPassword] = useState(false);
const [csrfToken, setCsrfToken] = useState<string | undefined>(undefined);
const [formData, setFormData] = useState<TFormData>(defaultFromData);
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorInfo, setErrorInfo] = useState<TAuthErrorInfo | undefined>(undefined);
const handleFormChange = (key: keyof TFormData, value: string | boolean) =>
setFormData((prev) => ({ ...prev, [key]: value }));
useEffect(() => {
if (csrfToken === undefined)
authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
}, [csrfToken]);
useEffect(() => {
if (emailParam) setFormData((prev) => ({ ...prev, email: emailParam }));
}, [emailParam]);
// derived values
const errorData: TError = useMemo(() => {
if (errorCode && errorMessage) {
switch (errorCode) {
case EErrorCodes.INSTANCE_NOT_CONFIGURED:
return { type: EErrorCodes.INVALID_EMAIL, message: errorMessage };
case EErrorCodes.REQUIRED_EMAIL_PASSWORD:
return { type: EErrorCodes.REQUIRED_EMAIL_PASSWORD, message: errorMessage };
case EErrorCodes.INVALID_EMAIL:
return { type: EErrorCodes.INVALID_EMAIL, message: errorMessage };
case EErrorCodes.USER_DOES_NOT_EXIST:
return { type: EErrorCodes.USER_DOES_NOT_EXIST, message: errorMessage };
case EErrorCodes.AUTHENTICATION_FAILED:
return { type: EErrorCodes.AUTHENTICATION_FAILED, message: errorMessage };
default:
return { type: undefined, message: undefined };
}
} else return { type: undefined, message: undefined };
}, [errorCode, errorMessage]);
const isButtonDisabled = useMemo(
() => (!isSubmitting && formData.email && formData.password ? false : true),
[formData.email, formData.password, isSubmitting]
);
useEffect(() => {
if (errorCode) {
const errorDetail = authErrorHandler(errorCode?.toString() as EAdminAuthErrorCodes);
if (errorDetail) {
setErrorInfo(errorDetail);
}
}
}, [errorCode]);
return (
<div className="flex-grow container mx-auto max-w-lg px-10 lg:max-w-md lg:px-5 py-10 lg:pt-28 transition-all">
<div className="relative flex flex-col space-y-6">
<div className="text-center space-y-1">
<h3 className="flex gap-4 justify-center text-3xl font-bold text-onboarding-text-100">
Manage your Plane instance
</h3>
<p className="font-medium text-onboarding-text-400">
Configure instance-wide settings to secure your instance
</p>
</div>
{errorData.type && errorData?.message ? (
<Banner type="error" message={errorData?.message} />
) : (
<>{errorInfo && <AuthBanner bannerData={errorInfo} handleBannerData={(value) => setErrorInfo(value)} />}</>
)}
<form
className="space-y-4"
method="POST"
action={`${API_BASE_URL}/api/instances/admins/sign-in/`}
onSubmit={() => setIsSubmitting(true)}
onError={() => setIsSubmitting(false)}
>
<input type="hidden" name="csrfmiddlewaretoken" value={csrfToken} />
<div className="w-full space-y-1">
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="email">
Email <span className="text-red-500">*</span>
</label>
<Input
className="w-full border border-onboarding-border-100 !bg-onboarding-background-200 placeholder:text-onboarding-text-400"
id="email"
name="email"
type="email"
inputSize="md"
placeholder="name@company.com"
value={formData.email}
onChange={(e) => handleFormChange("email", e.target.value)}
autoComplete="on"
autoFocus
/>
</div>
<div className="w-full space-y-1">
<label className="text-sm text-onboarding-text-300 font-medium" htmlFor="password">
Password <span className="text-red-500">*</span>
</label>
<div className="relative">
<Input
className="w-full border border-onboarding-border-100 !bg-onboarding-background-200 placeholder:text-onboarding-text-400"
id="password"
name="password"
type={showPassword ? "text" : "password"}
inputSize="md"
placeholder="Enter your password"
value={formData.password}
onChange={(e) => handleFormChange("password", e.target.value)}
autoComplete="on"
/>
{showPassword ? (
<button
type="button"
className="absolute right-3 top-3.5 flex items-center justify-center text-custom-text-400"
onClick={() => setShowPassword(false)}
>
<EyeOff className="h-4 w-4" />
</button>
) : (
<button
type="button"
className="absolute right-3 top-3.5 flex items-center justify-center text-custom-text-400"
onClick={() => setShowPassword(true)}
>
<Eye className="h-4 w-4" />
</button>
)}
</div>
</div>
<div className="py-2">
<Button type="submit" size="lg" className="w-full" disabled={isButtonDisabled}>
{isSubmitting ? <Spinner height="20px" width="20px" /> : "Sign in"}
</Button>
</div>
</form>
</div>
</div>
);
};

View File

@@ -1 +0,0 @@
export * from "./list-item";

View File

@@ -1,55 +0,0 @@
import { FC, ReactNode } from "react";
import { observer } from "mobx-react";
import useSWR from "swr";
// components
import { LogoSpinner } from "@/components/common";
import { InstanceSetupForm, InstanceFailureView } from "@/components/instance";
// hooks
import { useInstance } from "@/hooks/store";
// layout
import { DefaultLayout } from "@/layouts/default-layout";
type InstanceProviderProps = {
children: ReactNode;
};
export const InstanceProvider: FC<InstanceProviderProps> = observer((props) => {
const { children } = props;
// store hooks
const { instance, error, fetchInstanceInfo } = useInstance();
// fetching instance details
useSWR("INSTANCE_DETAILS", () => fetchInstanceInfo(), {
revalidateOnFocus: false,
revalidateIfStale: false,
errorRetryCount: 0,
});
if (!instance && !error)
return (
<div className="flex h-screen min-h-[500px] w-full justify-center items-center">
<LogoSpinner />
</div>
);
if (error) {
return (
<DefaultLayout>
<div className="relative h-full w-full overflow-y-auto px-6 py-10 mx-auto flex justify-center items-center">
<InstanceFailureView />
</div>
</DefaultLayout>
);
}
if (!instance?.is_setup_done) {
return (
<DefaultLayout>
<div className="relative h-full w-full overflow-y-auto px-6 py-10 mx-auto flex justify-center items-center">
<InstanceSetupForm />
</div>
</DefaultLayout>
);
}
return <>{children}</>;
});

View File

@@ -1,27 +0,0 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
trailingSlash: true,
reactStrictMode: false,
swcMinify: true,
output: "standalone",
images: {
unoptimized: true,
},
basePath: process.env.NEXT_PUBLIC_ADMIN_BASE_PATH || "",
transpilePackages: [
"@plane/constants",
"@plane/editor",
"@plane/hooks",
"@plane/i18n",
"@plane/logger",
"@plane/propel",
"@plane/services",
"@plane/shared-state",
"@plane/types",
"@plane/ui",
"@plane/utils",
],
};
module.exports = nextConfig;

View File

@@ -1,8 +0,0 @@
module.exports = {
plugins: {
"postcss-import": {},
"tailwindcss/nesting": {},
tailwindcss: {},
autoprefixer: {},
},
};

View File

@@ -70,18 +70,18 @@ ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
COPY apiserver/requirements.txt ./api/
COPY apiserver/requirements ./api/requirements
COPY apps/api/requirements.txt ./api/
COPY apps/api/requirements ./api/requirements
RUN pip install -r ./api/requirements.txt --compile --no-cache-dir
# Add in Django deps and generate Django's static files
COPY apiserver/manage.py ./api/manage.py
COPY apiserver/plane ./api/plane/
COPY apiserver/templates ./api/templates/
COPY apps/api/manage.py ./api/manage.py
COPY apps/api/plane ./api/plane/
COPY apps/api/templates ./api/templates/
COPY package.json ./api/package.json
COPY apiserver/bin ./api/bin/
COPY apps/api/bin ./api/bin/
RUN chmod +x ./api/bin/*
RUN chmod -R 777 ./api/

View File

@@ -1,3 +0,0 @@
web: gunicorn -w 4 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:$PORT --max-requests 10000 --max-requests-jitter 1000 --access-logfile -
worker: celery -A plane worker -l info
beat: celery -A plane beat -l INFO

View File

@@ -1,224 +0,0 @@
# All the python scripts that are used for back migrations
import uuid
import random
from django.contrib.auth.hashers import make_password
from plane.db.models import ProjectIdentifier
from plane.db.models import (
Issue,
IssueComment,
User,
Project,
ProjectMember,
Label,
Integration,
)
# Update description and description html values for old descriptions
def update_description():
try:
issues = Issue.objects.all()
updated_issues = []
for issue in issues:
issue.description_html = f"<p>{issue.description}</p>"
issue.description_stripped = issue.description
updated_issues.append(issue)
Issue.objects.bulk_update(
updated_issues, ["description_html", "description_stripped"], batch_size=100
)
print("Success")
except Exception as e:
print(e)
print("Failed")
def update_comments():
try:
issue_comments = IssueComment.objects.all()
updated_issue_comments = []
for issue_comment in issue_comments:
issue_comment.comment_html = f"<p>{issue_comment.comment_stripped}</p>"
updated_issue_comments.append(issue_comment)
IssueComment.objects.bulk_update(
updated_issue_comments, ["comment_html"], batch_size=100
)
print("Success")
except Exception as e:
print(e)
print("Failed")
def update_project_identifiers():
try:
project_identifiers = ProjectIdentifier.objects.filter(
workspace_id=None
).select_related("project", "project__workspace")
updated_identifiers = []
for identifier in project_identifiers:
identifier.workspace_id = identifier.project.workspace_id
updated_identifiers.append(identifier)
ProjectIdentifier.objects.bulk_update(
updated_identifiers, ["workspace_id"], batch_size=50
)
print("Success")
except Exception as e:
print(e)
print("Failed")
def update_user_empty_password():
try:
users = User.objects.filter(password="")
updated_users = []
for user in users:
user.password = make_password(uuid.uuid4().hex)
user.is_password_autoset = True
updated_users.append(user)
User.objects.bulk_update(updated_users, ["password"], batch_size=50)
print("Success")
except Exception as e:
print(e)
print("Failed")
def updated_issue_sort_order():
try:
issues = Issue.objects.all()
updated_issues = []
for issue in issues:
issue.sort_order = issue.sequence_id * random.randint(100, 500)
updated_issues.append(issue)
Issue.objects.bulk_update(updated_issues, ["sort_order"], batch_size=100)
print("Success")
except Exception as e:
print(e)
print("Failed")
def update_project_cover_images():
try:
project_cover_images = [
"https://images.unsplash.com/photo-1677432658720-3d84f9d657b4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
"https://images.unsplash.com/photo-1661107564401-57497d8fe86f?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1332&q=80",
"https://images.unsplash.com/photo-1677352241429-dc90cfc7a623?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1332&q=80",
"https://images.unsplash.com/photo-1677196728306-eeafea692454?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1331&q=80",
"https://images.unsplash.com/photo-1660902179734-c94c944f7830?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1255&q=80",
"https://images.unsplash.com/photo-1672243775941-10d763d9adef?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
"https://images.unsplash.com/photo-1677040628614-53936ff66632?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
"https://images.unsplash.com/photo-1676920410907-8d5f8dd4b5ba?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1332&q=80",
"https://images.unsplash.com/photo-1676846328604-ce831c481346?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1155&q=80",
"https://images.unsplash.com/photo-1676744843212-09b7e64c3a05?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
"https://images.unsplash.com/photo-1676798531090-1608bedeac7b?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
"https://images.unsplash.com/photo-1597088758740-56fd7ec8a3f0?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1169&q=80",
"https://images.unsplash.com/photo-1676638392418-80aad7c87b96?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80",
"https://images.unsplash.com/photo-1649639194967-2fec0b4ea7bc?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
"https://images.unsplash.com/photo-1675883086902-b453b3f8146e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=774&q=80",
"https://images.unsplash.com/photo-1675887057159-40fca28fdc5d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1173&q=80",
"https://images.unsplash.com/photo-1675373980203-f84c5a672aa5?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
"https://images.unsplash.com/photo-1675191475318-d2bf6bad1200?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1332&q=80",
"https://images.unsplash.com/photo-1675456230532-2194d0c4bcc0?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
"https://images.unsplash.com/photo-1675371788315-60fa0ef48267?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1332&q=80",
]
projects = Project.objects.all()
updated_projects = []
for project in projects:
project.cover_image = project_cover_images[random.randint(0, 19)]
updated_projects.append(project)
Project.objects.bulk_update(updated_projects, ["cover_image"], batch_size=100)
print("Success")
except Exception as e:
print(e)
print("Failed")
def update_user_view_property():
try:
project_members = ProjectMember.objects.all()
updated_project_members = []
for project_member in project_members:
project_member.default_props = {
"filters": {"type": None},
"orderBy": "-created_at",
"collapsed": True,
"issueView": "list",
"filterIssue": None,
"groupByProperty": None,
"showEmptyGroups": True,
}
updated_project_members.append(project_member)
ProjectMember.objects.bulk_update(
updated_project_members, ["default_props"], batch_size=100
)
print("Success")
except Exception as e:
print(e)
print("Failed")
def update_label_color():
try:
labels = Label.objects.filter(color="")
updated_labels = []
for label in labels:
label.color = f"#{random.randint(0, 0xFFFFFF+1):06X}"
updated_labels.append(label)
Label.objects.bulk_update(updated_labels, ["color"], batch_size=100)
print("Success")
except Exception as e:
print(e)
print("Failed")
def create_slack_integration():
try:
_ = Integration.objects.create(provider="slack", network=2, title="Slack")
print("Success")
except Exception as e:
print(e)
print("Failed")
def update_integration_verified():
try:
integrations = Integration.objects.all()
updated_integrations = []
for integration in integrations:
integration.verified = True
updated_integrations.append(integration)
Integration.objects.bulk_update(
updated_integrations, ["verified"], batch_size=10
)
print("Success")
except Exception as e:
print(e)
print("Failed")
def update_start_date():
try:
issues = Issue.objects.filter(state__group__in=["started", "completed"])
updated_issues = []
for issue in issues:
issue.start_date = issue.created_at.date()
updated_issues.append(issue)
Issue.objects.bulk_update(updated_issues, ["start_date"], batch_size=500)
print("Success")
except Exception as e:
print(e)
print("Failed")

View File

@@ -1,40 +0,0 @@
# Third party imports
from rest_framework import serializers
# Module imports
from .base import DynamicBaseSerializer
from plane.db.models import IssueView
from plane.utils.issue_filters import issue_filters
class IssueViewSerializer(DynamicBaseSerializer):
is_favorite = serializers.BooleanField(read_only=True)
class Meta:
model = IssueView
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"query",
"owned_by",
"access",
"is_locked",
]
def create(self, validated_data):
query_params = validated_data.get("filters", {})
if bool(query_params):
validated_data["query"] = issue_filters(query_params, "POST")
else:
validated_data["query"] = {}
return IssueView.objects.create(**validated_data)
def update(self, instance, validated_data):
query_params = validated_data.get("filters", {})
if bool(query_params):
validated_data["query"] = issue_filters(query_params, "POST")
else:
validated_data["query"] = {}
validated_data["query"] = issue_filters(query_params, "PATCH")
return super().update(instance, validated_data)

View File

@@ -1,102 +0,0 @@
# Django imports
from django.db.models import Q
# Third party imports
from rest_framework import status
from rest_framework.response import Response
# Module imports
from .base import BaseAPIView
from plane.db.models import Issue, ProjectMember, IssueRelation
from plane.utils.issue_search import search_issues
class IssueSearchEndpoint(BaseAPIView):
def get(self, request, slug, project_id):
query = request.query_params.get("search", False)
workspace_search = request.query_params.get("workspace_search", "false")
parent = request.query_params.get("parent", "false")
issue_relation = request.query_params.get("issue_relation", "false")
cycle = request.query_params.get("cycle", "false")
module = request.query_params.get("module", False)
sub_issue = request.query_params.get("sub_issue", "false")
target_date = request.query_params.get("target_date", True)
issue_id = request.query_params.get("issue_id", False)
issues = Issue.issue_objects.filter(
workspace__slug=slug,
project__project_projectmember__member=self.request.user,
project__project_projectmember__is_active=True,
project__archived_at__isnull=True,
)
if workspace_search == "false":
issues = issues.filter(project_id=project_id)
if query:
issues = search_issues(query, issues)
if parent == "true" and issue_id:
issue = Issue.issue_objects.filter(pk=issue_id).first()
if issue:
issues = issues.filter(
~Q(pk=issue_id), ~Q(pk=issue.parent_id), ~Q(parent_id=issue_id)
)
if issue_relation == "true" and issue_id:
issue = Issue.issue_objects.filter(pk=issue_id).first()
related_issue_ids = IssueRelation.objects.filter(
Q(related_issue=issue) | Q(issue=issue)
).values_list(
"issue_id", "related_issue_id"
).distinct()
related_issue_ids = [item for sublist in related_issue_ids for item in sublist]
if issue:
issues = issues.filter(
~Q(pk=issue_id),
~Q(pk__in=related_issue_ids),
)
if sub_issue == "true" and issue_id:
issue = Issue.issue_objects.filter(pk=issue_id).first()
if issue:
issues = issues.filter(~Q(pk=issue_id), parent__isnull=True)
if issue.parent:
issues = issues.filter(~Q(pk=issue.parent_id))
if cycle == "true":
issues = issues.exclude(
Q(issue_cycle__isnull=False) & Q(issue_cycle__deleted_at__isnull=True)
)
if module:
issues = issues.exclude(
Q(issue_module__module=module)
& Q(issue_module__deleted_at__isnull=True)
)
if target_date == "none":
issues = issues.filter(target_date__isnull=True)
if ProjectMember.objects.filter(
project_id=project_id, member=self.request.user, is_active=True, role=5
).exists():
issues = issues.filter(created_by=self.request.user)
return Response(
issues.values(
"name",
"id",
"start_date",
"sequence_id",
"project__name",
"project__identifier",
"project_id",
"workspace__slug",
"state__name",
"state__group",
"state__color",
)[:100],
status=status.HTTP_200_OK,
)

View File

@@ -1,187 +0,0 @@
# Python imports
import pytz
from datetime import datetime
# Django imports
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from rest_framework.views import APIView
# Module imports
from plane.authentication.rate_limit import AuthenticationThrottle
class TimezoneEndpoint(APIView):
permission_classes = [AllowAny]
throttle_classes = [AuthenticationThrottle]
@method_decorator(cache_page(60 * 60 * 2))
def get(self, request):
timezone_locations = [
('Midway Island', 'Pacific/Midway'), # UTC-11:00
('American Samoa', 'Pacific/Pago_Pago'), # UTC-11:00
('Hawaii', 'Pacific/Honolulu'), # UTC-10:00
('Aleutian Islands', 'America/Adak'), # UTC-10:00 (DST: UTC-09:00)
('Marquesas Islands', 'Pacific/Marquesas'), # UTC-09:30
('Alaska', 'America/Anchorage'), # UTC-09:00 (DST: UTC-08:00)
('Gambier Islands', 'Pacific/Gambier'), # UTC-09:00
('Pacific Time (US and Canada)', 'America/Los_Angeles'), # UTC-08:00 (DST: UTC-07:00)
('Baja California', 'America/Tijuana'), # UTC-08:00 (DST: UTC-07:00)
('Mountain Time (US and Canada)', 'America/Denver'), # UTC-07:00 (DST: UTC-06:00)
('Arizona', 'America/Phoenix'), # UTC-07:00
('Chihuahua, Mazatlan', 'America/Chihuahua'), # UTC-07:00 (DST: UTC-06:00)
('Central Time (US and Canada)', 'America/Chicago'), # UTC-06:00 (DST: UTC-05:00)
('Saskatchewan', 'America/Regina'), # UTC-06:00
('Guadalajara, Mexico City, Monterrey', 'America/Mexico_City'), # UTC-06:00 (DST: UTC-05:00)
('Tegucigalpa, Honduras', 'America/Tegucigalpa'), # UTC-06:00
('Costa Rica', 'America/Costa_Rica'), # UTC-06:00
('Eastern Time (US and Canada)', 'America/New_York'), # UTC-05:00 (DST: UTC-04:00)
('Lima', 'America/Lima'), # UTC-05:00
('Bogota', 'America/Bogota'), # UTC-05:00
('Quito', 'America/Guayaquil'), # UTC-05:00
('Chetumal', 'America/Cancun'), # UTC-05:00 (DST: UTC-04:00)
('Caracas (Old Venezuela Time)', 'America/Caracas'), # UTC-04:30
('Atlantic Time (Canada)', 'America/Halifax'), # UTC-04:00 (DST: UTC-03:00)
('Caracas', 'America/Caracas'), # UTC-04:00
('Santiago', 'America/Santiago'), # UTC-04:00 (DST: UTC-03:00)
('La Paz', 'America/La_Paz'), # UTC-04:00
('Manaus', 'America/Manaus'), # UTC-04:00
('Georgetown', 'America/Guyana'), # UTC-04:00
('Bermuda', 'Atlantic/Bermuda'), # UTC-04:00 (DST: UTC-03:00)
('Newfoundland Time (Canada)', 'America/St_Johns'), # UTC-03:30 (DST: UTC-02:30)
('Buenos Aires', 'America/Argentina/Buenos_Aires'), # UTC-03:00
('Brasilia', 'America/Sao_Paulo'), # UTC-03:00
('Greenland', 'America/Godthab'), # UTC-03:00 (DST: UTC-02:00)
('Montevideo', 'America/Montevideo'), # UTC-03:00
('Falkland Islands', 'Atlantic/Stanley'), # UTC-03:00
('South Georgia and the South Sandwich Islands', 'Atlantic/South_Georgia'), # UTC-02:00
('Azores', 'Atlantic/Azores'), # UTC-01:00 (DST: UTC+00:00)
('Cape Verde Islands', 'Atlantic/Cape_Verde'), # UTC-01:00
('Dublin', 'Europe/Dublin'), # UTC+00:00 (DST: UTC+01:00)
('Reykjavik', 'Atlantic/Reykjavik'), # UTC+00:00
('Lisbon', 'Europe/Lisbon'), # UTC+00:00 (DST: UTC+01:00)
('Monrovia', 'Africa/Monrovia'), # UTC+00:00
('Casablanca', 'Africa/Casablanca'), # UTC+00:00 (DST: UTC+01:00)
('Central European Time (Berlin, Rome, Paris)', 'Europe/Paris'), # UTC+01:00 (DST: UTC+02:00)
('West Central Africa', 'Africa/Lagos'), # UTC+01:00
('Algiers', 'Africa/Algiers'), # UTC+01:00
('Lagos', 'Africa/Lagos'), # UTC+01:00
('Tunis', 'Africa/Tunis'), # UTC+01:00
('Eastern European Time (Cairo, Helsinki, Kyiv)', 'Europe/Kiev'), # UTC+02:00 (DST: UTC+03:00)
('Athens', 'Europe/Athens'), # UTC+02:00 (DST: UTC+03:00)
('Jerusalem', 'Asia/Jerusalem'), # UTC+02:00 (DST: UTC+03:00)
('Johannesburg', 'Africa/Johannesburg'), # UTC+02:00
('Harare, Pretoria', 'Africa/Harare'), # UTC+02:00
('Moscow Time', 'Europe/Moscow'), # UTC+03:00
('Baghdad', 'Asia/Baghdad'), # UTC+03:00
('Nairobi', 'Africa/Nairobi'), # UTC+03:00
('Kuwait, Riyadh', 'Asia/Riyadh'), # UTC+03:00
('Tehran', 'Asia/Tehran'), # UTC+03:30 (DST: UTC+04:30)
('Abu Dhabi', 'Asia/Dubai'), # UTC+04:00
('Baku', 'Asia/Baku'), # UTC+04:00 (DST: UTC+05:00)
('Yerevan', 'Asia/Yerevan'), # UTC+04:00 (DST: UTC+05:00)
('Astrakhan', 'Europe/Astrakhan'), # UTC+04:00
('Tbilisi', 'Asia/Tbilisi'), # UTC+04:00
('Mauritius', 'Indian/Mauritius'), # UTC+04:00
('Islamabad', 'Asia/Karachi'), # UTC+05:00
('Karachi', 'Asia/Karachi'), # UTC+05:00
('Tashkent', 'Asia/Tashkent'), # UTC+05:00
('Yekaterinburg', 'Asia/Yekaterinburg'), # UTC+05:00
('Maldives', 'Indian/Maldives'), # UTC+05:00
('Chagos', 'Indian/Chagos'), # UTC+05:00
('Chennai', 'Asia/Kolkata'), # UTC+05:30
('Kolkata', 'Asia/Kolkata'), # UTC+05:30
('Mumbai', 'Asia/Kolkata'), # UTC+05:30
('New Delhi', 'Asia/Kolkata'), # UTC+05:30
('Sri Jayawardenepura', 'Asia/Colombo'), # UTC+05:30
('Kathmandu', 'Asia/Kathmandu'), # UTC+05:45
('Dhaka', 'Asia/Dhaka'), # UTC+06:00
('Almaty', 'Asia/Almaty'), # UTC+06:00
('Bishkek', 'Asia/Bishkek'), # UTC+06:00
('Thimphu', 'Asia/Thimphu'), # UTC+06:00
('Yangon (Rangoon)', 'Asia/Yangon'), # UTC+06:30
('Cocos Islands', 'Indian/Cocos'), # UTC+06:30
('Bangkok', 'Asia/Bangkok'), # UTC+07:00
('Hanoi', 'Asia/Ho_Chi_Minh'), # UTC+07:00
('Jakarta', 'Asia/Jakarta'), # UTC+07:00
('Novosibirsk', 'Asia/Novosibirsk'), # UTC+07:00
('Krasnoyarsk', 'Asia/Krasnoyarsk'), # UTC+07:00
('Beijing', 'Asia/Shanghai'), # UTC+08:00
('Singapore', 'Asia/Singapore'), # UTC+08:00
('Perth', 'Australia/Perth'), # UTC+08:00
('Hong Kong', 'Asia/Hong_Kong'), # UTC+08:00
('Ulaanbaatar', 'Asia/Ulaanbaatar'), # UTC+08:00
('Palau', 'Pacific/Palau'), # UTC+08:00
('Eucla', 'Australia/Eucla'), # UTC+08:45
('Tokyo', 'Asia/Tokyo'), # UTC+09:00
('Seoul', 'Asia/Seoul'), # UTC+09:00
('Yakutsk', 'Asia/Yakutsk'), # UTC+09:00
('Adelaide', 'Australia/Adelaide'), # UTC+09:30 (DST: UTC+10:30)
('Darwin', 'Australia/Darwin'), # UTC+09:30
('Sydney', 'Australia/Sydney'), # UTC+10:00 (DST: UTC+11:00)
('Brisbane', 'Australia/Brisbane'), # UTC+10:00
('Guam', 'Pacific/Guam'), # UTC+10:00
('Vladivostok', 'Asia/Vladivostok'), # UTC+10:00
('Tahiti', 'Pacific/Tahiti'), # UTC+10:00
('Lord Howe Island', 'Australia/Lord_Howe'), # UTC+10:30 (DST: UTC+11:00)
('Solomon Islands', 'Pacific/Guadalcanal'), # UTC+11:00
('Magadan', 'Asia/Magadan'), # UTC+11:00
('Norfolk Island', 'Pacific/Norfolk'), # UTC+11:00
('Bougainville Island', 'Pacific/Bougainville'), # UTC+11:00
('Chokurdakh', 'Asia/Srednekolymsk'), # UTC+11:00
('Auckland', 'Pacific/Auckland'), # UTC+12:00 (DST: UTC+13:00)
('Wellington', 'Pacific/Auckland'), # UTC+12:00 (DST: UTC+13:00)
('Fiji Islands', 'Pacific/Fiji'), # UTC+12:00 (DST: UTC+13:00)
('Anadyr', 'Asia/Anadyr'), # UTC+12:00
('Chatham Islands', 'Pacific/Chatham'), # UTC+12:45 (DST: UTC+13:45)
("Nuku'alofa", 'Pacific/Tongatapu'), # UTC+13:00
('Samoa', 'Pacific/Apia'), # UTC+13:00 (DST: UTC+14:00)
('Kiritimati Island', 'Pacific/Kiritimati') # UTC+14:00
]
timezone_list = []
now = datetime.now()
# Process timezone mapping
for friendly_name, tz_identifier in timezone_locations:
try:
tz = pytz.timezone(tz_identifier)
current_offset = now.astimezone(tz).strftime("%z")
# converting and formatting UTC offset to GMT offset
current_utc_offset = now.astimezone(tz).utcoffset()
total_seconds = int(current_utc_offset.total_seconds())
hours_offset = total_seconds // 3600
minutes_offset = abs(total_seconds % 3600) // 60
offset = (
f"{'+' if hours_offset >= 0 else '-'}"
f"{abs(hours_offset):02}:{minutes_offset:02}"
)
timezone_value = {
"offset": int(current_offset),
"utc_offset": f"UTC{offset}",
"gmt_offset": f"GMT{offset}",
"value": tz_identifier,
"label": f"{friendly_name}",
}
timezone_list.append(timezone_value)
except pytz.exceptions.UnknownTimeZoneError:
continue
# Sort by offset and then by label
timezone_list.sort(key=lambda x: (x["offset"], x["label"]))
# Remove offset from final output
for tz in timezone_list:
del tz["offset"]
return Response({"timezones": timezone_list}, status=status.HTTP_200_OK)

View File

@@ -1,40 +0,0 @@
# Django imports
from django.conf import settings
from django.http import HttpRequest
# Third party imports
from rest_framework.request import Request
# Module imports
from plane.utils.ip_address import get_client_ip
def base_host(request: Request | HttpRequest, is_admin: bool = False, is_space: bool = False, is_app: bool = False) -> str:
"""Utility function to return host / origin from the request"""
# Calculate the base origin from request
base_origin = settings.WEB_URL or settings.APP_BASE_URL
# Admin redirections
if is_admin:
if settings.ADMIN_BASE_URL:
return settings.ADMIN_BASE_URL
else:
return base_origin + "/god-mode/"
# Space redirections
if is_space:
if settings.SPACE_BASE_URL:
return settings.SPACE_BASE_URL
else:
return base_origin + "/spaces/"
# App Redirection
if is_app:
if settings.APP_BASE_URL:
return settings.APP_BASE_URL
else:
return base_origin
return base_origin
def user_ip(request: Request | HttpRequest) -> str:
return get_client_ip(request=request)

View File

@@ -1,407 +0,0 @@
# Python imports
import csv
import io
import json
import zipfile
import boto3
from botocore.client import Config
# Third party imports
from celery import shared_task
# Django imports
from django.conf import settings
from django.utils import timezone
from openpyxl import Workbook
# Module imports
from plane.db.models import ExporterHistory, Issue
from plane.utils.exception_logger import log_exception
def dateTimeConverter(time):
if time:
return time.strftime("%a, %d %b %Y %I:%M:%S %Z%z")
def dateConverter(time):
if time:
return time.strftime("%a, %d %b %Y")
def create_csv_file(data):
csv_buffer = io.StringIO()
csv_writer = csv.writer(csv_buffer, delimiter=",", quoting=csv.QUOTE_ALL)
for row in data:
csv_writer.writerow(row)
csv_buffer.seek(0)
return csv_buffer.getvalue()
def create_json_file(data):
return json.dumps(data)
def create_xlsx_file(data):
workbook = Workbook()
sheet = workbook.active
for row in data:
sheet.append(row)
xlsx_buffer = io.BytesIO()
workbook.save(xlsx_buffer)
xlsx_buffer.seek(0)
return xlsx_buffer.getvalue()
def create_zip_file(files):
zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zipf:
for filename, file_content in files:
zipf.writestr(filename, file_content)
zip_buffer.seek(0)
return zip_buffer
def upload_to_s3(zip_file, workspace_id, token_id, slug):
file_name = (
f"{workspace_id}/export-{slug}-{token_id[:6]}-{str(timezone.now().date())}.zip"
)
expires_in = 7 * 24 * 60 * 60
if settings.USE_MINIO:
upload_s3 = boto3.client(
"s3",
endpoint_url=settings.AWS_S3_ENDPOINT_URL,
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
config=Config(signature_version="s3v4"),
)
upload_s3.upload_fileobj(
zip_file,
settings.AWS_STORAGE_BUCKET_NAME,
file_name,
ExtraArgs={"ACL": "public-read", "ContentType": "application/zip"},
)
# Generate presigned url for the uploaded file with different base
presign_s3 = boto3.client(
"s3",
endpoint_url=f"{settings.AWS_S3_URL_PROTOCOL}//{str(settings.AWS_S3_CUSTOM_DOMAIN).replace('/uploads', '')}/",
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
config=Config(signature_version="s3v4"),
)
presigned_url = presign_s3.generate_presigned_url(
"get_object",
Params={"Bucket": settings.AWS_STORAGE_BUCKET_NAME, "Key": file_name},
ExpiresIn=expires_in,
)
else:
# If endpoint url is present, use it
if settings.AWS_S3_ENDPOINT_URL:
s3 = boto3.client(
"s3",
endpoint_url=settings.AWS_S3_ENDPOINT_URL,
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
config=Config(signature_version="s3v4"),
)
else:
s3 = boto3.client(
"s3",
region_name=settings.AWS_REGION,
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
config=Config(signature_version="s3v4"),
)
# Upload the file to S3
s3.upload_fileobj(
zip_file,
settings.AWS_STORAGE_BUCKET_NAME,
file_name,
ExtraArgs={"ContentType": "application/zip"},
)
# Generate presigned url for the uploaded file
presigned_url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": settings.AWS_STORAGE_BUCKET_NAME, "Key": file_name},
ExpiresIn=expires_in,
)
exporter_instance = ExporterHistory.objects.get(token=token_id)
# Update the exporter instance with the presigned url
if presigned_url:
exporter_instance.url = presigned_url
exporter_instance.status = "completed"
exporter_instance.key = file_name
else:
exporter_instance.status = "failed"
exporter_instance.save(update_fields=["status", "url", "key"])
def generate_table_row(issue):
return [
f"""{issue["project__identifier"]}-{issue["sequence_id"]}""",
issue["project__name"],
issue["name"],
issue["description_stripped"],
issue["state__name"],
dateConverter(issue["start_date"]),
dateConverter(issue["target_date"]),
issue["priority"],
(
f"{issue['created_by__first_name']} {issue['created_by__last_name']}"
if issue["created_by__first_name"] and issue["created_by__last_name"]
else ""
),
(
f"{issue['assignees__first_name']} {issue['assignees__last_name']}"
if issue["assignees__first_name"] and issue["assignees__last_name"]
else ""
),
issue["labels__name"] if issue["labels__name"] else "",
issue["issue_cycle__cycle__name"],
dateConverter(issue["issue_cycle__cycle__start_date"]),
dateConverter(issue["issue_cycle__cycle__end_date"]),
issue["issue_module__module__name"],
dateConverter(issue["issue_module__module__start_date"]),
dateConverter(issue["issue_module__module__target_date"]),
dateTimeConverter(issue["created_at"]),
dateTimeConverter(issue["updated_at"]),
dateTimeConverter(issue["completed_at"]),
dateTimeConverter(issue["archived_at"]),
]
def generate_json_row(issue):
return {
"ID": f"""{issue["project__identifier"]}-{issue["sequence_id"]}""",
"Project": issue["project__name"],
"Name": issue["name"],
"Description": issue["description_stripped"],
"State": issue["state__name"],
"Start Date": dateConverter(issue["start_date"]),
"Target Date": dateConverter(issue["target_date"]),
"Priority": issue["priority"],
"Created By": (
f"{issue['created_by__first_name']} {issue['created_by__last_name']}"
if issue["created_by__first_name"] and issue["created_by__last_name"]
else ""
),
"Assignee": (
f"{issue['assignees__first_name']} {issue['assignees__last_name']}"
if issue["assignees__first_name"] and issue["assignees__last_name"]
else ""
),
"Labels": issue["labels__name"] if issue["labels__name"] else "",
"Cycle Name": issue["issue_cycle__cycle__name"],
"Cycle Start Date": dateConverter(issue["issue_cycle__cycle__start_date"]),
"Cycle End Date": dateConverter(issue["issue_cycle__cycle__end_date"]),
"Module Name": issue["issue_module__module__name"],
"Module Start Date": dateConverter(issue["issue_module__module__start_date"]),
"Module Target Date": dateConverter(issue["issue_module__module__target_date"]),
"Created At": dateTimeConverter(issue["created_at"]),
"Updated At": dateTimeConverter(issue["updated_at"]),
"Completed At": dateTimeConverter(issue["completed_at"]),
"Archived At": dateTimeConverter(issue["archived_at"]),
}
def update_json_row(rows, row):
matched_index = next(
(
index
for index, existing_row in enumerate(rows)
if existing_row["ID"] == row["ID"]
),
None,
)
if matched_index is not None:
existing_assignees, existing_labels = (
rows[matched_index]["Assignee"],
rows[matched_index]["Labels"],
)
assignee, label = row["Assignee"], row["Labels"]
if assignee is not None and (
existing_assignees is None or label not in existing_assignees
):
rows[matched_index]["Assignee"] += f", {assignee}"
if label is not None and (
existing_labels is None or label not in existing_labels
):
rows[matched_index]["Labels"] += f", {label}"
else:
rows.append(row)
def update_table_row(rows, row):
matched_index = next(
(index for index, existing_row in enumerate(rows) if existing_row[0] == row[0]),
None,
)
if matched_index is not None:
existing_assignees, existing_labels = rows[matched_index][7:9]
assignee, label = row[7:9]
if assignee is not None and (
existing_assignees is None or label not in existing_assignees
):
rows[matched_index][8] += f", {assignee}"
if label is not None and (
existing_labels is None or label not in existing_labels
):
rows[matched_index][8] += f", {label}"
else:
rows.append(row)
def generate_csv(header, project_id, issues, files):
"""
Generate CSV export for all the passed issues.
"""
rows = [header]
for issue in issues:
row = generate_table_row(issue)
update_table_row(rows, row)
csv_file = create_csv_file(rows)
files.append((f"{project_id}.csv", csv_file))
def generate_json(header, project_id, issues, files):
rows = []
for issue in issues:
row = generate_json_row(issue)
update_json_row(rows, row)
json_file = create_json_file(rows)
files.append((f"{project_id}.json", json_file))
def generate_xlsx(header, project_id, issues, files):
rows = [header]
for issue in issues:
row = generate_table_row(issue)
update_table_row(rows, row)
xlsx_file = create_xlsx_file(rows)
files.append((f"{project_id}.xlsx", xlsx_file))
@shared_task
def issue_export_task(provider, workspace_id, project_ids, token_id, multiple, slug):
try:
exporter_instance = ExporterHistory.objects.get(token=token_id)
exporter_instance.status = "processing"
exporter_instance.save(update_fields=["status"])
workspace_issues = (
(
Issue.objects.filter(
workspace__id=workspace_id,
project_id__in=project_ids,
project__project_projectmember__member=exporter_instance.initiated_by_id,
project__project_projectmember__is_active=True,
project__archived_at__isnull=True,
)
.select_related("project", "workspace", "state", "parent", "created_by")
.prefetch_related(
"assignees", "labels", "issue_cycle__cycle", "issue_module__module"
)
.values(
"id",
"project__identifier",
"project__name",
"project__id",
"sequence_id",
"name",
"description_stripped",
"priority",
"start_date",
"target_date",
"state__name",
"created_at",
"updated_at",
"completed_at",
"archived_at",
"issue_cycle__cycle__name",
"issue_cycle__cycle__start_date",
"issue_cycle__cycle__end_date",
"issue_module__module__name",
"issue_module__module__start_date",
"issue_module__module__target_date",
"created_by__first_name",
"created_by__last_name",
"assignees__first_name",
"assignees__last_name",
"labels__name",
)
)
.order_by("project__identifier", "sequence_id")
.distinct()
)
# CSV header
header = [
"ID",
"Project",
"Name",
"Description",
"State",
"Start Date",
"Target Date",
"Priority",
"Created By",
"Assignee",
"Labels",
"Cycle Name",
"Cycle Start Date",
"Cycle End Date",
"Module Name",
"Module Start Date",
"Module Target Date",
"Created At",
"Updated At",
"Completed At",
"Archived At",
]
EXPORTER_MAPPER = {
"csv": generate_csv,
"json": generate_json,
"xlsx": generate_xlsx,
}
files = []
if multiple:
for project_id in project_ids:
issues = workspace_issues.filter(project__id=project_id)
exporter = EXPORTER_MAPPER.get(provider)
if exporter is not None:
exporter(header, project_id, issues, files)
else:
exporter = EXPORTER_MAPPER.get(provider)
if exporter is not None:
exporter(header, workspace_id, workspace_issues, files)
zip_buffer = create_zip_file(files)
upload_to_s3(zip_buffer, workspace_id, token_id, slug)
except Exception as e:
exporter_instance = ExporterHistory.objects.get(token=token_id)
exporter_instance.status = "failed"
exporter_instance.reason = str(e)
exporter_instance.save(update_fields=["status", "reason"])
log_exception(e)
return

View File

@@ -1,39 +0,0 @@
import uuid
# Django imports
from django.db import models
# Third party imports
from crum import get_current_user
# Module imports
from ..mixins import AuditModel
class BaseModel(AuditModel):
id = models.UUIDField(
default=uuid.uuid4, unique=True, editable=False, db_index=True, primary_key=True
)
class Meta:
abstract = True
def save(self, *args, **kwargs):
user = get_current_user()
if user is None or user.is_anonymous:
self.created_by = None
self.updated_by = None
super(BaseModel, self).save(*args, **kwargs)
else:
# Check if the model is being created or updated
if self._state.adding:
# If created only set created_by value: set updated_by to None
self.created_by = user
self.updated_by = None
# If updated only set updated_by value don't touch created_by
self.updated_by = user
super(BaseModel, self).save(*args, **kwargs)
def __str__(self):
return str(self.id)

View File

@@ -1,40 +0,0 @@
# Module imports
from plane.db.models import APIActivityLog
from plane.utils.ip_address import get_client_ip
class APITokenLogMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request_body = request.body
response = self.get_response(request)
self.process_request(request, response, request_body)
return response
def process_request(self, request, response, request_body):
api_key_header = "X-Api-Key"
api_key = request.headers.get(api_key_header)
# If the API key is present, log the request
if api_key:
try:
APIActivityLog.objects.create(
token_identifier=api_key,
path=request.path,
method=request.method,
query_params=request.META.get("QUERY_STRING", ""),
headers=str(request.headers),
body=(request_body.decode("utf-8") if request_body else None),
response_body=(
response.content.decode("utf-8") if response.content else None
),
response_code=response.status_code,
ip_address=get_client_ip(request=request),
user_agent=request.META.get("HTTP_USER_AGENT", None),
)
except Exception as e:
print(e)
# If the token does not exist, you can decide whether to log this as an invalid attempt
return None

View File

@@ -1 +0,0 @@
from .api import *

View File

@@ -1,34 +0,0 @@
# Third party imports
from rest_framework.test import APITestCase, APIClient
# Module imports
from plane.db.models import User
from plane.app.views.authentication import get_tokens_for_user
class BaseAPITest(APITestCase):
def setUp(self):
self.client = APIClient(HTTP_USER_AGENT="plane/test", REMOTE_ADDR="10.10.10.10")
class AuthenticatedAPITest(BaseAPITest):
def setUp(self):
super().setUp()
## Create Dummy User
self.email = "user@plane.so"
user = User.objects.create(email=self.email)
user.set_password("user@123")
user.save()
# Set user
self.user = user
# Set Up User ID
self.user_id = user.id
access_token, _ = get_tokens_for_user(user)
self.access_token = access_token
# Set Up Authentication Token
self.client.credentials(HTTP_AUTHORIZATION="Bearer " + access_token)

View File

@@ -1 +0,0 @@
# TODO: Tests for File Asset Uploads

View File

@@ -1 +0,0 @@
# TODO: Tests for ChangePassword and other Endpoints

View File

@@ -1,183 +0,0 @@
# Python import
import json
# Django imports
from django.urls import reverse
# Third Party imports
from rest_framework import status
from .base import BaseAPITest
# Module imports
from plane.db.models import User
from plane.settings.redis import redis_instance
class SignInEndpointTests(BaseAPITest):
def setUp(self):
super().setUp()
user = User.objects.create(email="user@plane.so")
user.set_password("user@123")
user.save()
def test_without_data(self):
url = reverse("sign-in")
response = self.client.post(url, {}, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_email_validity(self):
url = reverse("sign-in")
response = self.client.post(
url, {"email": "useremail.com", "password": "user@123"}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data, {"error": "Please provide a valid email address."}
)
def test_password_validity(self):
url = reverse("sign-in")
response = self.client.post(
url, {"email": "user@plane.so", "password": "user123"}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(
response.data,
{
"error": "Sorry, we could not find a user with the provided credentials. Please try again."
},
)
def test_user_exists(self):
url = reverse("sign-in")
response = self.client.post(
url, {"email": "user@email.so", "password": "user123"}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(
response.data,
{
"error": "Sorry, we could not find a user with the provided credentials. Please try again."
},
)
def test_user_login(self):
url = reverse("sign-in")
response = self.client.post(
url, {"email": "user@plane.so", "password": "user@123"}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data.get("user").get("email"), "user@plane.so")
class MagicLinkGenerateEndpointTests(BaseAPITest):
def setUp(self):
super().setUp()
user = User.objects.create(email="user@plane.so")
user.set_password("user@123")
user.save()
def test_without_data(self):
url = reverse("magic-generate")
response = self.client.post(url, {}, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
def test_email_validity(self):
url = reverse("magic-generate")
response = self.client.post(url, {"email": "useremail.com"}, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data, {"error": "Please provide a valid email address."}
)
def test_magic_generate(self):
url = reverse("magic-generate")
ri = redis_instance()
ri.delete("magic_user@plane.so")
response = self.client.post(url, {"email": "user@plane.so"}, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_max_generate_attempt(self):
url = reverse("magic-generate")
ri = redis_instance()
ri.delete("magic_user@plane.so")
for _ in range(4):
response = self.client.post(url, {"email": "user@plane.so"}, format="json")
response = self.client.post(url, {"email": "user@plane.so"}, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data, {"error": "Max attempts exhausted. Please try again later."}
)
class MagicSignInEndpointTests(BaseAPITest):
def setUp(self):
super().setUp()
user = User.objects.create(email="user@plane.so")
user.set_password("user@123")
user.save()
def test_without_data(self):
url = reverse("magic-sign-in")
response = self.client.post(url, {}, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.data, {"error": "User token and key are required"})
def test_expired_invalid_magic_link(self):
ri = redis_instance()
ri.delete("magic_user@plane.so")
url = reverse("magic-sign-in")
response = self.client.post(
url,
{"key": "magic_user@plane.so", "token": "xxxx-xxxxx-xxxx"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data, {"error": "The magic code/link has expired please try again"}
)
def test_invalid_magic_code(self):
ri = redis_instance()
ri.delete("magic_user@plane.so")
## Create Token
url = reverse("magic-generate")
self.client.post(url, {"email": "user@plane.so"}, format="json")
url = reverse("magic-sign-in")
response = self.client.post(
url,
{"key": "magic_user@plane.so", "token": "xxxx-xxxxx-xxxx"},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
response.data, {"error": "Your login code was incorrect. Please try again."}
)
def test_magic_code_sign_in(self):
ri = redis_instance()
ri.delete("magic_user@plane.so")
## Create Token
url = reverse("magic-generate")
self.client.post(url, {"email": "user@plane.so"}, format="json")
# Get the token
user_data = json.loads(ri.get("magic_user@plane.so"))
token = user_data["token"]
url = reverse("magic-sign-in")
response = self.client.post(
url, {"key": "magic_user@plane.so", "token": token}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data.get("user").get("email"), "user@plane.so")

View File

@@ -1 +0,0 @@
# TODO: Write Test for Cycle Endpoints

View File

@@ -1 +0,0 @@
# TODO: Write Test for Issue Endpoints

View File

@@ -1 +0,0 @@
# TODO: Tests for OAuth Authentication Endpoint

View File

@@ -1 +0,0 @@
# TODO: Write Test for people Endpoint

View File

@@ -1 +0,0 @@
# TODO: Write Tests for project endpoints

View File

@@ -1 +0,0 @@
# TODO: Write Test for shortcuts

View File

@@ -1 +0,0 @@
# TODO: Wrote test for state endpoints

View File

@@ -1 +0,0 @@
# TODO: Write test for view endpoints

View File

@@ -1,44 +0,0 @@
# Django imports
from django.urls import reverse
# Third party import
from rest_framework import status
# Module imports
from .base import AuthenticatedAPITest
from plane.db.models import Workspace, WorkspaceMember
class WorkSpaceCreateReadUpdateDelete(AuthenticatedAPITest):
def setUp(self):
super().setUp()
def test_create_workspace(self):
url = reverse("workspace")
# Test with empty data
response = self.client.post(url, {}, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
# Test with valid data
response = self.client.post(
url, {"name": "Plane", "slug": "pla-ne"}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Workspace.objects.count(), 1)
# Check if the member is created
self.assertEqual(WorkspaceMember.objects.count(), 1)
# Check other values
workspace = Workspace.objects.get(pk=response.data["id"])
workspace_member = WorkspaceMember.objects.get(
workspace=workspace, member_id=self.user_id
)
self.assertEqual(workspace.owner_id, self.user_id)
self.assertEqual(workspace_member.role, 20)
# Create a already existing workspace
response = self.client.post(
url, {"name": "Plane", "slug": "pla-ne"}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_410_GONE)

View File

@@ -1,18 +0,0 @@
# Python imports
import logging
import traceback
# Django imports
from django.conf import settings
def log_exception(e):
# Log the error
logger = logging.getLogger("plane")
logger.error(e)
if settings.DEBUG:
# Print the traceback if in debug mode
print(traceback.format_exc())
return

View File

@@ -1,45 +0,0 @@
# Django imports
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.http import HttpRequest
# Third party imports
from rest_framework.request import Request
# Module imports
from plane.utils.ip_address import get_client_ip
def base_host(request: Request | HttpRequest, is_admin: bool = False, is_space: bool = False, is_app: bool = False) -> str:
"""Utility function to return host / origin from the request"""
# Calculate the base origin from request
base_origin = settings.WEB_URL or settings.APP_BASE_URL
if not base_origin:
raise ImproperlyConfigured("APP_BASE_URL or WEB_URL is not set")
# Admin redirections
if is_admin:
if settings.ADMIN_BASE_URL:
return settings.ADMIN_BASE_URL
else:
return base_origin + "/god-mode/"
# Space redirections
if is_space:
if settings.SPACE_BASE_URL:
return settings.SPACE_BASE_URL
else:
return base_origin + "/spaces/"
# App Redirection
if is_app:
if settings.APP_BASE_URL:
return settings.APP_BASE_URL
else:
return base_origin
return base_origin
def user_ip(request: Request | HttpRequest) -> str:
return get_client_ip(request=request)

View File

@@ -1,8 +0,0 @@
import uuid
def is_valid_uuid(uuid_str):
try:
uuid.UUID(uuid_str, version=4)
return True
except ValueError:
return False

View File

@@ -1,4 +0,0 @@
from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [path("about/", TemplateView.as_view(template_name="about.html"))]

View File

@@ -1 +0,0 @@
# Create your views here.

View File

@@ -1,4 +0,0 @@
-r base.txt
# test checker
pytest==7.1.2
coverage==6.5.0

View File

@@ -1 +0,0 @@
python-3.12.6

View File

@@ -1,9 +0,0 @@
{% extends 'base.html' %}
{% load static %}
{% block content %}
<h1>Hello from plane!</h1>
<p>Made with Django</p>
{% endblock content %}

View File

@@ -1,5 +0,0 @@
{% extends 'base.html' %} {% load static %} {% block content %}
<div class="container mt-5">
<h1>Hello from plane!</h1>
</div>
{% endblock content %}

View File

@@ -1,73 +0,0 @@
{
"name": "Plane",
"description": "Plane helps you track your issues, epics, and product roadmaps.",
"repository": "http://github.com/makeplane/plane",
"logo": "https://avatars.githubusercontent.com/u/115727700?s=200&v=4",
"website": "https://plane.so/",
"success_url": "/",
"stack": "heroku-22",
"keywords": ["plane", "project management", "django", "next"],
"addons": ["heroku-postgresql:mini", "heroku-redis:mini"],
"buildpacks": [
{
"url": "https://github.com/heroku/heroku-buildpack-python.git"
},
{
"url": "https://github.com/heroku/heroku-buildpack-nodejs#v176"
}
],
"env": {
"EMAIL_HOST": {
"description": "Email host to send emails from",
"value": ""
},
"EMAIL_HOST_USER": {
"description": "Email host to send emails from",
"value": ""
},
"EMAIL_HOST_PASSWORD": {
"description": "Email host to send emails from",
"value": ""
},
"EMAIL_FROM": {
"description": "Email Sender",
"value": ""
},
"EMAIL_PORT": {
"description": "The default Email PORT to use",
"value": "587"
},
"AWS_REGION": {
"description": "AWS Region to use for S3",
"value": "false"
},
"AWS_ACCESS_KEY_ID": {
"description": "AWS Access Key ID to use for S3",
"value": ""
},
"AWS_SECRET_ACCESS_KEY": {
"description": "AWS Secret Access Key to use for S3",
"value": ""
},
"AWS_S3_BUCKET_NAME": {
"description": "AWS Bucket Name to use for S3",
"value": ""
},
"WEB_URL": {
"description": "Web URL for Plane this will be used for redirections in the emails",
"value": ""
},
"GITHUB_CLIENT_SECRET": {
"description": "GitHub Client Secret",
"value": ""
},
"NEXT_PUBLIC_API_BASE_URL": {
"description": "Next Public API Base URL",
"value": ""
},
"SECRET_KEY": {
"description": "Django Secret Key",
"value": ""
}
}
}

12
apps/admin/.env.example Normal file
View File

@@ -0,0 +1,12 @@
NEXT_PUBLIC_API_BASE_URL="http://localhost:8000"
NEXT_PUBLIC_WEB_BASE_URL="http://localhost:3000"
NEXT_PUBLIC_ADMIN_BASE_URL="http://localhost:3001"
NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode"
NEXT_PUBLIC_SPACE_BASE_URL="http://localhost:3002"
NEXT_PUBLIC_SPACE_BASE_PATH="/spaces"
NEXT_PUBLIC_LIVE_BASE_URL="http://localhost:3100"
NEXT_PUBLIC_LIVE_BASE_PATH="/live"

View File

@@ -1,4 +1,4 @@
FROM node:20-alpine as base
FROM node:22-alpine AS base
# *****************************************************************************
# STAGE 1: Build the project
@@ -46,8 +46,8 @@ ENV NEXT_PUBLIC_SPACE_BASE_PATH=$NEXT_PUBLIC_SPACE_BASE_PATH
ARG NEXT_PUBLIC_WEB_BASE_URL=""
ENV NEXT_PUBLIC_WEB_BASE_URL=$NEXT_PUBLIC_WEB_BASE_URL
ENV NEXT_TELEMETRY_DISABLED 1
ENV TURBO_TELEMETRY_DISABLED 1
ENV NEXT_TELEMETRY_DISABLED=1
ENV TURBO_TELEMETRY_DISABLED=1
RUN yarn turbo run build --filter=admin
@@ -57,12 +57,16 @@ RUN yarn turbo run build --filter=admin
FROM base AS runner
WORKDIR /app
COPY --from=installer /app/admin/next.config.js .
COPY --from=installer /app/admin/package.json .
# Don't run production as root
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs
COPY --from=installer /app/admin/.next/standalone ./
COPY --from=installer /app/admin/.next/static ./admin/.next/static
COPY --from=installer /app/admin/public ./admin/public
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=installer /app/apps/admin/.next/standalone ./
COPY --from=installer /app/apps/admin/.next/static ./apps/admin/.next/static
COPY --from=installer /app/apps/admin/public ./apps/admin/public
ARG NEXT_PUBLIC_API_BASE_URL=""
ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL
@@ -82,7 +86,9 @@ ENV NEXT_PUBLIC_SPACE_BASE_PATH=$NEXT_PUBLIC_SPACE_BASE_PATH
ARG NEXT_PUBLIC_WEB_BASE_URL=""
ENV NEXT_PUBLIC_WEB_BASE_URL=$NEXT_PUBLIC_WEB_BASE_URL
ENV NEXT_TELEMETRY_DISABLED 1
ENV TURBO_TELEMETRY_DISABLED 1
ENV NEXT_TELEMETRY_DISABLED=1
ENV TURBO_TELEMETRY_DISABLED=1
EXPOSE 3000
EXPOSE 3000
CMD ["node", "apps/admin/server.js"]

View File

@@ -1,4 +1,4 @@
FROM node:20-alpine
FROM node:22-alpine
RUN apk add --no-cache libc6-compat
# Set working directory
WORKDIR /app

View File

@@ -5,7 +5,7 @@ import { Lightbulb } from "lucide-react";
import { IFormattedInstanceConfiguration, TInstanceAIConfigurationKeys } from "@plane/types";
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
// components
import { ControllerInput, TControllerInputFormField } from "@/components/common";
import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
// hooks
import { useInstance } from "@/hooks/store";
@@ -26,16 +26,16 @@ export const InstanceAIForm: FC<IInstanceAIForm> = (props) => {
formState: { errors, isSubmitting },
} = useForm<AIFormValues>({
defaultValues: {
OPENAI_API_KEY: config["OPENAI_API_KEY"],
GPT_ENGINE: config["GPT_ENGINE"],
LLM_API_KEY: config["LLM_API_KEY"],
LLM_MODEL: config["LLM_MODEL"],
},
});
const aiFormFields: TControllerInputFormField[] = [
{
key: "GPT_ENGINE",
key: "LLM_MODEL",
type: "text",
label: "GPT_ENGINE",
label: "LLM Model",
description: (
<>
Choose an OpenAI engine.{" "}
@@ -49,12 +49,12 @@ export const InstanceAIForm: FC<IInstanceAIForm> = (props) => {
</a>
</>
),
placeholder: "gpt-3.5-turbo",
error: Boolean(errors.GPT_ENGINE),
placeholder: "gpt-4o-mini",
error: Boolean(errors.LLM_MODEL),
required: false,
},
{
key: "OPENAI_API_KEY",
key: "LLM_API_KEY",
type: "password",
label: "API key",
description: (
@@ -71,7 +71,7 @@ export const InstanceAIForm: FC<IInstanceAIForm> = (props) => {
</>
),
placeholder: "sk-asddassdfasdefqsdfasd23das3dasdcasd",
error: Boolean(errors.OPENAI_API_KEY),
error: Boolean(errors.LLM_API_KEY),
required: false,
},
];

View File

@@ -1,11 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
title: "Artificial Intelligence Settings - Plane Web",
title: "Artificial Intelligence Settings - God Mode",
};
export default function AILayout({ children }: { children: ReactNode }) {
return <AdminLayout>{children}</AdminLayout>;
return <>{children}</>;
}

View File

@@ -10,14 +10,10 @@ import { IFormattedInstanceConfiguration, TInstanceGithubAuthenticationConfigura
import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
import { cn } from "@plane/utils";
// components
import {
CodeBlock,
ConfirmDiscardModal,
ControllerInput,
CopyField,
TControllerInputFormField,
TCopyField,
} from "@/components/common";
import { CodeBlock } from "@/components/common/code-block";
import { ConfirmDiscardModal } from "@/components/common/confirm-discard-modal";
import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
import { CopyField, TCopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";
@@ -98,11 +94,7 @@ export const InstanceGithubConfigForm: FC<Props> = (props) => {
key: "GITHUB_ORGANIZATION_ID",
type: "text",
label: "Organization ID",
description: (
<>
The organization github ID.
</>
),
description: <>The organization github ID.</>,
placeholder: "123456789",
error: Boolean(errors.GITHUB_ORGANIZATION_ID),
required: false,

View File

@@ -0,0 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "GitHub Authentication - God Mode",
};
export default function GitHubAuthenticationLayout({ children }: { children: ReactNode }) {
return <>{children}</>;
}

View File

@@ -9,8 +9,7 @@ import useSWR from "swr";
import { Loader, ToggleSwitch, setPromiseToast } from "@plane/ui";
import { resolveGeneralTheme } from "@plane/utils";
// components
import { AuthenticationMethodCard } from "@/components/authentication";
import { PageHeader } from "@/components/common";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
@@ -61,9 +60,11 @@ const InstanceGithubAuthenticationPage = observer(() => {
setIsSubmitting(false);
});
};
const isGithubEnabled = enableGithubConfig === "1";
return (
<>
<PageHeader title="GitHub Authentication - Plane Web" />
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
<AuthenticationMethodCard
@@ -79,11 +80,9 @@ const InstanceGithubAuthenticationPage = observer(() => {
}
config={
<ToggleSwitch
value={Boolean(parseInt(enableGithubConfig))}
value={isGithubEnabled}
onChange={() => {
Boolean(parseInt(enableGithubConfig)) === true
? updateConfig("IS_GITHUB_ENABLED", "0")
: updateConfig("IS_GITHUB_ENABLED", "1");
updateConfig("IS_GITHUB_ENABLED", isGithubEnabled ? "0" : "1");
}}
size="sm"
disabled={isSubmitting || !formattedConfig}

View File

@@ -8,14 +8,10 @@ import { IFormattedInstanceConfiguration, TInstanceGitlabAuthenticationConfigura
import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
import { cn } from "@plane/utils";
// components
import {
CodeBlock,
ConfirmDiscardModal,
ControllerInput,
CopyField,
TControllerInputFormField,
TCopyField,
} from "@/components/common";
import { CodeBlock } from "@/components/common/code-block";
import { ConfirmDiscardModal } from "@/components/common/confirm-discard-modal";
import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
import { CopyField, TCopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";

View File

@@ -0,0 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "GitLab Authentication - God Mode",
};
export default function GitlabAuthenticationLayout({ children }: { children: ReactNode }) {
return <>{children}</>;
}

View File

@@ -6,8 +6,7 @@ import Image from "next/image";
import useSWR from "swr";
import { Loader, ToggleSwitch, setPromiseToast } from "@plane/ui";
// components
import { AuthenticationMethodCard } from "@/components/authentication";
import { PageHeader } from "@/components/common";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
@@ -57,7 +56,6 @@ const InstanceGitlabAuthenticationPage = observer(() => {
};
return (
<>
<PageHeader title="GitLab Authentication - Plane Web" />
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
<AuthenticationMethodCard

View File

@@ -9,14 +9,10 @@ import { IFormattedInstanceConfiguration, TInstanceGoogleAuthenticationConfigura
import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
import { cn } from "@plane/utils";
// components
import {
CodeBlock,
ConfirmDiscardModal,
ControllerInput,
CopyField,
TControllerInputFormField,
TCopyField,
} from "@/components/common";
import { CodeBlock } from "@/components/common/code-block";
import { ConfirmDiscardModal } from "@/components/common/confirm-discard-modal";
import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
import { CopyField, TCopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";

View File

@@ -0,0 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Google Authentication - God Mode",
};
export default function GoogleAuthenticationLayout({ children }: { children: ReactNode }) {
return <>{children}</>;
}

View File

@@ -6,8 +6,7 @@ import Image from "next/image";
import useSWR from "swr";
import { Loader, ToggleSwitch, setPromiseToast } from "@plane/ui";
// components
import { AuthenticationMethodCard } from "@/components/authentication";
import { PageHeader } from "@/components/common";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
@@ -57,7 +56,6 @@ const InstanceGoogleAuthenticationPage = observer(() => {
};
return (
<>
<PageHeader title="Google Authentication - Plane Web" />
<div className="relative container mx-auto w-full h-full p-4 py-4 space-y-6 flex flex-col">
<div className="border-b border-custom-border-100 mx-4 py-4 space-y-1 flex-shrink-0">
<AuthenticationMethodCard

View File

@@ -1,11 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
title: "Authentication Settings - Plane Web",
};
export default function AuthenticationLayout({ children }: { children: ReactNode }) {
return <AdminLayout>{children}</AdminLayout>;
return <>{children}</>;
}

View File

@@ -7,7 +7,7 @@ import { IFormattedInstanceConfiguration, TInstanceEmailConfigurationKeys } from
// ui
import { Button, CustomSelect, TOAST_TYPE, setToast } from "@plane/ui";
// components
import { ControllerInput, TControllerInputFormField } from "@/components/common";
import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
// hooks
import { useInstance } from "@/hooks/store";
// local components

View File

@@ -1,15 +1,14 @@
import { ReactNode } from "react";
import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout";
interface EmailLayoutProps {
children: ReactNode;
}
export const metadata: Metadata = {
title: "Email Settings - Plane Web",
title: "Email Settings - God Mode",
};
export default function EmailLayout({ children }: EmailLayoutProps) {
return <AdminLayout>{children}</AdminLayout>;
return <>{children}</>;
}

View File

@@ -8,7 +8,7 @@ import { IInstance, IInstanceAdmin } from "@plane/types";
// ui
import { Button, Input, TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui";
// components
import { ControllerInput } from "@/components/common";
import { ControllerInput } from "@/components/common/controller-input";
import { useInstance } from "@/hooks/store";
import { IntercomConfig } from "./intercom";
// hooks

View File

@@ -1,11 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
title: "General Settings - Plane Web",
title: "General Settings - God Mode",
};
export default function GeneralLayout({ children }: { children: ReactNode }) {
return <AdminLayout>{children}</AdminLayout>;
return <>{children}</>;
}

View File

@@ -3,16 +3,27 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { usePathname } from "next/navigation";
// mobx
// ui
import { Settings } from "lucide-react";
import { Menu, Settings } from "lucide-react";
// icons
import { Breadcrumbs } from "@plane/ui";
// components
import { SidebarHamburgerToggle } from "@/components/admin-sidebar";
import { BreadcrumbLink } from "@/components/common";
import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
// hooks
import { useTheme } from "@/hooks/store";
export const InstanceHeader: FC = observer(() => {
export const HamburgerToggle: FC = observer(() => {
const { isSidebarCollapsed, toggleSidebar } = useTheme();
return (
<div
className="w-7 h-7 rounded flex justify-center items-center bg-custom-background-80 transition-all hover:bg-custom-background-90 cursor-pointer group md:hidden"
onClick={() => toggleSidebar(!isSidebarCollapsed)}
>
<Menu size={14} className="text-custom-text-200 group-hover:text-custom-text-100 transition-all" />
</div>
);
});
export const AdminHeader: FC = observer(() => {
const pathName = usePathname();
const getHeaderTitle = (pathName: string) => {
@@ -63,13 +74,12 @@ export const InstanceHeader: FC = observer(() => {
return (
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 border-b border-custom-sidebar-border-200 bg-custom-sidebar-background-100 p-4">
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
<SidebarHamburgerToggle />
<HamburgerToggle />
{breadcrumbItems.length >= 0 && (
<div>
<Breadcrumbs>
<Breadcrumbs.BreadcrumbItem
type="text"
link={
<Breadcrumbs.Item
component={
<BreadcrumbLink
href="/general/"
label="Settings"
@@ -80,10 +90,9 @@ export const InstanceHeader: FC = observer(() => {
{breadcrumbItems.map(
(item) =>
item.title && (
<Breadcrumbs.BreadcrumbItem
<Breadcrumbs.Item
key={item.title}
type="text"
link={<BreadcrumbLink href={item.href} label={item.title} />}
component={<BreadcrumbLink href={item.href} label={item.title} />}
/>
)
)}

View File

@@ -4,7 +4,7 @@ import { useForm } from "react-hook-form";
import { IFormattedInstanceConfiguration, TInstanceImageConfigurationKeys } from "@plane/types";
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
// components
import { ControllerInput } from "@/components/common";
import { ControllerInput } from "@/components/common/controller-input";
// hooks
import { useInstance } from "@/hooks/store";

View File

@@ -1,15 +1,14 @@
import { ReactNode } from "react";
import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout";
interface ImageLayoutProps {
children: ReactNode;
}
export const metadata: Metadata = {
title: "Images Settings - Plane Web",
title: "Images Settings - God Mode",
};
export default function ImageLayout({ children }: ImageLayoutProps) {
return <AdminLayout>{children}</AdminLayout>;
return <>{children}</>;
}

View File

@@ -1,20 +1,22 @@
"use client";
import { FC, ReactNode, useEffect } from "react";
import { observer } from "mobx-react";
import { useRouter } from "next/navigation";
// components
import { InstanceSidebar } from "@/components/admin-sidebar";
import { InstanceHeader } from "@/components/auth-header";
import { LogoSpinner } from "@/components/common";
import { LogoSpinner } from "@/components/common/logo-spinner";
import { NewUserPopup } from "@/components/new-user-popup";
// hooks
import { useUser } from "@/hooks/store";
// local components
import { AdminHeader } from "./header";
import { AdminSidebar } from "./sidebar";
type TAdminLayout = {
children: ReactNode;
};
export const AdminLayout: FC<TAdminLayout> = observer((props) => {
const AdminLayout: FC<TAdminLayout> = (props) => {
const { children } = props;
// router
const router = useRouter();
@@ -35,14 +37,20 @@ export const AdminLayout: FC<TAdminLayout> = observer((props) => {
);
}
return (
<div className="relative flex h-screen w-screen overflow-hidden">
<InstanceSidebar />
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
<InstanceHeader />
<div className="h-full w-full overflow-hidden">{children}</div>
</main>
<NewUserPopup />
</div>
);
});
if (isUserLoggedIn) {
return (
<div className="relative flex h-screen w-screen overflow-hidden">
<AdminSidebar />
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
<AdminHeader />
<div className="h-full w-full overflow-hidden">{children}</div>
</main>
<NewUserPopup />
</div>
);
}
return <></>;
};
export default observer(AdminLayout);

View File

@@ -7,7 +7,7 @@ import { LogOut, UserCog2, Palette } from "lucide-react";
import { Menu, Transition } from "@headlessui/react";
// plane internal packages
import { API_BASE_URL } from "@plane/constants";
import {AuthService } from "@plane/services";
import { AuthService } from "@plane/services";
import { Avatar } from "@plane/ui";
import { getFileURL, cn } from "@plane/utils";
// hooks
@@ -16,7 +16,7 @@ import { useTheme, useUser } from "@/hooks/store";
// service initialization
const authService = new AuthService();
export const SidebarDropdown = observer(() => {
export const AdminSidebarDropdown = observer(() => {
// store hooks
const { isSidebarCollapsed } = useTheme();
const { currentUser, signOut } = useUser();

View File

@@ -33,7 +33,7 @@ const helpOptions = [
},
];
export const HelpSection: FC = observer(() => {
export const AdminSidebarHelpSection: FC = observer(() => {
// states
const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false);
// store

View File

@@ -49,7 +49,7 @@ const INSTANCE_ADMIN_LINKS = [
},
];
export const SidebarMenu = observer(() => {
export const AdminSidebarMenu = observer(() => {
// store hooks
const { isSidebarCollapsed, toggleSidebar } = useTheme();
// router

View File

@@ -4,12 +4,14 @@ import { FC, useEffect, useRef } from "react";
import { observer } from "mobx-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/hooks";
// components
import { HelpSection, SidebarMenu, SidebarDropdown } from "@/components/admin-sidebar";
// hooks
import { useTheme } from "@/hooks/store";
// components
import { AdminSidebarDropdown } from "./sidebar-dropdown";
import { AdminSidebarHelpSection } from "./sidebar-help-section";
import { AdminSidebarMenu } from "./sidebar-menu";
export const InstanceSidebar: FC = observer(() => {
export const AdminSidebar: FC = observer(() => {
// store
const { isSidebarCollapsed, toggleSidebar } = useTheme();
@@ -47,9 +49,9 @@ export const InstanceSidebar: FC = observer(() => {
`}
>
<div ref={ref} className="flex h-full w-full flex-1 flex-col">
<SidebarDropdown />
<SidebarMenu />
<HelpSection />
<AdminSidebarDropdown />
<AdminSidebarMenu />
<AdminSidebarHelpSection />
</div>
</div>
);

View File

@@ -1,12 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
// layouts
import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
title: "Workspace Management - Plane Web",
title: "Workspace Management - God Mode",
};
export default function WorkspaceManagementLayout({ children }: { children: ReactNode }) {
return <AdminLayout>{children}</AdminLayout>;
return <>{children}</>;
}

View File

@@ -10,7 +10,7 @@ import { TInstanceConfigurationKeys } from "@plane/types";
import { Button, getButtonStyling, Loader, setPromiseToast, ToggleSwitch } from "@plane/ui";
import { cn } from "@plane/utils";
// components
import { WorkspaceListItem } from "@/components/workspace";
import { WorkspaceListItem } from "@/components/workspace/list-item";
// hooks
import { useInstance, useWorkspace } from "@/hooks/store";

View File

@@ -1,11 +1,11 @@
import { FC } from "react";
import { Info, X } from "lucide-react";
// plane constants
import { TAuthErrorInfo } from "@plane/constants";
import { TAdminAuthErrorInfo } from "@plane/constants";
type TAuthBanner = {
bannerData: TAuthErrorInfo | undefined;
handleBannerData?: (bannerData: TAuthErrorInfo | undefined) => void;
bannerData: TAdminAuthErrorInfo | undefined;
handleBannerData?: (bannerData: TAdminAuthErrorInfo | undefined) => void;
};
export const AuthBanner: FC<TAuthBanner> = (props) => {

View File

@@ -3,17 +3,15 @@ import Image from "next/image";
import Link from "next/link";
import { KeyRound, Mails } from "lucide-react";
// plane packages
import { SUPPORT_EMAIL, EAdminAuthErrorCodes, TAuthErrorInfo } from "@plane/constants";
import { SUPPORT_EMAIL, EAdminAuthErrorCodes, TAdminAuthErrorInfo } from "@plane/constants";
import { TGetBaseAuthenticationModeProps, TInstanceAuthenticationModes } from "@plane/types";
import { resolveGeneralTheme } from "@plane/utils";
// components
import {
EmailCodesConfiguration,
GithubConfiguration,
GitlabConfiguration,
GoogleConfiguration,
PasswordLoginConfiguration,
} from "@/components/authentication";
import { EmailCodesConfiguration } from "@/components/authentication/email-config-switch";
import { GithubConfiguration } from "@/components/authentication/github-config";
import { GitlabConfiguration } from "@/components/authentication/gitlab-config";
import { GoogleConfiguration } from "@/components/authentication/google-config";
import { PasswordLoginConfiguration } from "@/components/authentication/password-config-switch";
// images
import githubLightModeImage from "@/public/logos/github-black.png";
import githubDarkModeImage from "@/public/logos/github-white.png";
@@ -89,7 +87,7 @@ const errorCodeMessages: {
export const authErrorHandler = (
errorCode: EAdminAuthErrorCodes,
email?: string | undefined
): TAuthErrorInfo | undefined => {
): TAdminAuthErrorInfo | undefined => {
const bannerAlertErrorCodes = [
EAdminAuthErrorCodes.ADMIN_ALREADY_EXIST,
EAdminAuthErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME,

Some files were not shown because too many files have changed in this diff Show More