Compare commits

..
Author SHA1 Message Date
Palanikannan M 202336dd9c fix: rendering node views reliably 2025-12-01 16:15:33 +05:30
Vipin ChaudharyandGitHub 8db95d9ec0 [WIKI-823] fix: callout element emoji search (#8201)
* fix: emoji search input

* fix: enhance keyboard navigation in EmojiPicker component
2025-12-01 13:37:20 +05:30
b-saikrishnakanthandGitHub 27bf2575bd [WEB-5534] fix: intake state dropdown (#8199) 2025-12-01 12:50:01 +05:30
b-saikrishnakanthandGitHub 22bb3c5ecc [WEB-5490] fix: intake section filter persists incorrectly across projects (#8187) 2025-12-01 12:49:05 +05:30
Aaryan KhandelwalandGitHub 6b85d67f6c [WIKI-788] regression: copy markdown option #8200 2025-12-01 12:48:28 +05:30
Prateek ShouryaandGitHub 123f59e74b [WEB-5525] improvement: update WorkspaceMenuRoot to use variant prop for layout adjustments (#8196) 2025-11-28 19:00:25 +05:30
sriram veeraghantaandGitHub c7bf912cf2 fix: state group choices (#8198) 2025-11-28 18:06:00 +05:30
Aaryan KhandelwalandGitHub 2980836015 [WEB-5527] fix: extended sidebar (#8197) 2025-11-28 16:54:53 +05:30
78fbdde165 [WEB-5282] chore: triage state in intake (#8135)
* chore: traige state in intake

* chore: triage state changes

* feat: implement intake state dropdown component and integrate into issue properties

* chore: added the triage state validation

* chore: added triage state filter

* chore: added workspace filter

* fix: migration file

* chore: added triage group state check

* chore: updated the filters

* chore: updated the filters

* chore: added variables for intake state

* fix: import error

* refactor: improve project intake state retrieval logic and update TriageGroupIcon component

* chore: changed the intake validation logic

* refactor: update intake state types and clean up unused interfaces

* chore: changed the state color

* chore: changed the update serializer

* chore: updated with current instance

* chore: update TriageGroupIcon color to match new intake state group color

* chore: stringified value

* chore: added validation in serializer

* chore: added logger instead of print

* fix: correct component closing syntax in ActiveProjectItem

* chore: updated the migration file

* chore: added noop in migation

---------

Co-authored-by: b-saikrishnakanth <bsaikrishnakanth97@gmail.com>
2025-11-28 16:16:48 +05:30
b-saikrishnakanthandGitHub dbc5a6348d fix: disable timezone selection button for non-admin users (#8195) 2025-11-28 16:14:43 +05:30
Aaryan KhandelwalandGitHub c685042a47 regression: projects breadcrumb in accordion layout (#8194) 2025-11-28 14:05:38 +05:30
Vipin ChaudharyandGitHub a4de486cf7 [WIKI-811] fix: ensure only non-deleted project pages are retrieved in page queries (#8182)
* fix: ensure soft delete handling for pages in PageViewSet methods

* refactor: streamline query for project IDs in PageDuplicateEndpoint

* refactor: remove soft delete condition from ProjectPage queries in PageViewSet and PageDuplicateEndpoint

* refactor: simplify ProjectPage query in PageViewSet for improved readability

* refactor: replace filter with get for Page queries in PageViewSet and PageDuplicateEndpoint to enhance clarity

* refactor: replace filter with get for Page queries in PagesDescriptionViewSet to improve efficiency
2025-11-27 20:55:50 +05:30
Prateek ShouryaandGitHub 3c84e75350 [WEB-5510] fix: handle null values in context indicator for improved stability (#8190) 2025-11-27 20:53:42 +05:30
Aaryan KhandelwalandGitHub 39749106a2 regression: sidebar toggle button position (#8186)
* fix: sidebar toggle button position

* chore: remove border radius
2025-11-27 20:53:12 +05:30
Aaryan KhandelwalandGitHub 9bcb1fa469 [WEB-5515]: comments ordering (#8193)
* fix: comments ordering

* fix: comment timestamp:
2025-11-27 20:51:06 +05:30
SangeethaandGitHub c31a225775 [WEB-5506] fix: new navigation pre release bugs (#8181)
* chore: update navigation_project_limit and navigation_control_preference

* chore: set default true for user specific widgets

* chore: use serializer in ProjectMemberPreferenceEndpoint
chore: use serializer in WorkspaceUserPropertiesEndpoint
"

* fix: validate preferences

* fix: status code

* fix: remove saving from validate

* fix: simply validate_preferences

* chore: create WorkspaceUserProperties if it doesn't exist

* fix: create WorksapceUserProperties it not exist

* fix: copy the instance

* Revert "fix: copy the instance"

This reverts commit ddb0384b6d.

* chore: migrate WorkspaceUserPreference to set defaults

* fix: migration file name

* Revert "fix: migration file name"

This reverts commit 80a21dedf1.

* Revert "chore: migrate WorkspaceUserPreference to set defaults"

This reverts commit 25bc583a08.
2025-11-27 18:12:20 +05:30
sriramveeraghanta 73c317f283 chore(deps): adding pacakges to resolutions to resolve vulnerbailities 2025-11-27 16:37:36 +05:30
Aaryan KhandelwalandGitHub a0da806a79 [WEB-5520] fix: comments UI in space app #8189 2025-11-27 15:58:10 +05:30
Aaryan KhandelwalandGitHub eddf80aaed [WEB-5511] regression: revamped navigation UI bugs (#8183) 2025-11-26 18:51:03 +05:30
Aaryan KhandelwalandGitHub 05b1c147a9 [WEB-5506] regression: navigation revamp bugs (#8180) 2025-11-26 16:25:29 +05:30
Prateek ShouryaandGitHub ae7898aaee fix: move X-Frame-Options header to auth page for enhanced security (#8179) 2025-11-26 13:57:46 +05:30
Anmol Singh BhatiaandGitHub 4806bdf99c [WEB-5170] feat: navigation revamp (#8162) 2025-11-26 12:56:11 +05:30
Prateek ShouryaandGitHub 37c59ef0d1 [WEB-5507] fix: remove module checks in analytics sidebar link handlers (#8177) 2025-11-26 00:02:14 +05:30
Prateek ShouryaandGitHub 3f11183768 [WEB-5508] fix: improve error handling in AuthFormRoot by ensuring safe access to error_code (#8178) 2025-11-25 23:59:21 +05:30
Aaryan KhandelwalandGitHub d38147b875 fix: build error (#8171) 2025-11-25 19:15:35 +05:30
Prateek ShouryaandGitHub 3436c4f1f5 [WEB-5501] refactor: optimize component structures and improve hooks (#8174)
* [WEB-5501] refactor: optimize component structures and improve hooks

- Updated type definitions in AppProvider to use React.ReactNode for children.
- Enhanced HomePeekOverviewsRoot by using MobX observer and integrating issue detail hook.
- Optimized ContentOverflowWrapper to prevent unnecessary re-renders by adjusting useEffect dependencies.
- Updated DashboardQuickLinks to include necessary dependencies in useCallback.
- Refactored GlobalShortcutsProvider to utilize refs for context and handler management, improving performance.
- Changed useCurrentTime to update every minute instead of every second.
- Refactored outside click hooks to use useCallback for better performance.
- Improved IntercomProvider and PostHogProvider to prevent multiple initializations using refs.

* refactor: simplify conditional rendering in HomePeekOverviewsRoot component

* refactor: improve outside click detection in sidebar and peek overview hooks

* refactor: enhance IntercomProvider and PostHogProvider with hydration state management
2025-11-25 18:52:20 +05:30
sriramveeraghanta 31e8563725 chore(deps): upgrade sentry pacakges 2025-11-25 16:25:07 +05:30
b-saikrishnakanthandGitHub 5ddfd0e1a9 [WEB-5497] fix: update change email button label for localization consistency #8173 2025-11-25 15:47:14 +05:30
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
ef99f8bbca chore(deps): bump @sentry/node (#8169)
Bumps the npm_and_yarn group with 1 update in the / directory: [@sentry/node](https://github.com/getsentry/sentry-javascript).


Updates `@sentry/node` from 10.24.0 to 10.27.0
- [Release notes](https://github.com/getsentry/sentry-javascript/releases)
- [Changelog](https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-javascript/compare/10.24.0...10.27.0)

---
updated-dependencies:
- dependency-name: "@sentry/node"
  dependency-version: 10.27.0
  dependency-type: direct:production
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 13:35:01 +05:30
2804987fe8 [WEB-5358] fix: analytics enhancements (#8150)
* refactor: enhance analytics page tab functionality and UI

- Introduced state management for selected tabs using useState and useEffect hooks.
- Updated tab handling to improve user experience with onValueChange for Tabs component.
- Refactored AnalyticsFilterActions to remove unused duration selection.
- Added Tooltip to project name in ActiveProjectItem for better visibility.
- Minor styling adjustments in Tabs component for improved layout consistency.

* refactor: improve tab layout in analytics page by adding w-fit

* fix: update styling for ActiveProjectItem component

* refactor: simplify analytics page and introduce useAnalyticsTabs hook

- Removed unused imports and optimized the analytics page component.
- Replaced getAnalyticsTabs with a new custom hook useAnalyticsTabs for better modularity.
- Added useAnalyticsTabs hook to manage analytics tab logic.
- Created new files for useAnalyticsTabs and analytics tabs in the 'ce' and 'ee' directories.

* fix: ensure consistent export in use-analytics-tabs file

* style: format code for better readability in AnalyticsPage component

* fix: add missing newline at end of file in use-analytics-tabs

* chore: remove unused analytics tab components

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-11-24 21:29:34 +05:30
09f4e3d4ae [WIKI-774] refactor: space app mentions #8152
Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-11-24 21:26:48 +05:30
7c8cbc4ead [WEB-4428] fix: duplicate labels with case insensitive (#7388)
Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-11-24 21:22:17 +05:30
ce6299937f [WEB-5430] feat: allow users to change email (#8120)
* feat: change user email

* chore: optimised the logic

* feat: add email change functionality and related modals in profile form

* refactor: format checkEmail method for improved readability

* chore: added rate limit exceeded validation

* feat: implement change email modal with localization support

- Added translation support for the change email modal, including titles, descriptions, and error messages.
- Integrated the useTranslation hook for dynamic text rendering.
- Updated form validation messages to utilize localized strings.
- Enhanced user feedback with localized success and error toast messages.
- Updated button labels and placeholders to reflect localization changes.

* chore: added extra validation in cache key

* fix: format files

---------

Co-authored-by: b-saikrishnakanth <bsaikrishnakanth97@gmail.com>
Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-11-24 21:21:52 +05:30
Dheeraj Kumar KetireddyandGitHub d6fce114d6 [SILO-663] chore: enhance error handling in ComplexFilterBackend with DRFValidationError (#8090)
* [SILO-663] chore: enhance error handling in ComplexFilterBackend with DRFValidationError

* Log the exception and re-raise it
2025-11-24 21:14:14 +05:30
Prateek ShouryaandGitHub e6d584fde7 [WEB-5489] fix: prevent AppRail hook usage outside context in disabled workspace components (#8164) 2025-11-24 16:03:36 +05:30
sriram veeraghantaandGitHub 0240e46f04 fix: live server docker build changes (#8166) 2025-11-24 14:08:37 +05:30
e36f4f47f1 [MOB-1199] dev: update index constraints for notifications to optimize query performance (#7870)
* dev: updated the index constraints for notification

* dev: updated migration file with AddIndexConcurrently

* dev: handled indexing for file asset with asset

* bumped migration sequence number

---------

Co-authored-by: Dheeraj Kumar Ketireddy <dheeru0198@gmail.com>
2025-11-23 19:41:27 +05:30
ba4e711f9b [WEB-5350] migration: navigation (#8156)
* migration: navigation related fields in workspace_user_properties

* fix: field names

* fix: remove max_length

* fix: create new migration

* fix: typo

* Renamed horizontal preference to tabbed

---------

Co-authored-by: Dheeraj Kumar Ketireddy <dheeru0198@gmail.com>
2025-11-21 20:51:47 +05:30
AaronandGitHub 0f4309659a [WEB-5478] chore: fix types (#8155) 2025-11-21 20:22:37 +05:30
SangeethaandGitHub 5cfb9538df [WEB-5312] migration: work item comments (#8072)
* migration: description field on issue_comment
sync: issue_comment and description

* fix: update if description already exists for the IssueComment

* feat: management command to copy IssueComment to Description

* fix: description creation order

* chore: add while loop

* fix: move write outside loop

* chore: change sync logic
chore: test cases

* chore: removed deleted_at filter and added order_by in management command

* fix: description_id

* migration: added parent_id for IssueComment

* fix: update update_by_id

* fix: use ChangeTrackerMixin in save

* chore: add docstring
fix: remove self.pk check
chore: wrap the description creation logic in transaction.atomic()

* fix: tests

* fix: use super save method

* fix: mulitple if conditions

* fix: update updated_at
2025-11-21 16:15:07 +05:30
Vipin ChaudharyandGitHub 6a26ce3a2b [WIKI-792] feat: add 'status' attribute to content validator (#8151) 2025-11-21 14:00:29 +05:30
sriramveeraghanta ec9c868f85 chore: file format using prettier 2025-11-21 13:48:01 +05:30
matutinalandGitHub 03c581433a chore: french localization updates (#8031) 2025-11-21 13:47:07 +05:30
2e15e4f786 fix: source map warning during build (#8148)
* [WEB-5473] fix: source map errors

* [WEB-5473] chore: run codemod

* fix: build errors in editor

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-11-21 13:43:52 +05:30
Aaryan KhandelwalandGitHub 9611cd1e73 [WIKI-786] refactor: bubble menu #8138 2025-11-21 12:49:30 +05:30
sriram veeraghantaandGitHub 8307badae5 fix: eslint errors and warnings (#8149) 2025-11-20 19:31:22 +05:30
83fdebf64d [WEB-5459] feat(codemods): add function declaration transformer with tests (#8137)
- Add jscodeshift-based codemod to convert arrow function components to function declarations
- Support React.FC, observer-wrapped, and forwardRef components
- Include comprehensive test suite covering edge cases
- Add npm script to run transformer across codebase
- Target only .tsx files in source directories, excluding node_modules and declaration files

* [WEB-5459] chore: updates after running codemod

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-11-20 17:39:40 +05:30
90866fb925 chore: use oxc tooling to speed up prettier (#8117)
Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-11-20 17:30:27 +05:30
Aaryan KhandelwalandGitHub f3031a44f7 [WEB-5429] refactor: conditional hooks (#8114)
* fix: conditional hooks

* chore: remove unwanted file
2025-11-20 16:22:46 +05:30
Aaryan KhandelwalGitHubNarayanBavisettiBavisetti NarayanVipinDevelopscoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
83679806fd [WIKI-419] chore: new asset duplicate endpoint added (#7172)
* chore: new asset duplicate endpoint added

* chore: change the type in url

* chore: added rate limiting for image duplication endpoint

* chore: added rate limiting per asset id

* chore: added throttle class

* chore: added validations for entity

* chore: added extra validations

* chore: removed the comment

* chore: reverted the frontend code

* chore: added the response key

* feat: handle image duplication for web

* feat: custom image duplication update

* fix: remove paste logic for image

* fix : remove entity validation

* refactor: remove entity id for duplication

* feat: handle duplication in utils

* feat: add asset duplication registry

* chore: update the set attribute method

* fix: add ref for api check

* chore :remove logs

* chore : add entity types types

* refactor: rename duplication success status value

* chore: update attribute to enums

* chore: update variable name

* chore: set uploading state

* chore : update enum name

* chore : update replace command

* chore: fix retry UI

* chore: remove default logic

* refactor: optimize imports in custom image extension files and improve error handling in image duplication

* fix:type error

* Update packages/editor/src/core/extensions/custom-image/components/node-view.tsx

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

* fix: enhance asset duplication handler to ignore HTTP sources

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com>
Co-authored-by: VipinDevelops <vipinchaudhary1809@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-11-20 15:05:01 +05:30
Aaryan KhandelwalandGitHub d462546055 [WIKI-788] fix: editor markdown copy rules (#8140) 2025-11-20 14:46:12 +05:30
Dheeraj Kumar KetireddyandGitHub f510020daa [WEB-5285] feat: add ChangeTrackerMixin to track model field changes and original values #8145 2025-11-20 14:36:55 +05:30
Prateek ShouryaandGitHub 1eaa48c95c [WEB-5458] improvement: restructure layout components to enhance loading (#8141) 2025-11-19 19:11:17 +05:30
sriramveeraghanta d6503232de chore(deps): bump npm vulnerabilities 2025-11-19 14:56:29 +05:30
Jayash TripathyandGitHub 88a41479f4 [WEB-5000] feat: enhance exports settings with rich filters (#8124) 2025-11-19 14:31:48 +05:30
Vipin ChaudharyandGitHub b73cf4f0e2 [WEB-5449] fix: enhance content check for unique ID generation and update issue loader condition (#8132) 2025-11-18 15:27:01 +05:30
Aaryan KhandelwalandGitHub 2e6225a883 [WEB-5436] feat: work item preview (#8121) 2025-11-18 13:54:26 +05:30
Vipin ChaudharyandGitHub f34ca18a34 [WIKI-775] fix: remove fallback image from emojis #8130 2025-11-18 13:53:04 +05:30
Prateek ShouryaandGitHub 69323f4164 [WEB-5442] fix: favorites list on workspace switch (#8131) 2025-11-18 13:52:29 +05:30
Jayash TripathyandGitHub 06300d1a8e [WEB-5447] feat: add dataPreventOutsideClick prop to reafactor: ComboboxOptions for enhanced click handling #8112 2025-11-17 19:47:48 +05:30
Vipin ChaudharyandGitHub 6e32cb51b6 [WIKI-770] fix: update editor ref after editor ready #8115 2025-11-17 16:41:30 +05:30
Vipin ChaudharyandGitHub bd0361de92 [WIKI-480] feat: unique id extension (#8098) 2025-11-17 16:14:20 +05:30
Prateek ShouryaandGitHub ebab5e209f [WEB-5437] fix: remove temporary code for issue display filters to fix work item ordering. (#8125) 2025-11-17 14:28:02 +05:30
Aaryan KhandelwalandGitHub c65e2c4aab [WIKI-773] refactor: editor mention components and hooks (#8111) 2025-11-17 14:07:37 +05:30
Prateek ShouryaandGitHub c04ae51d20 [WEB-5423] revert: update imports for pragmatic-drag-and-drop to use cjs entry points and add TypeScript error handling (#8118) 2025-11-14 19:04:49 +05:30
Prateek ShouryaandGitHub 19a0ef490b [WEB-5423] fix: typescript errors and add types check step to pull request workflow (#8110) 2025-11-14 16:18:36 +05:30
sriram veeraghantaGitHubcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>Copilot
4e357c4ad0 [WEB-5404] chore: update next images with html default images (#8101)
* chore: update next images with html default images

* chore: sync related changes

* Update apps/admin/core/components/instance/failure.tsx

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

* Update apps/space/app/not-found.tsx

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

* Update apps/space/core/components/issues/issue-layouts/error.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update apps/space/core/components/ui/not-found.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* chore: replace classname styles in space

* fix: copoilot suggestions

* fix: copilot suggestions

* chore: format files

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-13 18:33:18 +05:30
Prateek ShouryaandGitHub 80670b2b3f [WEB-5128] refactor: remove local database dependencies and unused code (#8109) 2025-11-13 18:32:15 +05:30
64f90b828b [WEB-5419] chore: add dotenv dependency, hosts and configure environment variables in admin, space, and web apps (#8107)
* chore: add dotenv dependency and configure environment variables in admin, space, and web apps

* chore: allowed multiple hosts in dev mode

* chore: move dotenv to dev deps

* chore: update Vite configuration to set server host to 127.0.0.1 for admin, space, and web apps

---------

Co-authored-by: gakshita <akshitagoyal1516@gmail.com>
2025-11-13 17:57:47 +05:30
AaronandGitHub 95c742244e [WEB-5416] fix: Use proper import syntax (#8105) 2025-11-13 17:41:06 +05:30
sriramveeraghanta 34c0e81d8e chore: update tubro envs and removed plausible script 2025-11-13 15:24:17 +05:30
Vipin ChaudharyandGitHub 2a2c4921a7 [WIKI-768] fix: ordering and grouping of list-related toolbar and slash commands #8104 2025-11-13 15:20:07 +05:30
Vipin ChaudharyandGitHub f4c2d519fc [WIKI-718] feat: add full width options in table block menu (#8087) 2025-11-13 14:46:27 +05:30
Jayash TripathyandGitHub cbfdcd5638 [WEB-5390] refactor: gantt layout support in base layouts (#8089) 2025-11-13 14:33:24 +05:30
Prateek ShouryaandGitHub a04d3b5c29 [WEB-5414] fix: Use correct SWR cache key for fetching project details (#8103) 2025-11-12 23:31:26 +05:30
sriram veeraghantaandGitHub 30da349475 [WEB-5413] feat: adding sentry error handling in web, space and admin (#8099) 2025-11-12 19:03:47 +05:30
Anmol Singh BhatiaandGitHub 0b78e03055 [WEB-5394] fix: propel storybook circular dependencies (#8096)
* fix: resolve circular dependency crashes in storybook stories

* fix: toolbar circular dependency fix and code refactor
2025-11-11 19:29:16 +05:30
Prateek ShouryaandGitHub f8a9a1576d [WEB-5399] chore: update dependencies and improve PostHog integration (#8097)
- Updated PostHog React package to version 1.4.0 and posthog-js to version 1.255.1.
- Refactored PostHogProvider to include hydration state management for improved event tracking.
- Cleaned up version references in pnpm-lock.yaml for react-router and next-themes.
2025-11-11 19:27:49 +05:30
Krzysztof DąbrowskiandGitHub 6ba15545d9 fix: escape slashes in environment variable values during update (#8081) 2025-11-11 17:52:03 +05:30
sriramveeraghanta da22c2f670 chore(deps): bump turbo package and remove unused packages 2025-11-11 15:50:10 +05:30
sriramveeraghanta d47755b4c6 chore: remove unused files 2025-11-11 15:45:53 +05:30
sriramveeraghanta b51da2f997 chore: remove unused middleware files 2025-11-11 15:33:34 +05:30
Aaryan KhandelwalandGitHub 1447be12e6 [WEB-5370] fix: cycle and modules not being removed from the work item edit modal #8094 2025-11-11 14:55:27 +05:30
Prateek ShouryaandGitHub 433b5a4fe1 [WEB-5386] refactor: update all apps to use react-router for development and enable SSR for space app. (#8095) 2025-11-11 14:08:42 +05:30
sriramveeraghanta 4ae0763d0f chore: bump turbo version 2025-11-11 13:32:10 +05:30
Prateek ShouryaandGitHub a407105bb8 [WEB-5389] chore: enable progress bar for production builds and add logo spinner for hydration fallback (#8093)
* [WEB-5389] chore: enable progress bar for production builds

* feat: add LogoSpinner to HydrateFallback in admin, space, and web apps
2025-11-11 12:22:40 +05:30
M. PalanikannanandGitHub 5d7bf554dd [WEB-5381] fix: buffer issue with vite #8091 2025-11-10 20:33:41 +05:30
sriramveeraghanta 5ec09a7fe1 chore: update dockerfile pnpm install with ci=true 2025-11-10 18:28:51 +05:30
sriramveeraghanta 3f0721c59a chore: upgrade vite version using catalog 2025-11-10 13:13:22 +05:30
Prateek ShouryaandGitHub dfc49eea27 [WEB-5379] fix: optimize filter handling in work item components (#8079) 2025-11-07 20:28:10 +05:30
Akshita GoyalandGitHub 1e5f583a24 [WEB-5367] fix: removed integrations and imports from the routes #8073 2025-11-07 16:12:12 +05:30
Aaryan KhandelwalandGitHub d05c222d0a regression: fallback base url for redirection (#8075) 2025-11-07 16:10:52 +05:30
Vamsi KrishnaandGitHub 8853637e98 [WEB-5064] fix: peek overview reloading when parent is added (#7950) 2025-11-06 19:48:35 +05:30
Aaryan KhandelwalandGitHub 12a050e7d3 [WIKI-538] chore: common description component (#7785)
* chore: common description input component

* chore: replace existing description input components

* fix: await for update calls

* refactor: handle fallback values for description states and form data

* fix: import statements

* chore: add workspaceDetails check
2025-11-06 19:47:38 +05:30
Vipin ChaudharyandGitHub fd542a85fa [WIKI-728] fix: update emoji insertion method #7962 2025-11-06 19:46:32 +05:30
Jayash TripathyandGitHub 0a738d419e [WEB-5306] refactor: base layouts (#8051) 2025-11-06 19:45:56 +05:30
Vipin ChaudharyandGitHub c719d67f71 [WIKI-714] fix: close drag handle dropdown when any key is pressed #8040 2025-11-06 18:58:23 +05:30
Vamsi KrishnaandGitHub 7178627f6a [WEB-5339] chore: work item sidebar refactor #8058 2025-11-06 18:57:50 +05:30
Aaryan KhandelwalandGitHub 10590ffa13 [WEB-5360] fix: modules list board layout #8074 2025-11-06 18:57:22 +05:30
Akshita GoyalandGitHub 37aabe7d1d [PAI-923] fix: implemented fetch key functions for auth layouts #8067 2025-11-06 18:50:45 +05:30
Anmol Singh BhatiaandGitHub fd38b9b6d8 [WEB-4320] refactor: migrate emoji reactions to propel (#8039) 2025-11-06 18:25:43 +05:30
M. PalanikannanandGitHub d709465a89 [WIKI-564] fix: editor deps #8069 2025-11-06 17:33:51 +05:30
Anmol Singh BhatiaandGitHub 9b3bd11c03 [WEB-5305] refactor: migrate emoji and logo components to propel and remove duplication (#8038) 2025-11-06 17:33:06 +05:30
Aaryan KhandelwalandGitHub 4927ef8c71 [WEB-5352] fix: layout selection icon #8070 2025-11-06 16:58:38 +05:30
dependabot[bot]andGitHub 0dcea8db70 chore(deps): bump django (#8068) 2025-11-06 16:21:43 +05:30
Prateek ShouryaandGitHub 0941856f67 [WEB-5356] feat: update public environment keys in Vite config for improved configuration management #8071 2025-11-06 15:41:01 +05:30
Prateek ShouryaandGitHub 696fb96e87 [WEB-5043] feat: web vite migration (#7973) 2025-11-06 14:08:48 +05:30
Prateek ShouryaandGitHub 118ecc81ba [WEB-5042] feat: sites vite migration (#7965) 2025-11-06 13:58:24 +05:30
AaronandGitHub 315e1d5eb0 [WEB-5040] feat: admin react-router migration (#7922) 2025-11-06 13:39:35 +05:30
NikhilandGitHub 545bfa203e [WEB-5345] chore: update IssueActivity model to use DO_NOTHING #8065 2025-11-05 20:14:42 +05:30
Vamsi KrishnaandGitHub 78d4356cfa [WEB-5343]chore: updated view access for exports page at workspace level (#8062)
* chore: updated view access for exports page at workspace level

* fix: permissions
2025-11-04 16:25:07 +05:30
NikhilandGitHub 3c6f24de64 [WEB-5237] feat: add workspace invitation and project member management endpoints (#8059) 2025-11-04 14:56:21 +05:30
NikhilandGitHub 96bbbec588 [WEB-5342] fix: update Issue query to use the correct manager in state checks #8060 2025-11-04 14:47:05 +05:30
Dheeraj Kumar KetireddyandGitHub bfea2c8572 [SILO-598] fix: Fixed bugs identified while testing SDK (#8042) 2025-10-31 19:53:22 +05:30
sriram veeraghantaandGitHub 961cdf6c8f fix: storybook build error (#8041) 2025-10-30 19:21:32 +05:30
Surya PrashanthandGitHub e8bdc47d6a [SILO-640] fix: add missing title field in IssueLinkCreateSerializer #8036 2025-10-29 20:38:27 +05:30
Vamsi KrishnaandGitHub 710138f3a1 [WEB-5296]chore: grouping filter refactor (#8034) 2025-10-29 20:36:28 +05:30
Anmol Singh BhatiaandGitHub 0e8128594b [WEB-5191 | WEB-5197] chore: actions and arrows icon revamp (#7984) 2025-10-29 20:13:08 +05:30
350107d6c1 [WEB-5088] feat: Power K v2 (#7905)
* feat: add project shortcut in command palette

* feat: global project switcher shortcut

* refactor: generalize command palette entity handling

* feat: extend command palette navigation

* feat: add issue shortcut to command palette

* feat: add modular project selection for cycle navigation

* chore: add reusable command palette utilities

* fix: update key sequence handling to use window methods for timeout management

* fix: build errors

* chore: minor ux copy improvements

* feat: implement a new command registry and renderer for enhanced command palette functionality

* feat: introduce new command palette components and enhance search functionality

* feat: enhance command palette components with improved initialization and loading indicators

* feat: Implement new command palette architecture with multi-step commands, context-aware filtering, and reusable components. Add comprehensive documentation and integration guides. Enhance command execution with a dedicated executor and context provider. Introduce new command types and improve existing command definitions for better usability and maintainability.

* refactor: hook arguments

* refactor: folder structure

* refactor: update import paths

* fix: context prop drilling

* refactor: update search components

* refactor: create actions

* chore: add type to pages

* chore: init contextual actions

* refactor: context based actions code split

* chore: module context-based actions

* refactor: streamline command execution flow and enhance multi-step handling in command palette

* refactor: remove placeholder management from command execution and implement centralized placeholder mapping

* chore: cycle context based actions

* refactor: simplify command execution by consolidating selection steps and adding page change handling

* chore: added more options to work item contextual actions

* chore: page context actions

* refactor: update step type definitions and enhance page mapping for command execution

* feat: implement Command Palette V2 with global shortcuts and enhanced context handling

* refactor: power k v2

* refactor: creation commands

* feat: add navigation utility for Power K context handling

* feat: implement comprehensive navigation commands for Power K

* refactor: work item contextual actions

* fix: build errors

* refactor: remaining contextual actions

* refactor: remove old code

* chore: update placeholder

* refactor: enhance command registry with observable properties and context-aware shortcut handling

* refactor: improve command filtering logic in CommandPaletteModal

* chore: context indicator

* chore: misc actions

* style: shortcut badge

* feat: add open entity actions and enhance navigation commands for Power K

* refactor: rename and reorganize Power K components for improved clarity and structure

* refactor: update CommandPalette components and streamline global shortcuts handling

* refactor: adjust debounce timing in CommandPaletteModal for improved responsiveness

* feat: implement shortcuts modal and enhance command registry for better shortcut management

* fix: search implemented

* refactor: search results code split

* refactor: search results code split

* feat: introduce creation and navigation command modules for Power K, enhancing command organization and functionality

* chore: update menu logos

* refactor: remove unused PowerKOpenEntityActionsExtended component from command palette

* refactor: search menu

* fix: clear context on backspace and manual clear

* refactor: rename creation command keys for consistency and clarity in Power K

* chore: added intake in global search

* chore: preferences menu

* chore: removed the empty serach params

* revert: command palette changes

* cleanup

* refactor: update command IDs to use underscores for consistency across Power K components

* refactor: extended context based actions

* chore: modal command item status props

* refactor: replace CommandPalette with CommandPaletteProvider in settings and profile layouts

* refactor: update settings menu to use translated labels instead of i18n labels

* refactor: update command titles to use translation keys for creation actions

* refactor: update navigation command titles to use translation keys for consistency

* chore: minor cleanup

* chore: misc commands added

* chore: code split for no search results command

* chore: state menu items for work item context based commands

* chore: add more props to no search results command

* chore: add more props to no search results command

* refactor: remove shortcut key for create workspace command

* Refactor command palette to use PowerK store

- Replaced instances of `useCommandPalette` with `usePowerK` across various components, including `AppSearch`, `CommandModal`, and `CommandPalette`.
- Introduced `PowerKStore` to manage modal states and commands, enhancing the command palette functionality.
- Updated modal handling to toggle `PowerKModal` and `ShortcutsListModal` instead of the previous command palette modals.
- Refactored related components to ensure compatibility with the new store structure and maintain functionality.

* Refactor PowerK command handling to remove context dependency

- Updated `usePowerKCommands` and `usePowerKCreationCommands` to eliminate the need for a context parameter, simplifying their usage.
- Adjusted related command records to utilize the new structure, ensuring consistent access to command configurations.
- Enhanced permission checks in creation commands to utilize user project roles for better access control.

* chore: add context indicator

* chore: update type import

* chore: migrate toast implementation from @plane/ui to @plane/propel/toast across multiple command files

* refactor: power k modal wrapper and provider

* fix: type imports

* chore: update creation command shortcuts

* fix: page context commands

* chore: update navigation and open command shortcuts

* fix: work item standalone page modals

* fix: context indicator visibility

* fix: potential error points

* fix: build errors

* fix: lint errors

* fix: import order

---------

Co-authored-by: Vihar Kurama <vihar.kurama@gmail.com>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2025-10-29 15:38:30 +05:30
Jayash TripathyandGitHub 73e0e8d529 [WEB-4944] feat: add base layouts for kanban and list with drag-and-drop support (#8032) 2025-10-29 14:49:34 +05:30
Anmol Singh BhatiaandGitHub 5247fedd23 [WEB-5271] chore: your work empty state updated #8029 2025-10-29 13:34:04 +05:30
Anmol Singh BhatiaandGitHub 0560849f88 [WEB-5271] fix: empty state translation error and code refactoring (#8027)
* fix: workspace view empty state translation

* chore: search empty state translation fix

* chore: workspace view empty state translation
2025-10-28 20:14:07 +05:30
sriram veeraghantaandGitHub 79537cd1df chore: code splitting instance config variables (#8028)
* chore: code splitting instance config variables

* chore: typo fixes
2025-10-28 19:52:23 +05:30
1126ca30b0 [WEB-5262] feat: gitea sso (#8022)
* Feature/7137/gitea sso (#7940)

* added gitea auth to admin panel with configs , added api calls

* added gitea to oauth root (for signup and signin)

* removed log

* replace github oauth with gitea ouath error messages

* added gitea to auth root

* fix: update token expiration handling and remove unused variable in Gitea callback

* fix: include Gitea in OAuth enabled checks

* fix: improve error handling when fetching emails from Gitea

* chore : remove logs and add semicolons

* refactor: update Gitea authentication components and imports for consistency

* fix: enhance Gitea authentication form to auto-populate host value and improve OAuth checks

* refactor: enhance Gitea OAuth provider with improved error handling and URL validation

* fix: update authentication success messages to check for string value "1"

---------

Co-authored-by: Shivam Jain <shivam.clgstash@gmail.com>
Co-authored-by: Prateek Shourya <prateekshourya29@gmail.com>
2025-10-28 18:53:54 +05:30
SangeethaandGitHub 69fe581fd8 [WEB-5228] chore: IssueLink.DoesNotExist on crawl_work_item_link_title (#8003)
* chore: wrap IssueLink logic in a try-except block

* chore: user logger.warning

* fix: add id and url on the error message
2025-10-28 18:18:36 +05:30
Bavisetti NarayanandGitHub e09d986497 [WEB-5263] chore: removed the tracking of sanitized HTML (#8023)
* chore: removed the html sanitized tracking

* chore: added the greater than sign
2025-10-28 16:57:07 +05:30
SangeethaandGitHub 044003e7ec [WEB-5211] fix: accessing NoneType current_instance for delete_module_issue_activity bgtask (#7993)
* fix: accessing NoneType current_instance

* fix: return module_name

* fix: add none check
2025-10-28 16:56:39 +05:30
SangeethaandGitHub a8b6930486 [WEB-5224] chore: raise warning instead of logging an exception for webhook_send_task (#7996) 2025-10-28 16:49:19 +05:30
Anmol Singh BhatiaandGitHub 685e3fa2f8 [WEB-5236] chore: attachment icon revamp (#8009)
* chore: iconwrapper component added

* chore: attachments icon added to propel

* chore: code refactor

* chore: code refactor
2025-10-28 16:47:43 +05:30
Anmol Singh BhatiaandGitHub ec6e682044 [WEB-5255] fix: calendar layout weekly view (#8018)
* fix: calendar layout weekly view

* chore: code refactor
2025-10-28 16:47:10 +05:30
Anmol Singh BhatiaandGitHub b7aa25f2c6 [WEB-5248] chore: translations and empty state refactor (#8021)
* chore: translations code refactoring

* chore: empty state translation refactor

* chore: code refactor
2025-10-28 13:31:06 +05:30
Anmol Singh BhatiaandGitHub cf7f891bcb [WEB-5248] chore: empty state code refactor and translation fix (#8017)
* chore: empty state code refactor and translation fix

* chore: code refactor
2025-10-27 19:55:46 +05:30
Anmol Singh BhatiaandGitHub 3faf768112 [WEB-3567] chore: empty state refactoring and translation fix (#8014)
* chore: empty state component improvement and code refactor

* chore: translation code refactor

* chore: empty state code refactor
2025-10-27 17:03:35 +05:30
Vamsi KrishnaandGitHub be0d1871f0 [WEB-5241] fix: project features toggle #8015 2025-10-27 17:02:22 +05:30
Surya PrashanthandGitHub c07f7b7c1e [WEB-5245] fix: add is_time_tracking_enabled field in project serializer (#8016) 2025-10-27 16:54:03 +05:30
Surya PrashanthandGitHub 1d4cde9ba0 [WEB-5245] feat: auto-populate logo_props in project creation #8013 2025-10-27 16:19:52 +05:30
NikhilandGitHub c4dd4bd02f [WEB-5155]refactor: simplify user filtering logic in SearchEndpoint #8012 2025-10-27 16:17:19 +05:30
Anmol Singh BhatiaandGitHub d71dfe8f86 [WEB-5188 | WEB-5190] chore: layout and properties icon revamp (#7980) 2025-10-24 19:53:36 +05:30
Anmol Singh BhatiaandGitHub 33b6405695 [WEB-5160] chore: propel banner and archived work item improvements (#7999) 2025-10-24 19:48:28 +05:30
Anmol Singh BhatiaandGitHub 68fd2463f4 [WEB-5230 | WEB-5231] chore: new empty state implementation (#7972) 2025-10-24 17:21:14 +05:30
Vihar KuramaandGitHub a60d74a3c0 [WEB-5235] Fix activity timeline ordering for edited comments #8002 2025-10-24 16:17:51 +05:30
Anmol Singh BhatiaandGitHub 76ffe52cd5 [WEB-5220] fix: intake actions btn ui #7995 2025-10-24 16:05:46 +05:30
b65b1b4828 fix: use issue store was not loading up properly (#8006)
* use issue store was not loading up properly , and hence created data issues for rendering filters options

* Added React.FC for better type suggestions

* chore: observer implementation change

---------

Co-authored-by: shivam-jainn <shivam.clgstash@gmail.com>
2025-10-23 21:45:25 +05:30
sriram veeraghantaandGitHub e5063cd280 fix: get work item activity external endpoint (#8005)
* fix: activity get endpoint fixes

* chore: missing pk added
2025-10-23 21:37:30 +05:30
sriramveeraghanta 9448f642f0 sync: master branch with preview 2025-10-23 20:29:18 +05:30
Akshat Jainandsriramveeraghanta 443f8b793d [INFRA-252] fix: Add missing Redis environment variables in live service Docker Compose 2025-10-23 20:28:39 +05:30
Akshat JainandGitHub 96fa9ab15b [INFRA-252] fix: Add missing Redis environment variables in live service Docker Compose 2025-10-23 19:26:27 +05:30
sriram veeraghantaandGitHub d5bad5aedc release: v1.1.0 #7991 2025-10-23 18:24:42 +05:30
e710f5b278 [WEB-5196] chore: switch from isomorphic-dompurify to dompurify (#7983)
* [WEB-5196] chore: switch from isomorphic-dompurify to dompurify

Replace isomorphic-dompurify with dompurify package in utils.
This change simplifies the dependency and uses the canonical
DOMPurify package directly.

* fix: removing dompurify from the space app as dependency

* chore: remove unused import

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-10-23 16:33:32 +05:30
sriramveeraghanta 80bd1b6dcd Merge branch 'canary' of github.com:makeplane/plane into preview 2025-10-23 15:43:16 +05:30
b34c9ca04f fix: live server secret key app version env variables (#7997)
* fix: live server secret key app version env variables

* fix: revert to stable version

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-23 15:42:43 +05:30
sriramveeraghanta ad16ea1440 Merge branch 'canary' of github.com:makeplane/plane into preview 2025-10-23 14:54:09 +05:30
sriramveeraghanta addf3c4104 chore: added live server secret key in community docker file 2025-10-23 14:53:41 +05:30
Anmol Singh BhatiaandGitHub 38cdf756a5 [WEB-5158] chore: calendar start of week alignment fix and code refactoring #7978 2025-10-23 13:59:29 +05:30
Bavisetti NarayanandGitHub f94da68597 [WEB-5153] chore: optimised the cycle transfer issues (#7969)
* chore: optimised the cycle transfer issues

* chore: added more vlaidation in transfer

* chore: improve the comments
2025-10-23 00:29:32 +05:30
Bavisetti NarayanandGitHub 68aa2fe0b8 [WIKI-553] chore: improved pages components tracking (#7966)
* chore: page components tracking

* chore: changed the transaction task

* chore: added logger for description html
2025-10-23 00:29:05 +05:30
Vamsi KrishnaandGitHub 5fa9943b66 [WEB-5141] chore: project features refactor (#7960)
* chore: project features refactor

* fix: enable/disable condition for toggle

* fix: dependencies

* chore: lint fix

* chore: lint fix

* chore: added fallback exports
2025-10-23 00:27:16 +05:30
Anmol Singh BhatiaandGitHub 772b5c5719 [WEB-5201] chore: work item and inbox modal refactor (#7990)
* chore: work item and inbbox modal refactor

* chore: code refactor

* chore: code refactor

* chore: code refactor
2025-10-22 21:11:08 +05:30
NikhilandGitHub d6657d5168 [WEB-5207] fix: update date formatting in IssueExportSchema for cycle start and end dates #7992 2025-10-22 17:11:43 +05:30
sriramveeraghanta 1b43efbc2a chore: version bump 2025-10-21 19:14:43 +05:30
64781be7d2 regression: downgrade to tiptap v2 (#7982)
* chore: downgrade to tiptap v2

* fix: revert back to hocuspocus

* fix: collaboration events added

* fix: lock unlock issues

* fix: build errors

* fix: type errors

* fix: graceful shutdown

---------

Co-authored-by: Palanikannan M <akashmalinimurugu@gmail.com>
2025-10-21 18:28:16 +05:30
sriramveeraghanta 59022b6beb fix: vite package upgrade 2025-10-21 14:41:34 +05:30
NikhilandGitHub f266cd8414 [WEB-5162] fix: add exporter URL patterns for exporting issues (#7977)
* feat: add exporter URL patterns for exporting issues and update session cookie age handling

* fix: ensure ADMIN_SESSION_COOKIE_AGE is an integer for consistent session handling
2025-10-16 15:36:48 +05:30
sriramveeraghanta 98b81d7ebb chore(deps): happy dom version bump 2025-10-16 14:55:57 +05:30
AaronandGitHub 00807d2d62 [WEB-5157] chore: fix propel icon clip paths #7975 2025-10-16 14:03:26 +05:30
Vamsi KrishnaandGitHub 9d757ccc6a [WEB-5156] fix: activity filters bug #7971 2025-10-15 19:57:52 +05:30
Anmol Singh BhatiaandGitHub a8c253acfe [WEB-5154] chore: nav button text colour updated #7970 2025-10-15 19:27:10 +05:30
Vamsi KrishnaandGitHub 2b106cbd66 [WEB-5054]feat: added activity filters for state and assignee activities (#7918)
* feat: added activity filters for state and assignee

* chore: removed unused funtion

* chore: lint fix
2025-10-15 17:12:03 +05:30
sriramveeraghanta f9cca8e2cb fix: live server log 2025-10-15 16:18:42 +05:30
ee176efae3 [WEB-5095]chore: updated delete modal info content (#7967)
* chore: updated delete modal info content

* chore: added language support for modal content

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-10-15 16:05:55 +05:30
Akshita GoyalandGitHub 44a483f895 [WEB-5142] fix: Issue modal styling #7961 2025-10-15 15:19:40 +05:30
sriramveeraghanta 196baf099a chore: lint errors 2025-10-15 15:15:48 +05:30
NikhilandGitHub 1a9ebc8b68 [WEB-5071] chore: implement webhook logging to MongoDB and fallback to database (#7896)
* feat: implement webhook logging to MongoDB and fallback to database (#7887)

- Added a new function `save_webhook_log` to log webhook requests and responses to MongoDB, with a fallback to the database if the MongoDB save fails.
- Updated the `webhook_send_task` to utilize the new logging function.
- Modified the `get_webhook_logs_queryset` to order logs by creation date and adjusted the chunk size for iteration.

* refactor: clean up log data formatting in save_webhook_log function

* fix: update retry_count type in save_webhook_log function
2025-10-15 14:53:43 +05:30
Vamsi KrishnaandGitHub 97e662215a [WEB-5125] fix: suspended user view #7964 2025-10-14 17:35:39 +05:30
Bavisetti NarayanandGitHub 606e34ec81 [WIKI-730] chore: handle body too large error (#7963)
* chore: added middleware to handle body too large

* chore: added middleware to handle body too large

* chore: indentend the code

* chore: changed the response structure

* chore: changed the response structure

* chore: created a new file for middleware

* chore: added a standardized error key
2025-10-14 17:21:11 +05:30
Anmol Singh BhatiaandGitHub a3019ebd46 [WEB-5092] feat: app sidebar enhancements (#7946)
* chore: project sidebar and settings sidebar improvement

* chore: navigationitem ui improvement

* chore: workspace level new icon added

* chore: propel icon migration

* chore: code refactor

* chore: dashboard icon updated

* chore: code refactor

* chore: icons updated

* chore: code refactor

* chore: code refactor

* chore: scroll area component refactor

* chore: sidebar enhancements

* chore: add and archive icon updated

* chore: code refactor

* chore: code refactor

* chore: code refactor
2025-10-14 17:20:20 +05:30
Prateek ShouryaandGitHub 9cfde896b3 [WEB-5134] refactor: update web ESLint configuration and refactor imports to use type imports (#7957)
* [WEB-5134] refactor: update `web` ESLint configuration and refactor imports to use type imports

- Enhanced ESLint configuration by adding new rules for import consistency and type imports.
- Refactored multiple files to replace regular imports with type imports for better clarity and performance.
- Ensured consistent use of type imports across the application to align with TypeScript best practices.

* refactor: standardize type imports across components

- Updated multiple files to replace regular imports with type imports for improved clarity and consistency.
- Ensured adherence to TypeScript best practices in the rich filters and issue layouts components.
2025-10-14 16:45:07 +05:30
Dheeraj Kumar KetireddyandGitHub 4168127803 [WEB-4999] feat: implement flexible data export utility with CSV, JSON, and XLSX support (#7884)
* feat: implement flexible data export utility with CSV, JSON, and XLSX support

- Introduced Exporter class for handling various data formats.
- Added formatters for CSV, JSON, and XLSX exports.
- Created schemas for defining export fields and their transformations.
- Implemented IssueExportSchema for exporting issue data with nested attributes.
- Enhanced issue export task to utilize the new exporter system for better data handling.

* feat: enhance issue export functionality with new relations and context handling

- Updated issue export task to utilize new IssueRelation model for better relationship management.
- Refactored Exporter class to accept QuerySets directly, improving performance and flexibility.
- Enhanced IssueExportSchema to include parent issues and relations in the export.
- Improved documentation for exporting multiple projects and filtering fields during export.

* feat: enhance export functionality with field filtering and context support

- Updated Exporter class to merge fields into options for formatting.
- Modified formatters to filter fields based on specified options.
- Enhanced ExportSchema to support optional field selection during serialization.
- Improved documentation for the serialize method to clarify field filtering capabilities.

* fixed type
2025-10-14 15:46:55 +05:30
Anmol Singh BhatiaandGitHub 9dc14d8d67 [WEB-5139] fix: custom menu item link (#7959)
* fix: custom menu link action

* chore: code refactor

* chore: code refactor
2025-10-14 15:45:49 +05:30
Anmol Singh BhatiaandGitHub 56007e7d47 [WEB-5129] chore: icons revamp (#7958)
* chore: code refactor

* chore: code refactor
2025-10-14 12:47:53 +05:30
Prateek ShouryaandGitHub cfb4a8212c [WEB-5099] improvement: enhance rich filters with new components and configurations (#7916)
* feat: enhance rich filters with new components and configurations

- Added `AdditionalFilterValueInput` for unsupported filter types.
- Introduced `FilterItem` and related components for better filter item management.
- Updated filter configurations to include new properties and support for multiple values.
- Improved loading states and error handling in filter components.
- Refactored existing filter logic to streamline operations and enhance performance.

* Refactor rich filters component structure and enhance filter item functionality

- Moved AddFilterButton and AddFilterDropdown to a new directory structure for better organization.
- Updated FilterItemProperty to handle filter selection and condition updates more effectively.
- Enhanced the FilterInstance class with methods to update condition properties and operators, improving filter management.
- Added new functionality to handle invalid filter states and improve user feedback.

* [WEB-5111] feat: add 'created_at' and 'updated_at' filters to work item configuration

- Introduced new filter configurations for 'created_at' and 'updated_at' in the work item filters.
- Updated relevant components to utilize these new filters, enhancing filtering capabilities.
- Added corresponding filter configuration functions in the utils for better date handling.

* fix: build
2025-10-14 01:39:24 +05:30
9f41e92d21 [WEB-5135] refactor: update sites ESLint configuration and refactor imports to use type imports (#7956)
- Enhanced ESLint configuration by adding new rules for import consistency and type imports.
- Refactored multiple files to replace regular imports with type imports for better clarity and performance.
- Ensured consistent use of type imports across the application to align with TypeScript best practices.

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
2025-10-14 00:40:30 +05:30
Vamsi KrishnaandGitHub ddf07dc993 [WEB-5029] chore: updates icons for title and description #7862 2025-10-14 00:09:50 +05:30
eee9744159 [WEB-5119] chore: remove any deprecated toast instances from the plane/ui page (#7943)
* [WEB-5119] chore: remove deprecated toast implementation from @plane/ui

* fix: build

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-10-14 00:08:00 +05:30
Prateek ShouryaandGitHub c80c76b882 [WEB-5136] refactor: update admin ESLint configuration and refactor imports to use type imports (#7955)
- Enhanced ESLint configuration by adding new rules for import consistency and type imports.
- Refactored multiple files to replace regular imports with type imports for better clarity and performance.
- Ensured consistent use of type imports across the application to align with TypeScript best practices.
2025-10-13 21:07:49 +05:30
Vamsi KrishnaandGitHub ffe38b592a [WEB-5080] fix: attachment and link count in spreadsheet columns #7942 2025-10-13 21:03:54 +05:30
Anmol Singh BhatiaandGitHub 87eb1949c6 [WEB-5129] feat: icons revamp (#7945) 2025-10-13 19:43:24 +05:30
Anmol Singh BhatiaandGitHub c736354739 [WEB-5130] chore: propel scroll area improvement #7952 2025-10-13 19:30:58 +05:30
sriramveeraghanta 3eecec552a chore(deps): lock file resolutions 2025-10-13 13:43:05 +05:30
sriramveeraghanta c561164d65 chore(deps): happy dom resolution added 2025-10-13 13:32:13 +05:30
c3dd790f7e [WEB-5058] feat: enhance workspace seeding with cycles, modules, and views creation (#7951)
* feat: enhance workspace seeding with cycles, modules, and views creation

- Added `create_cycles`, `create_modules`, and `create_views` functions to the workspace seeding process, enabling the creation of cycles, modules, and views based on new seed data.
- Updated `create_project_issues` to associate issues with cycles and modules.
- Introduced new seed files: `cycles.json`, `modules.json`, and `views.json` to provide initial data for cycles, modules, and views.
- Integrated these new functionalities into the `workspace_seed` task for comprehensive workspace initialization.

* feat: add project_id to page seed data for improved association

- Added `project_id` field to the page with `id` 2 in `pages.json` to establish a clear link between pages and their respective projects.
- This enhancement supports better organization and retrieval of page data within the project context.

* feat: enhance workspace seed task with improved display properties and layout options

- Updated the `create_project_and_member` function to include new display properties and layout configurations for better project visualization.
- Modified display filters to group by state and added calendar layout options.
- Enhanced the `create_modules` and `create_views` functions with improved formatting and structure for better readability and maintainability.

* Update apps/api/plane/bgtasks/workspace_seed_task.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: correct project_id mapping in cycle and view creation functions

- Updated the `create_cycles` function to use the correct `project_id` from the `project_map` for fetching the last cycle.
- Removed redundant `view_id` extraction in the `create_views` function to streamline view creation process.

* refactor: update create_cycles function to return project mapping

- Changed the return type of the `create_cycles` function from `None` to `Dict[int, uuid.UUID]` to provide a mapping of project IDs after cycle creation.
- This modification enhances the function's utility by allowing the caller to access the generated project mappings directly.

* refactor: remove unused view_map variable in create_views function

- Eliminated the `view_map` dictionary from the `create_views` function as it was not utilized, streamlining the code.
- This change enhances code clarity and maintainability by removing unnecessary elements.

* refactor: improve issue creation logic in create_project_issues function

- Added comments to clarify the creation of issue labels, cycle issues, and module issues within the `create_project_issues` function.
- Enhanced code readability and maintainability by structuring the issue creation process with clear conditional checks for cycles and modules.

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-11 20:55:48 +05:30
Akshita GoyalandGitHub 70be4a4ace [WEB-5127] chore: added readonly properties + fixed state dropdown + added additional props to issue modal (#7949)
* chore: added readonly properties + fixed state dropdown + added addditional props to issue modal

* fix: refactor

* fix: refactors

* fix: build
2025-10-11 16:18:32 +05:30
Anmol Singh BhatiaandGitHub 2c17f8ad72 [WEB-5103] fix: custom menu event propagation (#7932)
* fix: custommenu event propagation

* chore: code refactor
2025-10-11 15:02:34 +05:30
NikhilandGitHub 151674687c [WEB-5059] feat: add page creation functionality to workspace seeding process (#7948)
* feat: add page creation functionality to workspace seeding process

- Implemented `create_pages` function to create pages for each project in the workspace based on data from `pages.json`.
- Integrated page creation into the `workspace_seed` task, ensuring pages are created alongside project issues.
- Added a new `pages.json` seed file containing initial page data and descriptions.

* fix: update page creation logic and seed data

- Set `is_global` to `False` for pages created in the `create_pages` function.
- Adjusted the project type check to be case-insensitive in the page creation logic.
- Added `id`, `project_id`, and `description_stripped` fields to the `pages.json` seed data for improved page initialization.
2025-10-10 18:32:15 +05:30
sriram veeraghantaandGitHub 8cd29c5009 fix: adding comprehensive logs for live server (#7947)
* fix: adding comprehensive logs

* fix: document controller naming convention

* fix: axios interception logger
2025-10-10 18:28:52 +05:30
Jayash TripathyandGitHub 9ce6179421 [WEB-5120] refactor: add onSearchQueryKeyDown prop to ComboboxOptions for keyboard event handling #7941 2025-10-10 16:46:47 +05:30
sriram veeraghanta 71ec9fadb7 chore: package versions 2025-10-10 01:52:23 +05:30
sriram veeraghanta c88ed332e5 chore: package version upgrade 2025-10-10 01:36:32 +05:30
Aaryan KhandelwalandGitHub d8c1dff34f [WIKI-725] regression: editor floaters propagation #7938 2025-10-10 01:35:14 +05:30
Akshat JainandGitHub 5d161f671d [INFRA-246] Update Valkey image version to 7.2.11-alpine in docker-compose files #7935 2025-10-10 00:19:17 +05:30
sriram veeraghantaandGitHub ae215a542e [WIKI-724 ] feat: sentry setup for live express server #7934 2025-10-09 21:00:43 +05:30
Anmol Singh BhatiaandGitHub b7c14ac9f5 [WEB-5104] chore: combobox improvements (#7933)
* chore: base ui package upgrade

* feat: migrate combobox to use base-ui primitives

* chore: code refactor

* chore: code refactor
2025-10-09 19:13:17 +05:30
75cd2017a0 [WEB-5104] chore: base-ui package upgrade and combobox migration (#7931)
* chore: base ui package upgrade

* feat: migrate combobox to use base-ui primitives

* chore: code refactor

* fix: format fixes

---------

Co-authored-by: sriramveeraghanta <veeraghanta.sriram@gmail.com>
2025-10-09 18:47:09 +05:30
Rohan BirtiaandGitHub 1895cfe728 Update docker-compose.yml for valkey security patch (#7926)
Critical security patch for Redis.
https://github.com/valkey-io/valkey/security/advisories/GHSA-9rfg-jx7v-52p6
2025-10-09 17:15:49 +05:30
M. PalanikannanandGitHub 98e0089723 [WIKI-722] fix: hocuspocus provider update to v3 (#7930)
* fix: hocuspocus provider

* fix: hocuspocus updated url instead of queryparams
2025-10-09 15:38:15 +05:30
sriramveeraghanta 561ae82d9d chore: update gitignore and dockerignore 2025-10-09 15:35:11 +05:30
Vamsi KrishnaandGitHub afac9f72db [WEB-5101]fix: toast action items hover behaviour (#7929)
* fix: toast action items hover behaviour

* fix: refactored toast styles
2025-10-09 15:10:56 +05:30
M. PalanikannanandGitHub 0f038705ed fix: hocuspocus version upgrade (#7928) 2025-10-09 14:32:43 +05:30
Prateek ShouryaandGitHub 0b257c8693 [WEB-5093] improvement: adds content-based MIME type detection for uploads #7925
- Refactored file upload utilities to use async functions for better handling of file metadata.
- Introduced MIME type detection using the file-type library.
- Updated file service methods to await metadata retrieval.
- Added new dependencies for file-type and updated package.json accordingly.
- Removed deprecated file handling code from utils and adjusted imports across services.
2025-10-09 12:22:43 +05:30
Aaryan KhandelwalandGitHub f2539c5051 fix: editor dropdowns positioning (#7927)
* fix: editor dropdowns positioning

* fix: add cleanup to prevent memory leak

* chore: add editor fallback
2025-10-09 00:25:21 +05:30
sriram veeraghantaandGitHub 5d60d6d702 chore: adding types node package to pnpm catalog (#7923) 2025-10-08 18:42:53 +05:30
sriram veeraghantaandGitHub 63096ceb8c release: v1.0.0 #7711 2025-09-10 14:53:52 +05:30
sriram veeraghantaandGitHub 9b58b9259e fix: adding proxy command in compose file #7519 2025-07-30 21:03:03 +05:30
sriram veeraghantaandGitHub 1e235600b7 release: v0.28.0 #7488 2025-07-30 16:51:00 +05:30
sriram veeraghantaandGitHub 04b0d7ee9f release: v0.27.1 #7328 2025-07-04 13:31:00 +05:30
sriram veeraghantaandGitHub 5a3f709e72 release: v0.27.0 #7296 2025-07-01 17:40:56 +05:30
sriram veeraghantaandGitHub 5ef33ab798 release: v0.26.1 #7181 2025-06-06 17:55:03 +05:30
sriram veeraghantaandGitHub 27806fbe20 release: v0.26.1 #7179 2025-06-06 17:27:49 +05:30
3520 changed files with 65730 additions and 40917 deletions
+6
View File
@@ -61,3 +61,9 @@ temp/
# Misc
*.pem
*.key
# React Router - https://github.com/remix-run/react-router-templates/blob/dc79b1a065f59f3bfd840d4ef75cc27689b611e6/default/.dockerignore
.react-router/
build/
node_modules/
README.md
+48
View File
@@ -0,0 +1,48 @@
---
description: Guidelines for bash commands and tooling in the monorepo
applyTo: "**/*.sh"
---
# Bash & Tooling Instructions
This document outlines the standard tools and commands used in this monorepo.
## Package Manager
We use **pnpm** for package management.
- **Do not use `npm` or `yarn`.**
- Lockfile: `pnpm-lock.yaml`
- Workspace configuration: `pnpm-workspace.yaml`
### Common Commands
- Install dependencies: `pnpm install`
- Run a script in a specific package: `pnpm --filter <package_name> run <script>`
- Run a script in all packages: `pnpm -r run <script>`
## Monorepo Tooling
We use **Turbo** for build system orchestration.
- Configuration: `turbo.json`
## Project Structure
- `apps/`: Contains application services (admin, api, live, proxy, space, web).
- `packages/`: Contains shared packages and libraries.
- `deployments/`: Deployment configurations.
## Running Tests
- To run tests in a specific package (e.g., codemods):
```bash
cd packages/codemods
pnpm run test
```
- Or from root:
```bash
pnpm --filter @plane/codemods run test
```
## Docker
- Local development uses `docker-compose-local.yml`.
- Production/Staging uses `docker-compose.yml`.
@@ -0,0 +1,129 @@
---
description: Guidelines for using modern TypeScript features (v5.0-v5.8)
applyTo: "**/*.{ts,tsx,mts,cts}"
---
# TypeScript Coding Guidelines & Modern Features (v5.0 - v5.8)
When writing TypeScript code, prioritize using modern features and best practices introduced in recent versions (up to 5.8).
## Global Themes Across 5.x
1. **Standard decorators are here; legacy decorators are legacy.**
New TC39-compliant decorators landed in 5.0 and were extended in 5.2 (metadata). Old `experimentalDecorators`-style behavior is still supported but should be treated as legacy.
2. **Type system is more precise and less noisy.**
Major work went into narrowing, control flow analysis, error messages, and new helpers like `NoInfer`, inferred predicates, and better `undefined`/`never`/uninitialized checks.
3. **Module / runtime interop has been modernized.**
Options like `--moduleResolution bundler`, `--module nodenext`/`node18`, `--rewriteRelativeImportExtensions`, `--erasableSyntaxOnly`, and `--verbatimModuleSyntax` are about playing nicely with ESM, Node 18+/22+, direct TypeScript execution, and bundlers.
4. **The standard library keeps tracking modern JS.**
Support for new ES features (iterator helpers, `Object.groupBy`/`Map.groupBy`, new Set/ES2024 APIs) shows up as type declarations and sometimes extra checks (regex syntax checking, etc.).
When generating or refactoring code, prefer these newer idioms, and avoid patterns that conflict with updated checks.
## Modern Features to Utilize
### Type System & Inference
- **`const` Type Parameters (5.0)**: Use `const` type parameters for more precise literal inference.
```typescript
declare function names<const T extends string[]>(...names: T): void;
```
- **`@satisfies` Operator (5.0)**: Use `satisfies` to validate types without widening them.
- **Inferred Type Predicates (5.5)**: Allow TypeScript to infer type predicates for functions that filter arrays or check types, reducing the need for explicit `is` return types.
- **`NoInfer` Utility (5.4)**: Use `NoInfer<T>` to block inference for specific type arguments when you want them to be determined by other arguments.
- **Narrowing**:
- **Switch(true) (5.3)**: Utilize narrowing in `switch(true)` blocks.
- **Boolean Comparisons (5.3)**: Rely on narrowing from direct boolean comparisons.
- **Closures (5.4)**: Trust preserved narrowing in closures when variables aren't modified after the check.
- **Constant Indexed Access (5.5)**: Use constant indices to narrow object/array properties.
### Syntax & Control Flow
- **Decorators (5.0)**: Use standard ECMAScript decorators (Stage 3).
- **`using` Declarations (5.2)**: Use `using` for explicit resource management (Disposable pattern) instead of manual cleanup.
```typescript
using resource = new Resource();
```
- **Import Attributes (5.3/5.8)**: Use `with { type: "json" }` for import attributes. Avoid the deprecated `assert` syntax.
- **`switch` Exhaustiveness**: Rely on TypeScript's exhaustiveness checking in switch statements.
### Modules & Imports
- **`verbatimModuleSyntax` (5.0)**: Respect this flag by using `import type` explicitly when importing types to ensure they are erased during compilation.
- **Type-Only Imports with Extensions (5.2)**: You can use `.ts`, `.mts`, `.cts` extensions in `import type` statements.
- **`resolution-mode` (5.3)**: Use `import type { Type } from "mod" with { "resolution-mode": "import" }` if needed for specific module resolution contexts.
- **JSDoc `@import` (5.5)**: Use `@import` tags in JSDoc for cleaner type imports in JS files if working in a mixed codebase.
### Standard Library & Built-ins
- **Iterator Helpers (5.6)**: Use new iterator methods (map, filter, etc.) if targeting modern environments.
- **Set Methods (5.5)**: Utilize new `Set` methods like `union`, `intersection`, etc., when available.
- **`Object.groupBy` / `Map.groupBy` (5.4)**: Use these standard methods for grouping instead of external libraries like Lodash when appropriate.
- **`Promise.withResolvers` (5.7)**: Use `Promise.withResolvers()` for creating promises with exposed resolve/reject functions.
### Configuration & Tooling
- **`--moduleResolution bundler` (5.0)**: Assume this resolution strategy for modern web projects (Vite, Next.js, etc.).
- **`--erasableSyntaxOnly` (5.8)**: Be aware of this flag; avoid TypeScript-specific syntax that cannot be simply erased (like `enum`s or `namespaces`) if the project aims for maximum compatibility with tools like Node.js's `--strip-types`. Prefer `const` objects or unions over `enum`s if requested.
## Specific Coding Patterns
### Arrays & Collections
- Use **Copying Array Methods (5.2)** (`toSorted`, `toSpliced`, `with`) for immutable array operations.
- **TypedArrays (5.7)**: Be aware that TypedArrays are now generic over `ArrayBufferLike`.
### Classes
- **Parameter Decorators (5.0/5.2)**: Use modern standard decorators.
- **`super` Property Access (5.3)**: Avoid accessing instance fields via `super`.
### Error Handling
- **Checks for Never-Initialized Variables (5.7)**: Ensure variables are initialized before use to avoid new errors.
## Deprecations to Avoid
- Avoid `import ... assert` (use `with`).
- Avoid implicit `any` returns in `undefined`-returning functions (though 5.1 makes this easier, explicit is better).
- Avoid `enum`s if the project prefers erasable syntax (5.8).
## Version-Specific Highlights
### TypeScript 5.0
- **Decorators**: Use standard decorators unless `experimentalDecorators` is explicitly enabled.
- **`const` Type Parameters**: Use for literal inference.
- **Enums**: All enums are union enums.
- **Modules**: `--moduleResolution bundler` and `--verbatimModuleSyntax` are key for modern bundlers.
### TypeScript 5.1
- **Returns**: `undefined`-returning functions don't need explicit returns.
- **Getters/Setters**: Can have unrelated types with explicit annotations.
### TypeScript 5.2
- **Resource Management**: `using` declarations for `Symbol.dispose`.
- **Decorator Metadata**: Use `context.metadata` for design-time metadata.
### TypeScript 5.3
- **Import Attributes**: Use `with { type: "json" }`.
- **Switch(true)**: Narrowing works in `switch(true)`.
### TypeScript 5.4
- **Closures**: Narrowing preserved in closures if last assignment is before creation.
- **`NoInfer`**: Block inference for specific arguments.
- **Grouping**: `Object.groupBy` / `Map.groupBy`.
### TypeScript 5.5
- **Inferred Predicates**: Functions checking types often don't need explicit `is` return types.
- **Constant Index Access**: Better narrowing for constant keys.
- **Regex**: Syntax checking for regex literals.
### TypeScript 5.6
- **Truthiness Checks**: Errors on always-truthy/falsy conditions (e.g., `if (/regex/)`).
- **Iterator Helpers**: `.map`, `.filter` on iterators.
### TypeScript 5.7
- **Uninitialized Variables**: Stricter checks for never-initialized variables.
- **Relative Imports**: `--rewriteRelativeImportExtensions` for `.ts` imports in output.
- **ES2024**: Support for `Promise.withResolvers`, `Atomics.waitAsync`.
### TypeScript 5.8
- **Return Checks**: Granular checks for conditional returns.
- **Node Modules**: `--module node18` stable; `require()` of ESM allowed in `nodenext`.
- **Erasable Syntax**: `--erasableSyntaxOnly` forbids enums, namespaces, etc.
When generating code, always prefer the most modern, standard, and type-safe approach available in TypeScript 5.8.
@@ -49,5 +49,8 @@ jobs:
- name: Check Affected format
run: pnpm turbo run check:format --affected
- name: Check Affected types
run: pnpm turbo run check:types --affected
- name: Build Affected
run: pnpm turbo run build --affected
+11 -1
View File
@@ -16,9 +16,10 @@ node_modules
/out/
# Production
/build
dist/
out/
build/
.react-router/
# Misc
.DS_Store
@@ -101,3 +102,12 @@ dev-editor
storybook-static
CLAUDE.md
build/
.react-router/
AGENTS.md
build/
.react-router/
AGENTS.md
temp/
+6
View File
@@ -0,0 +1,6 @@
{
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "es5",
"plugins": ["@prettier/plugin-oxc"]
}
+5
View File
@@ -0,0 +1,5 @@
# React Router - https://github.com/remix-run/react-router-templates/blob/dc79b1a065f59f3bfd840d4ef75cc27689b611e6/default/.dockerignore
.react-router/
build/
node_modules/
README.md
+8 -8
View File
@@ -1,12 +1,12 @@
NEXT_PUBLIC_API_BASE_URL="http://localhost:8000"
VITE_API_BASE_URL="http://localhost:8000"
NEXT_PUBLIC_WEB_BASE_URL="http://localhost:3000"
VITE_WEB_BASE_URL="http://localhost:3000"
NEXT_PUBLIC_ADMIN_BASE_URL="http://localhost:3001"
NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode"
VITE_ADMIN_BASE_URL="http://localhost:3001"
VITE_ADMIN_BASE_PATH="/god-mode"
NEXT_PUBLIC_SPACE_BASE_URL="http://localhost:3002"
NEXT_PUBLIC_SPACE_BASE_PATH="/spaces"
VITE_SPACE_BASE_URL="http://localhost:3002"
VITE_SPACE_BASE_PATH="/spaces"
NEXT_PUBLIC_LIVE_BASE_URL="http://localhost:3100"
NEXT_PUBLIC_LIVE_BASE_PATH="/live"
VITE_LIVE_BASE_URL="http://localhost:3100"
VITE_LIVE_BASE_PATH="/live"
+2
View File
@@ -1,4 +1,6 @@
.next/*
.react-router/*
.vite/*
out/*
public/*
dist/*
+18
View File
@@ -0,0 +1,18 @@
module.exports = {
root: true,
extends: ["@plane/eslint-config/next.js"],
ignorePatterns: ["build/**", "dist/**", ".vite/**"],
rules: {
"import/no-duplicates": ["error", { "prefer-inline": false }],
"import/consistent-type-specifier-style": ["error", "prefer-top-level"],
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/consistent-type-imports": [
"error",
{
prefer: "type-imports",
fixStyle: "separate-type-imports",
disallowTypeAnnotations: false,
},
],
},
};
-4
View File
@@ -1,4 +0,0 @@
module.exports = {
root: true,
extends: ["@plane/eslint-config/next.js"],
};
+2
View File
@@ -1,4 +1,6 @@
.next
.react-router
.vite
.vercel
.tubro
out/
+2 -1
View File
@@ -1,5 +1,6 @@
{
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "es5"
"trailingComma": "es5",
"plugins": ["@prettier/plugin-oxc"]
}
+58 -75
View File
@@ -1,103 +1,86 @@
# syntax=docker/dockerfile:1.7
FROM node:22-alpine AS base
# Setup pnpm package manager with corepack and configure global bin directory for caching
WORKDIR /app
ENV TURBO_TELEMETRY_DISABLED=1
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
ENV CI=1
RUN corepack enable pnpm
# =========================================================================== #
# *****************************************************************************
# STAGE 1: Build the project
# *****************************************************************************
FROM base AS builder
RUN apk add --no-cache libc6-compat
WORKDIR /app
ARG TURBO_VERSION=2.5.6
RUN corepack enable pnpm && pnpm add -g turbo@${TURBO_VERSION}
RUN pnpm add -g turbo@2.5.8
COPY . .
# Create a pruned workspace for just the admin app
RUN turbo prune --scope=admin --docker
# *****************************************************************************
# STAGE 2: Install dependencies & build the project
# *****************************************************************************
# =========================================================================== #
FROM base AS installer
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Build in production mode; we still install dev deps explicitly below
ENV NODE_ENV=production
# Public envs required at build time (pick up via process.env)
ARG VITE_API_BASE_URL=""
ENV VITE_API_BASE_URL=$VITE_API_BASE_URL
ARG VITE_API_BASE_PATH="/api"
ENV VITE_API_BASE_PATH=$VITE_API_BASE_PATH
ARG VITE_ADMIN_BASE_URL=""
ENV VITE_ADMIN_BASE_URL=$VITE_ADMIN_BASE_URL
ARG VITE_ADMIN_BASE_PATH="/god-mode"
ENV VITE_ADMIN_BASE_PATH=$VITE_ADMIN_BASE_PATH
ARG VITE_SPACE_BASE_URL=""
ENV VITE_SPACE_BASE_URL=$VITE_SPACE_BASE_URL
ARG VITE_SPACE_BASE_PATH="/spaces"
ENV VITE_SPACE_BASE_PATH=$VITE_SPACE_BASE_PATH
ARG VITE_LIVE_BASE_URL=""
ENV VITE_LIVE_BASE_URL=$VITE_LIVE_BASE_URL
ARG VITE_LIVE_BASE_PATH="/live"
ENV VITE_LIVE_BASE_PATH=$VITE_LIVE_BASE_PATH
ARG VITE_WEB_BASE_URL=""
ENV VITE_WEB_BASE_URL=$VITE_WEB_BASE_URL
ARG VITE_WEB_BASE_PATH=""
ENV VITE_WEB_BASE_PATH=$VITE_WEB_BASE_PATH
ARG VITE_WEBSITE_URL="https://plane.so"
ENV VITE_WEBSITE_URL=$VITE_WEBSITE_URL
ARG VITE_SUPPORT_EMAIL="support@plane.so"
ENV VITE_SUPPORT_EMAIL=$VITE_SUPPORT_EMAIL
COPY .gitignore .gitignore
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
RUN corepack enable pnpm
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm fetch --store-dir=/pnpm/store
# Fetch dependencies to cache store, then install offline with dev deps
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm fetch --store-dir=/pnpm/store
COPY --from=builder /app/out/full/ .
COPY turbo.json turbo.json
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm install --offline --frozen-lockfile --store-dir=/pnpm/store
ARG NEXT_PUBLIC_API_BASE_URL=""
ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL
ARG NEXT_PUBLIC_ADMIN_BASE_URL=""
ENV NEXT_PUBLIC_ADMIN_BASE_URL=$NEXT_PUBLIC_ADMIN_BASE_URL
ARG NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode"
ENV NEXT_PUBLIC_ADMIN_BASE_PATH=$NEXT_PUBLIC_ADMIN_BASE_PATH
ARG NEXT_PUBLIC_SPACE_BASE_URL=""
ENV NEXT_PUBLIC_SPACE_BASE_URL=$NEXT_PUBLIC_SPACE_BASE_URL
ARG NEXT_PUBLIC_SPACE_BASE_PATH="/spaces"
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
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store CI=true pnpm install --offline --frozen-lockfile --store-dir=/pnpm/store --prod=false
# Build only the admin package
RUN pnpm turbo run build --filter=admin
# *****************************************************************************
# STAGE 3: Copy the project and start it
# *****************************************************************************
FROM base AS runner
WORKDIR /app
# =========================================================================== #
# Don't run production as root
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs
FROM nginx:1.27-alpine AS production
# 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
ARG NEXT_PUBLIC_ADMIN_BASE_URL=""
ENV NEXT_PUBLIC_ADMIN_BASE_URL=$NEXT_PUBLIC_ADMIN_BASE_URL
ARG NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode"
ENV NEXT_PUBLIC_ADMIN_BASE_PATH=$NEXT_PUBLIC_ADMIN_BASE_PATH
ARG NEXT_PUBLIC_SPACE_BASE_URL=""
ENV NEXT_PUBLIC_SPACE_BASE_URL=$NEXT_PUBLIC_SPACE_BASE_URL
ARG NEXT_PUBLIC_SPACE_BASE_PATH="/spaces"
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
COPY apps/admin/nginx/nginx.conf /etc/nginx/nginx.conf
COPY --from=installer /app/apps/admin/build/client /usr/share/nginx/html/god-mode
EXPOSE 3000
CMD ["node", "apps/admin/server.js"]
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -fsS http://127.0.0.1:3000/ >/dev/null || exit 1
CMD ["nginx", "-g", "daemon off;"]
+1 -1
View File
@@ -8,7 +8,7 @@ COPY . .
RUN corepack enable pnpm && pnpm add -g turbo
RUN pnpm install
ENV NEXT_PUBLIC_ADMIN_BASE_PATH="/god-mode"
ENV VITE_ADMIN_BASE_PATH="/god-mode"
EXPOSE 3000
+5 -6
View File
@@ -1,12 +1,11 @@
"use client";
import { FC } from "react";
import { useForm } from "react-hook-form";
import { Lightbulb } from "lucide-react";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { IFormattedInstanceConfiguration, TInstanceAIConfigurationKeys } from "@plane/types";
import type { IFormattedInstanceConfiguration, TInstanceAIConfigurationKeys } from "@plane/types";
// components
import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
import type { TControllerInputFormField } from "@/components/common/controller-input";
import { ControllerInput } from "@/components/common/controller-input";
// hooks
import { useInstance } from "@/hooks/store";
@@ -16,7 +15,7 @@ type IInstanceAIForm = {
type AIFormValues = Record<TInstanceAIConfigurationKeys, string>;
export const InstanceAIForm: FC<IInstanceAIForm> = (props) => {
export function InstanceAIForm(props: IInstanceAIForm) {
const { config } = props;
// store
const { updateInstanceConfigurations } = useInstance();
@@ -132,4 +131,4 @@ export const InstanceAIForm: FC<IInstanceAIForm> = (props) => {
</div>
</div>
);
};
}
@@ -1,10 +0,0 @@
import { ReactNode } from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Artificial Intelligence Settings - God Mode",
};
export default function AILayout({ children }: { children: ReactNode }) {
return <>{children}</>;
}
+4 -3
View File
@@ -1,14 +1,13 @@
"use client";
import { observer } from "mobx-react";
import useSWR from "swr";
import { Loader } from "@plane/ui";
// hooks
import { useInstance } from "@/hooks/store";
// components
import type { Route } from "./+types/page";
import { InstanceAIForm } from "./form";
const InstanceAIPage = observer(() => {
const InstanceAIPage = observer(function InstanceAIPage(_props: Route.ComponentProps) {
// store
const { fetchInstanceConfigurations, formattedConfig } = useInstance();
@@ -42,4 +41,6 @@ const InstanceAIPage = observer(() => {
);
});
export const meta: Route.MetaFunction = () => [{ title: "Artificial Intelligence Settings - God Mode" }];
export default InstanceAIPage;
@@ -0,0 +1,207 @@
import { useState } from "react";
import { isEmpty } from "lodash-es";
import Link from "next/link";
import { useForm } from "react-hook-form";
// plane internal packages
import { API_BASE_URL } from "@plane/constants";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { IFormattedInstanceConfiguration, TInstanceGiteaAuthenticationConfigurationKeys } from "@plane/types";
import { Button, getButtonStyling } from "@plane/ui";
import { cn } from "@plane/utils";
// components
import { CodeBlock } from "@/components/common/code-block";
import { ConfirmDiscardModal } from "@/components/common/confirm-discard-modal";
import type { TControllerInputFormField } from "@/components/common/controller-input";
import { ControllerInput } from "@/components/common/controller-input";
import type { TCopyField } from "@/components/common/copy-field";
import { CopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";
type Props = {
config: IFormattedInstanceConfiguration;
};
type GiteaConfigFormValues = Record<TInstanceGiteaAuthenticationConfigurationKeys, string>;
export function InstanceGiteaConfigForm(props: Props) {
const { config } = props;
// states
const [isDiscardChangesModalOpen, setIsDiscardChangesModalOpen] = useState(false);
// store hooks
const { updateInstanceConfigurations } = useInstance();
// form data
const {
handleSubmit,
control,
reset,
formState: { errors, isDirty, isSubmitting },
} = useForm<GiteaConfigFormValues>({
defaultValues: {
GITEA_HOST: config["GITEA_HOST"] || "https://gitea.com",
GITEA_CLIENT_ID: config["GITEA_CLIENT_ID"],
GITEA_CLIENT_SECRET: config["GITEA_CLIENT_SECRET"],
},
});
const originURL = !isEmpty(API_BASE_URL) ? API_BASE_URL : typeof window !== "undefined" ? window.location.origin : "";
const GITEA_FORM_FIELDS: TControllerInputFormField[] = [
{
key: "GITEA_HOST",
type: "text",
label: "Gitea Host",
description: (
<>Use the URL of your Gitea instance. For the official Gitea instance, use &quot;https://gitea.com&quot;.</>
),
placeholder: "https://gitea.com",
error: Boolean(errors.GITEA_HOST),
required: true,
},
{
key: "GITEA_CLIENT_ID",
type: "text",
label: "Client ID",
description: (
<>
You will get this from your{" "}
<a
tabIndex={-1}
href="https://gitea.com/user/settings/applications"
target="_blank"
className="text-custom-primary-100 hover:underline"
rel="noreferrer"
>
Gitea OAuth application settings.
</a>
</>
),
placeholder: "70a44354520df8bd9bcd",
error: Boolean(errors.GITEA_CLIENT_ID),
required: true,
},
{
key: "GITEA_CLIENT_SECRET",
type: "password",
label: "Client secret",
description: (
<>
Your client secret is also found in your{" "}
<a
tabIndex={-1}
href="https://gitea.com/user/settings/applications"
target="_blank"
className="text-custom-primary-100 hover:underline"
rel="noreferrer"
>
Gitea OAuth application settings.
</a>
</>
),
placeholder: "9b0050f94ec1b744e32ce79ea4ffacd40d4119cb",
error: Boolean(errors.GITEA_CLIENT_SECRET),
required: true,
},
];
const GITEA_SERVICE_FIELD: TCopyField[] = [
{
key: "Callback_URI",
label: "Callback URI",
url: `${originURL}/auth/gitea/callback/`,
description: (
<>
We will auto-generate this. Paste this into your <CodeBlock darkerShade>Authorized Callback URI</CodeBlock>{" "}
field{" "}
<a
tabIndex={-1}
href={`${control._formValues.GITEA_HOST || "https://gitea.com"}/user/settings/applications`}
target="_blank"
className="text-custom-primary-100 hover:underline"
rel="noreferrer"
>
here.
</a>
</>
),
},
];
const onSubmit = async (formData: GiteaConfigFormValues) => {
const payload: Partial<GiteaConfigFormValues> = { ...formData };
await updateInstanceConfigurations(payload)
.then((response = []) => {
setToast({
type: TOAST_TYPE.SUCCESS,
title: "Done!",
message: "Your Gitea authentication is configured. You should test it now.",
});
reset({
GITEA_HOST: response.find((item) => item.key === "GITEA_HOST")?.value,
GITEA_CLIENT_ID: response.find((item) => item.key === "GITEA_CLIENT_ID")?.value,
GITEA_CLIENT_SECRET: response.find((item) => item.key === "GITEA_CLIENT_SECRET")?.value,
});
})
.catch((err) => console.error(err));
};
const handleGoBack = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
if (isDirty) {
e.preventDefault();
setIsDiscardChangesModalOpen(true);
}
};
return (
<>
<ConfirmDiscardModal
isOpen={isDiscardChangesModalOpen}
onDiscardHref="/authentication"
handleClose={() => setIsDiscardChangesModalOpen(false)}
/>
<div className="flex flex-col gap-8">
<div className="grid grid-cols-2 gap-x-12 gap-y-8 w-full">
<div className="flex flex-col gap-y-4 col-span-2 md:col-span-1 pt-1">
<div className="pt-2.5 text-xl font-medium">Gitea-provided details for Plane</div>
{GITEA_FORM_FIELDS.map((field) => (
<ControllerInput
key={field.key}
control={control}
type={field.type}
name={field.key}
label={field.label}
description={field.description}
placeholder={field.placeholder}
error={field.error}
required={field.required}
/>
))}
<div className="flex flex-col gap-1 pt-4">
<div className="flex items-center gap-4">
<Button variant="primary" onClick={handleSubmit(onSubmit)} loading={isSubmitting} disabled={!isDirty}>
{isSubmitting ? "Saving..." : "Save changes"}
</Button>
<Link
href="/authentication"
className={cn(getButtonStyling("neutral-primary", "md"), "font-medium")}
onClick={handleGoBack}
>
Go back
</Link>
</div>
</div>
</div>
<div className="col-span-2 md:col-span-1">
<div className="flex flex-col gap-y-4 px-6 pt-1.5 pb-4 bg-custom-background-80/60 rounded-lg">
<div className="pt-2 text-xl font-medium">Plane-provided details for Gitea</div>
{GITEA_SERVICE_FIELD.map((field) => (
<CopyField key={field.key} label={field.label} url={field.url} description={field.description} />
))}
</div>
</div>
</div>
</div>
</>
);
}
@@ -0,0 +1,99 @@
import { useState } from "react";
import { observer } from "mobx-react";
import useSWR from "swr";
// plane internal packages
import { setPromiseToast } from "@plane/propel/toast";
import { Loader, ToggleSwitch } from "@plane/ui";
// components
import giteaLogo from "@/app/assets/logos/gitea-logo.svg?url";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
//local components
import type { Route } from "./+types/page";
import { InstanceGiteaConfigForm } from "./form";
const InstanceGiteaAuthenticationPage = observer(function InstanceGiteaAuthenticationPage() {
// store
const { fetchInstanceConfigurations, formattedConfig, updateInstanceConfigurations } = useInstance();
// state
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
// config
const enableGiteaConfig = formattedConfig?.IS_GITEA_ENABLED ?? "";
useSWR("INSTANCE_CONFIGURATIONS", () => fetchInstanceConfigurations());
const updateConfig = async (key: "IS_GITEA_ENABLED", value: string) => {
setIsSubmitting(true);
const payload = {
[key]: value,
};
const updateConfigPromise = updateInstanceConfigurations(payload);
setPromiseToast(updateConfigPromise, {
loading: "Saving Configuration...",
success: {
title: "Configuration saved",
message: () => `Gitea authentication is now ${value === "1" ? "active" : "disabled"}.`,
},
error: {
title: "Error",
message: () => "Failed to save configuration",
},
});
await updateConfigPromise
.then(() => {
setIsSubmitting(false);
})
.catch((err) => {
console.error(err);
setIsSubmitting(false);
});
};
const isGiteaEnabled = enableGiteaConfig === "1";
return (
<>
<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
name="Gitea"
description="Allow members to login or sign up to plane with their Gitea accounts."
icon={<img src={giteaLogo} height={24} width={24} alt="Gitea Logo" />}
config={
<ToggleSwitch
value={isGiteaEnabled}
onChange={() => {
updateConfig("IS_GITEA_ENABLED", isGiteaEnabled ? "0" : "1");
}}
size="sm"
disabled={isSubmitting || !formattedConfig}
/>
}
disabled={isSubmitting || !formattedConfig}
withBorder={false}
/>
</div>
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
{formattedConfig ? (
<InstanceGiteaConfigForm config={formattedConfig} />
) : (
<Loader className="space-y-8">
<Loader.Item height="50px" width="25%" />
<Loader.Item height="50px" />
<Loader.Item height="50px" />
<Loader.Item height="50px" />
<Loader.Item height="50px" width="50%" />
</Loader>
)}
</div>
</div>
</>
);
});
export const meta: Route.MetaFunction = () => [{ title: "Gitea Authentication - God Mode" }];
export default InstanceGiteaAuthenticationPage;
@@ -1,6 +1,4 @@
"use client";
import { FC, useState } from "react";
import { useState } from "react";
import { isEmpty } from "lodash-es";
import Link from "next/link";
import { useForm } from "react-hook-form";
@@ -9,14 +7,16 @@ import { Monitor } from "lucide-react";
import { API_BASE_URL } from "@plane/constants";
import { Button, getButtonStyling } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { IFormattedInstanceConfiguration, TInstanceGithubAuthenticationConfigurationKeys } from "@plane/types";
import type { IFormattedInstanceConfiguration, TInstanceGithubAuthenticationConfigurationKeys } from "@plane/types";
import { cn } from "@plane/utils";
// components
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";
import type { TControllerInputFormField } from "@/components/common/controller-input";
import { ControllerInput } from "@/components/common/controller-input";
import type { TCopyField } from "@/components/common/copy-field";
import { CopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";
@@ -26,7 +26,7 @@ type Props = {
type GithubConfigFormValues = Record<TInstanceGithubAuthenticationConfigurationKeys, string>;
export const InstanceGithubConfigForm: FC<Props> = (props) => {
export function InstanceGithubConfigForm(props: Props) {
const { config } = props;
// states
const [isDiscardChangesModalOpen, setIsDiscardChangesModalOpen] = useState(false);
@@ -243,4 +243,4 @@ export const InstanceGithubConfigForm: FC<Props> = (props) => {
</div>
</>
);
};
}
@@ -1,10 +0,0 @@
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}</>;
}
@@ -1,8 +1,5 @@
"use client";
import { useState } from "react";
import { observer } from "mobx-react";
import Image from "next/image";
import { useTheme } from "next-themes";
import useSWR from "swr";
// plane internal packages
@@ -10,16 +7,19 @@ import { setPromiseToast } from "@plane/propel/toast";
import { Loader, ToggleSwitch } from "@plane/ui";
import { resolveGeneralTheme } from "@plane/utils";
// components
import githubLightModeImage from "@/app/assets/logos/github-black.png?url";
import githubDarkModeImage from "@/app/assets/logos/github-white.png?url";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
import githubLightModeImage from "@/public/logos/github-black.png";
import githubDarkModeImage from "@/public/logos/github-white.png";
// local components
import type { Route } from "./+types/page";
import { InstanceGithubConfigForm } from "./form";
const InstanceGithubAuthenticationPage = observer(() => {
const InstanceGithubAuthenticationPage = observer(function InstanceGithubAuthenticationPage(
_props: Route.ComponentProps
) {
// store
const { fetchInstanceConfigurations, formattedConfig, updateInstanceConfigurations } = useInstance();
// state
@@ -44,7 +44,7 @@ const InstanceGithubAuthenticationPage = observer(() => {
loading: "Saving Configuration...",
success: {
title: "Configuration saved",
message: () => `GitHub authentication is now ${value ? "active" : "disabled"}.`,
message: () => `GitHub authentication is now ${value === "1" ? "active" : "disabled"}.`,
},
error: {
title: "Error",
@@ -72,7 +72,7 @@ const InstanceGithubAuthenticationPage = observer(() => {
name="GitHub"
description="Allow members to login or sign up to plane with their GitHub accounts."
icon={
<Image
<img
src={resolveGeneralTheme(resolvedTheme) === "dark" ? githubDarkModeImage : githubLightModeImage}
height={24}
width={24}
@@ -111,4 +111,6 @@ const InstanceGithubAuthenticationPage = observer(() => {
);
});
export const meta: Route.MetaFunction = () => [{ title: "GitHub Authentication - God Mode" }];
export default InstanceGithubAuthenticationPage;
@@ -1,4 +1,4 @@
import { FC, useState } from "react";
import { useState } from "react";
import { isEmpty } from "lodash-es";
import Link from "next/link";
import { useForm } from "react-hook-form";
@@ -6,13 +6,15 @@ import { useForm } from "react-hook-form";
import { API_BASE_URL } from "@plane/constants";
import { Button, getButtonStyling } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { IFormattedInstanceConfiguration, TInstanceGitlabAuthenticationConfigurationKeys } from "@plane/types";
import type { IFormattedInstanceConfiguration, TInstanceGitlabAuthenticationConfigurationKeys } from "@plane/types";
import { cn } from "@plane/utils";
// components
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";
import type { TControllerInputFormField } from "@/components/common/controller-input";
import { ControllerInput } from "@/components/common/controller-input";
import type { TCopyField } from "@/components/common/copy-field";
import { CopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";
@@ -22,7 +24,7 @@ type Props = {
type GitlabConfigFormValues = Record<TInstanceGitlabAuthenticationConfigurationKeys, string>;
export const InstanceGitlabConfigForm: FC<Props> = (props) => {
export function InstanceGitlabConfigForm(props: Props) {
const { config } = props;
// states
const [isDiscardChangesModalOpen, setIsDiscardChangesModalOpen] = useState(false);
@@ -206,4 +208,4 @@ export const InstanceGitlabConfigForm: FC<Props> = (props) => {
</div>
</>
);
};
}
@@ -1,10 +0,0 @@
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}</>;
}
@@ -1,21 +1,21 @@
"use client";
import { useState } from "react";
import { observer } from "mobx-react";
import Image from "next/image";
import useSWR from "swr";
import { setPromiseToast } from "@plane/propel/toast";
import { Loader, ToggleSwitch } from "@plane/ui";
// components
import GitlabLogo from "@/app/assets/logos/gitlab-logo.svg?url";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
import GitlabLogo from "@/public/logos/gitlab-logo.svg";
// local components
import type { Route } from "./+types/page";
import { InstanceGitlabConfigForm } from "./form";
const InstanceGitlabAuthenticationPage = observer(() => {
const InstanceGitlabAuthenticationPage = observer(function InstanceGitlabAuthenticationPage(
_props: Route.ComponentProps
) {
// store
const { fetchInstanceConfigurations, formattedConfig, updateInstanceConfigurations } = useInstance();
// state
@@ -38,7 +38,7 @@ const InstanceGitlabAuthenticationPage = observer(() => {
loading: "Saving Configuration...",
success: {
title: "Configuration saved",
message: () => `GitLab authentication is now ${value ? "active" : "disabled"}.`,
message: () => `GitLab authentication is now ${value === "1" ? "active" : "disabled"}.`,
},
error: {
title: "Error",
@@ -62,7 +62,7 @@ const InstanceGitlabAuthenticationPage = observer(() => {
<AuthenticationMethodCard
name="GitLab"
description="Allow members to login or sign up to plane with their GitLab accounts."
icon={<Image src={GitlabLogo} height={24} width={24} alt="GitLab Logo" />}
icon={<img src={GitlabLogo} height={24} width={24} alt="GitLab Logo" />}
config={
<ToggleSwitch
value={Boolean(parseInt(enableGitlabConfig))}
@@ -99,4 +99,6 @@ const InstanceGitlabAuthenticationPage = observer(() => {
);
});
export const meta: Route.MetaFunction = () => [{ title: "GitLab Authentication - God Mode" }];
export default InstanceGitlabAuthenticationPage;
@@ -1,5 +1,4 @@
"use client";
import { FC, useState } from "react";
import { useState } from "react";
import { isEmpty } from "lodash-es";
import Link from "next/link";
import { useForm } from "react-hook-form";
@@ -8,13 +7,15 @@ import { Monitor } from "lucide-react";
import { API_BASE_URL } from "@plane/constants";
import { Button, getButtonStyling } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { IFormattedInstanceConfiguration, TInstanceGoogleAuthenticationConfigurationKeys } from "@plane/types";
import type { IFormattedInstanceConfiguration, TInstanceGoogleAuthenticationConfigurationKeys } from "@plane/types";
import { cn } from "@plane/utils";
// components
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";
import type { TControllerInputFormField } from "@/components/common/controller-input";
import { ControllerInput } from "@/components/common/controller-input";
import type { TCopyField } from "@/components/common/copy-field";
import { CopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";
@@ -24,7 +25,7 @@ type Props = {
type GoogleConfigFormValues = Record<TInstanceGoogleAuthenticationConfigurationKeys, string>;
export const InstanceGoogleConfigForm: FC<Props> = (props) => {
export function InstanceGoogleConfigForm(props: Props) {
const { config } = props;
// states
const [isDiscardChangesModalOpen, setIsDiscardChangesModalOpen] = useState(false);
@@ -229,4 +230,4 @@ export const InstanceGoogleConfigForm: FC<Props> = (props) => {
</div>
</>
);
};
}
@@ -1,10 +0,0 @@
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}</>;
}
@@ -1,21 +1,21 @@
"use client";
import { useState } from "react";
import { observer } from "mobx-react";
import Image from "next/image";
import useSWR from "swr";
import { setPromiseToast } from "@plane/propel/toast";
import { Loader, ToggleSwitch } from "@plane/ui";
// components
import GoogleLogo from "@/app/assets/logos/google-logo.svg?url";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
import GoogleLogo from "@/public/logos/google-logo.svg";
// local components
import type { Route } from "./+types/page";
import { InstanceGoogleConfigForm } from "./form";
const InstanceGoogleAuthenticationPage = observer(() => {
const InstanceGoogleAuthenticationPage = observer(function InstanceGoogleAuthenticationPage(
_props: Route.ComponentProps
) {
// store
const { fetchInstanceConfigurations, formattedConfig, updateInstanceConfigurations } = useInstance();
// state
@@ -38,7 +38,7 @@ const InstanceGoogleAuthenticationPage = observer(() => {
loading: "Saving Configuration...",
success: {
title: "Configuration saved",
message: () => `Google authentication is now ${value ? "active" : "disabled"}.`,
message: () => `Google authentication is now ${value === "1" ? "active" : "disabled"}.`,
},
error: {
title: "Error",
@@ -63,7 +63,7 @@ const InstanceGoogleAuthenticationPage = observer(() => {
name="Google"
description="Allow members to login or sign up to plane with their Google
accounts."
icon={<Image src={GoogleLogo} height={24} width={24} alt="Google Logo" />}
icon={<img src={GoogleLogo} height={24} width={24} alt="Google Logo" />}
config={
<ToggleSwitch
value={Boolean(parseInt(enableGoogleConfig))}
@@ -100,4 +100,6 @@ const InstanceGoogleAuthenticationPage = observer(() => {
);
});
export const meta: Route.MetaFunction = () => [{ title: "Google Authentication - God Mode" }];
export default InstanceGoogleAuthenticationPage;
@@ -1,10 +0,0 @@
import { ReactNode } from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Authentication Settings - Plane Web",
};
export default function AuthenticationLayout({ children }: { children: ReactNode }) {
return <>{children}</>;
}
@@ -1,19 +1,18 @@
"use client";
import { useState } from "react";
import { observer } from "mobx-react";
import useSWR from "swr";
// plane internal packages
import { setPromiseToast } from "@plane/propel/toast";
import { TInstanceConfigurationKeys } from "@plane/types";
import type { TInstanceConfigurationKeys } from "@plane/types";
import { Loader, ToggleSwitch } from "@plane/ui";
import { cn } from "@plane/utils";
// hooks
import { useInstance } from "@/hooks/store";
// plane admin components
import { AuthenticationModes } from "@/plane-admin/components/authentication";
import type { Route } from "./+types/page";
const InstanceAuthenticationPage = observer(() => {
const InstanceAuthenticationPage = observer(function InstanceAuthenticationPage(_props: Route.ComponentProps) {
// store
const { fetchInstanceConfigurations, formattedConfig, updateInstanceConfigurations } = useInstance();
@@ -111,4 +110,6 @@ const InstanceAuthenticationPage = observer(() => {
);
});
export const meta: Route.MetaFunction = () => [{ title: "Authentication Settings - Plane Web" }];
export default InstanceAuthenticationPage;
@@ -1,15 +1,14 @@
"use client";
import React, { FC, useMemo, useState } from "react";
import { useMemo, useState } from "react";
import { useForm } from "react-hook-form";
// types
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { IFormattedInstanceConfiguration, TInstanceEmailConfigurationKeys } from "@plane/types";
import type { IFormattedInstanceConfiguration, TInstanceEmailConfigurationKeys } from "@plane/types";
// ui
import { CustomSelect } from "@plane/ui";
// components
import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
import type { TControllerInputFormField } from "@/components/common/controller-input";
import { ControllerInput } from "@/components/common/controller-input";
// hooks
import { useInstance } from "@/hooks/store";
// local components
@@ -29,7 +28,7 @@ const EMAIL_SECURITY_OPTIONS: { [key in TEmailSecurityKeys]: string } = {
NONE: "No email security",
};
export const InstanceEmailForm: FC<IInstanceEmailForm> = (props) => {
export function InstanceEmailForm(props: IInstanceEmailForm) {
const { config } = props;
// states
const [isSendTestEmailModalOpen, setIsSendTestEmailModalOpen] = useState(false);
@@ -223,4 +222,4 @@ export const InstanceEmailForm: FC<IInstanceEmailForm> = (props) => {
</div>
</div>
);
};
}
@@ -1,14 +0,0 @@
import { ReactNode } from "react";
import { Metadata } from "next";
interface EmailLayoutProps {
children: ReactNode;
}
export const metadata: Metadata = {
title: "Email Settings - God Mode",
};
export default function EmailLayout({ children }: EmailLayoutProps) {
return <>{children}</>;
}
@@ -1,5 +1,3 @@
"use client";
import { useEffect, useState } from "react";
import { observer } from "mobx-react";
import useSWR from "swr";
@@ -8,9 +6,10 @@ import { Loader, ToggleSwitch } from "@plane/ui";
// hooks
import { useInstance } from "@/hooks/store";
// components
import type { Route } from "./+types/page";
import { InstanceEmailForm } from "./email-config-form";
const InstanceEmailPage: React.FC = observer(() => {
const InstanceEmailPage = observer(function InstanceEmailPage(_props: Route.ComponentProps) {
// store
const { fetchInstanceConfigurations, formattedConfig, disableEmail } = useInstance();
@@ -91,4 +90,6 @@ const InstanceEmailPage: React.FC = observer(() => {
);
});
export const meta: Route.MetaFunction = () => [{ title: "Email Settings - God Mode" }];
export default InstanceEmailPage;
@@ -1,4 +1,4 @@
import React, { FC, useEffect, useState } from "react";
import { useEffect, useState, Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";
// plane imports
import { Button } from "@plane/propel/button";
@@ -19,7 +19,7 @@ enum ESendEmailSteps {
const instanceService = new InstanceService();
export const SendTestEmailModal: FC<Props> = (props) => {
export function SendTestEmailModal(props: Props) {
const { isOpen, handleClose } = props;
// state
@@ -61,10 +61,10 @@ export const SendTestEmailModal: FC<Props> = (props) => {
};
return (
<Transition.Root show={isOpen} as={React.Fragment}>
<Transition.Root show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-20" onClose={handleClose}>
<Transition.Child
as={React.Fragment}
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
@@ -77,7 +77,7 @@ export const SendTestEmailModal: FC<Props> = (props) => {
<div className="fixed inset-0 z-20 overflow-y-auto">
<div className="my-10 flex justify-center p-4 text-center sm:p-0 md:my-20">
<Transition.Child
as={React.Fragment}
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
@@ -133,4 +133,4 @@ export const SendTestEmailModal: FC<Props> = (props) => {
</Dialog>
</Transition.Root>
);
};
}
@@ -1,12 +1,10 @@
"use client";
import { FC } from "react";
import { observer } from "mobx-react";
import { Controller, useForm } from "react-hook-form";
import { Telescope } from "lucide-react";
// types
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { IInstance, IInstanceAdmin } from "@plane/types";
import type { IInstance, IInstanceAdmin } from "@plane/types";
// ui
import { Input, ToggleSwitch } from "@plane/ui";
// components
@@ -20,7 +18,7 @@ export interface IGeneralConfigurationForm {
instanceAdmins: IInstanceAdmin[];
}
export const GeneralConfigurationForm: FC<IGeneralConfigurationForm> = observer((props) => {
export const GeneralConfigurationForm = observer(function GeneralConfigurationForm(props: IGeneralConfigurationForm) {
const { instance, instanceAdmins } = props;
// hooks
const { instanceConfigurations, updateInstanceInfo, updateInstanceConfigurations } = useInstance();
@@ -1,10 +1,8 @@
"use client";
import { FC, useState } from "react";
import { useState } from "react";
import { observer } from "mobx-react";
import useSWR from "swr";
import { MessageSquare } from "lucide-react";
import { IFormattedInstanceConfiguration } from "@plane/types";
import type { IFormattedInstanceConfiguration } from "@plane/types";
import { ToggleSwitch } from "@plane/ui";
// hooks
import { useInstance } from "@/hooks/store";
@@ -13,7 +11,7 @@ type TIntercomConfig = {
isTelemetryEnabled: boolean;
};
export const IntercomConfig: FC<TIntercomConfig> = observer((props) => {
export const IntercomConfig = observer(function IntercomConfig(props: TIntercomConfig) {
const { isTelemetryEnabled } = props;
// hooks
const { instanceConfigurations, updateInstanceConfigurations, fetchInstanceConfigurations } = useInstance();
@@ -1,10 +0,0 @@
import { ReactNode } from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "General Settings - God Mode",
};
export default function GeneralLayout({ children }: { children: ReactNode }) {
return <>{children}</>;
}
@@ -1,8 +1,8 @@
"use client";
import { observer } from "mobx-react";
// hooks
import { useInstance } from "@/hooks/store";
// components
import type { Route } from "./+types/page";
import { GeneralConfigurationForm } from "./form";
function GeneralPage() {
@@ -28,4 +28,6 @@ function GeneralPage() {
);
}
export const meta: Route.MetaFunction = () => [{ title: "General Settings - God Mode" }];
export default observer(GeneralPage);
+4 -5
View File
@@ -1,6 +1,3 @@
"use client";
import { FC } from "react";
import { observer } from "mobx-react";
import { usePathname } from "next/navigation";
import { Menu, Settings } from "lucide-react";
@@ -11,7 +8,7 @@ import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
// hooks
import { useTheme } from "@/hooks/store";
export const HamburgerToggle: FC = observer(() => {
export const HamburgerToggle = observer(function HamburgerToggle() {
const { isSidebarCollapsed, toggleSidebar } = useTheme();
return (
<div
@@ -23,7 +20,7 @@ export const HamburgerToggle: FC = observer(() => {
);
});
export const AdminHeader: FC = observer(() => {
export const AdminHeader = observer(function AdminHeader() {
const pathName = usePathname();
const getHeaderTitle = (pathName: string) => {
@@ -44,6 +41,8 @@ export const AdminHeader: FC = observer(() => {
return "GitHub";
case "gitlab":
return "GitLab";
case "gitea":
return "Gitea";
case "workspace":
return "Workspace";
case "create":
@@ -1,9 +1,7 @@
"use client";
import { FC } from "react";
import { useForm } from "react-hook-form";
import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { IFormattedInstanceConfiguration, TInstanceImageConfigurationKeys } from "@plane/types";
import type { IFormattedInstanceConfiguration, TInstanceImageConfigurationKeys } from "@plane/types";
// components
import { ControllerInput } from "@/components/common/controller-input";
// hooks
@@ -15,7 +13,7 @@ type IInstanceImageConfigForm = {
type ImageConfigFormValues = Record<TInstanceImageConfigurationKeys, string>;
export const InstanceImageConfigForm: FC<IInstanceImageConfigForm> = (props) => {
export function InstanceImageConfigForm(props: IInstanceImageConfigForm) {
const { config } = props;
// store hooks
const { updateInstanceConfigurations } = useInstance();
@@ -78,4 +76,4 @@ export const InstanceImageConfigForm: FC<IInstanceImageConfigForm> = (props) =>
</div>
</div>
);
};
}
@@ -1,14 +0,0 @@
import { ReactNode } from "react";
import { Metadata } from "next";
interface ImageLayoutProps {
children: ReactNode;
}
export const metadata: Metadata = {
title: "Images Settings - God Mode",
};
export default function ImageLayout({ children }: ImageLayoutProps) {
return <>{children}</>;
}
@@ -1,14 +1,13 @@
"use client";
import { observer } from "mobx-react";
import useSWR from "swr";
import { Loader } from "@plane/ui";
// hooks
import { useInstance } from "@/hooks/store";
// local
import type { Route } from "./+types/page";
import { InstanceImageConfigForm } from "./form";
const InstanceImagePage = observer(() => {
const InstanceImagePage = observer(function InstanceImagePage(_props: Route.ComponentProps) {
// store
const { formattedConfig, fetchInstanceConfigurations } = useInstance();
@@ -38,4 +37,6 @@ const InstanceImagePage = observer(() => {
);
});
export const meta: Route.MetaFunction = () => [{ title: "Images Settings - God Mode" }];
export default InstanceImagePage;
+11 -16
View File
@@ -1,33 +1,26 @@
"use client";
import { FC, ReactNode, useEffect } from "react";
import { useEffect } from "react";
import { observer } from "mobx-react";
import { useRouter } from "next/navigation";
import { Outlet } from "react-router";
// components
import { LogoSpinner } from "@/components/common/logo-spinner";
import { NewUserPopup } from "@/components/new-user-popup";
// hooks
import { useUser } from "@/hooks/store";
// local components
import type { Route } from "./+types/layout";
import { AdminHeader } from "./header";
import { AdminSidebar } from "./sidebar";
type TAdminLayout = {
children: ReactNode;
};
const AdminLayout: FC<TAdminLayout> = (props) => {
const { children } = props;
function AdminLayout(_props: Route.ComponentProps) {
// router
const router = useRouter();
const { replace } = useRouter();
// store hooks
const { isUserLoggedIn } = useUser();
useEffect(() => {
if (isUserLoggedIn === false) {
router.push("/");
}
}, [router, isUserLoggedIn]);
if (isUserLoggedIn === false) replace("/");
}, [replace, isUserLoggedIn]);
if (isUserLoggedIn === undefined) {
return (
@@ -43,7 +36,9 @@ const AdminLayout: FC<TAdminLayout> = (props) => {
<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>
<div className="h-full w-full overflow-hidden">
<Outlet />
</div>
</main>
<NewUserPopup />
</div>
@@ -51,6 +46,6 @@ const AdminLayout: FC<TAdminLayout> = (props) => {
}
return <></>;
};
}
export default observer(AdminLayout);
@@ -1,5 +1,3 @@
"use client";
import { Fragment, useEffect, useState } from "react";
import { observer } from "mobx-react";
import { useTheme as useNextTheme } from "next-themes";
@@ -16,7 +14,7 @@ import { useTheme, useUser } from "@/hooks/store";
// service initialization
const authService = new AuthService();
export const AdminSidebarDropdown = observer(() => {
export const AdminSidebarDropdown = observer(function AdminSidebarDropdown() {
// store hooks
const { isSidebarCollapsed } = useTheme();
const { currentUser, signOut } = useUser();
@@ -1,13 +1,11 @@
"use client";
import { FC, useState, useRef } from "react";
import { useState, useRef } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
import { ExternalLink, FileText, HelpCircle, MoveLeft } from "lucide-react";
import { ExternalLink, HelpCircle, MoveLeft } from "lucide-react";
import { Transition } from "@headlessui/react";
// plane internal packages
import { WEB_BASE_URL } from "@plane/constants";
import { DiscordIcon, GithubIcon } from "@plane/propel/icons";
import { DiscordIcon, GithubIcon, PageIcon } from "@plane/propel/icons";
import { Tooltip } from "@plane/propel/tooltip";
import { cn } from "@plane/utils";
// hooks
@@ -20,7 +18,7 @@ const helpOptions = [
{
name: "Documentation",
href: "https://docs.plane.so/",
Icon: FileText,
Icon: PageIcon,
},
{
name: "Join our Discord",
@@ -34,7 +32,7 @@ const helpOptions = [
},
];
export const AdminSidebarHelpSection: FC = observer(() => {
export const AdminSidebarHelpSection = observer(function AdminSidebarHelpSection() {
// states
const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false);
// store
@@ -110,7 +108,7 @@ export const AdminSidebarHelpSection: FC = observer(() => {
<Link href={href} key={name} target="_blank">
<div className="flex items-center gap-x-2 rounded px-2 py-1 text-xs hover:bg-custom-background-80">
<div className="grid flex-shrink-0 place-items-center">
<Icon className="h-3.5 w-3.5 text-custom-text-200" size={14} />
<Icon className="h-3.5 w-3.5 text-custom-text-200" width={14} height={14} />
</div>
<span className="text-xs">{name}</span>
</div>
@@ -1,5 +1,3 @@
"use client";
import { observer } from "mobx-react";
import Link from "next/link";
import { usePathname } from "next/navigation";
@@ -50,7 +48,7 @@ const INSTANCE_ADMIN_LINKS = [
},
];
export const AdminSidebarMenu = observer(() => {
export const AdminSidebarMenu = observer(function AdminSidebarMenu() {
// store hooks
const { isSidebarCollapsed, toggleSidebar } = useTheme();
// router
+2 -4
View File
@@ -1,6 +1,4 @@
"use client";
import { FC, useEffect, useRef } from "react";
import { useEffect, useRef } from "react";
import { observer } from "mobx-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/hooks";
@@ -11,7 +9,7 @@ import { AdminSidebarDropdown } from "./sidebar-dropdown";
import { AdminSidebarHelpSection } from "./sidebar-help-section";
import { AdminSidebarMenu } from "./sidebar-menu";
export const AdminSidebar: FC = observer(() => {
export const AdminSidebar = observer(function AdminSidebar() {
// store
const { isSidebarCollapsed, toggleSidebar } = useTheme();
@@ -7,7 +7,7 @@ import { WEB_BASE_URL, ORGANIZATION_SIZE, RESTRICTED_URLS } from "@plane/constan
import { Button, getButtonStyling } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { InstanceWorkspaceService } from "@plane/services";
import { IWorkspace } from "@plane/types";
import type { IWorkspace } from "@plane/types";
// components
import { CustomSelect, Input } from "@plane/ui";
// hooks
@@ -15,7 +15,7 @@ import { useWorkspace } from "@/hooks/store";
const instanceWorkspaceService = new InstanceWorkspaceService();
export const WorkspaceCreateForm = () => {
export function WorkspaceCreateForm() {
// router
const router = useRouter();
// states
@@ -209,4 +209,4 @@ export const WorkspaceCreateForm = () => {
</div>
</div>
);
};
}
@@ -1,21 +1,24 @@
"use client";
import { observer } from "mobx-react";
// components
import type { Route } from "./+types/page";
import { WorkspaceCreateForm } from "./form";
const WorkspaceCreatePage = observer(() => (
<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">
<div className="text-xl font-medium text-custom-text-100">Create a new workspace on this instance.</div>
<div className="text-sm font-normal text-custom-text-300">
You will need to invite users from Workspace Settings after you create this workspace.
const WorkspaceCreatePage = observer(function WorkspaceCreatePage(_props: Route.ComponentProps) {
return (
<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">
<div className="text-xl font-medium text-custom-text-100">Create a new workspace on this instance.</div>
<div className="text-sm font-normal text-custom-text-300">
You will need to invite users from Workspace Settings after you create this workspace.
</div>
</div>
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
<WorkspaceCreateForm />
</div>
</div>
<div className="flex-grow overflow-hidden overflow-y-scroll vertical-scrollbar scrollbar-md px-4">
<WorkspaceCreateForm />
</div>
</div>
));
);
});
export const meta: Route.MetaFunction = () => [{ title: "Create Workspace - God Mode" }];
export default WorkspaceCreatePage;
@@ -1,10 +0,0 @@
import { ReactNode } from "react";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Workspace Management - God Mode",
};
export default function WorkspaceManagementLayout({ children }: { children: ReactNode }) {
return <>{children}</>;
}
@@ -1,5 +1,3 @@
"use client";
import { useState } from "react";
import { observer } from "mobx-react";
import Link from "next/link";
@@ -8,7 +6,7 @@ import { Loader as LoaderIcon } from "lucide-react";
// types
import { Button, getButtonStyling } from "@plane/propel/button";
import { setPromiseToast } from "@plane/propel/toast";
import { TInstanceConfigurationKeys } from "@plane/types";
import type { TInstanceConfigurationKeys } from "@plane/types";
import { Loader, ToggleSwitch } from "@plane/ui";
import { cn } from "@plane/utils";
@@ -16,8 +14,9 @@ import { cn } from "@plane/utils";
import { WorkspaceListItem } from "@/components/workspace/list-item";
// hooks
import { useInstance, useWorkspace } from "@/hooks/store";
import type { Route } from "./+types/page";
const WorkspaceManagementPage = observer(() => {
const WorkspaceManagementPage = observer(function WorkspaceManagementPage(_props: Route.ComponentProps) {
// states
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
// store
@@ -167,4 +166,6 @@ const WorkspaceManagementPage = observer(() => {
);
});
export const meta: Route.MetaFunction = () => [{ title: "Workspace Management - God Mode" }];
export default WorkspaceManagementPage;
+7 -6
View File
@@ -1,14 +1,15 @@
import { FC } from "react";
import { Info, X } from "lucide-react";
import { Info } from "lucide-react";
// plane constants
import { TAdminAuthErrorInfo } from "@plane/constants";
import type { TAdminAuthErrorInfo } from "@plane/constants";
// icons
import { CloseIcon } from "@plane/propel/icons";
type TAuthBanner = {
bannerData: TAdminAuthErrorInfo | undefined;
handleBannerData?: (bannerData: TAdminAuthErrorInfo | undefined) => void;
};
export const AuthBanner: FC<TAuthBanner> = (props) => {
export function AuthBanner(props: TAuthBanner) {
const { bannerData, handleBannerData } = props;
if (!bannerData) return <></>;
@@ -22,8 +23,8 @@ export const AuthBanner: FC<TAuthBanner> = (props) => {
className="relative ml-auto w-6 h-6 rounded-sm flex justify-center items-center transition-all cursor-pointer hover:bg-custom-primary-100/20 text-custom-primary-100/80"
onClick={() => handleBannerData && handleBannerData(undefined)}
>
<X className="w-4 h-4 flex-shrink-0" />
<CloseIcon className="w-4 h-4 flex-shrink-0" />
</div>
</div>
);
};
}
+9 -9
View File
@@ -1,12 +1,12 @@
"use client";
import Link from "next/link";
import { PlaneLockup } from "@plane/propel/icons";
export const AuthHeader = () => (
<div className="flex items-center justify-between gap-6 w-full flex-shrink-0 sticky top-0">
<Link href="/">
<PlaneLockup height={20} width={95} className="text-custom-text-100" />
</Link>
</div>
);
export function AuthHeader() {
return (
<div className="flex items-center justify-between gap-6 w-full flex-shrink-0 sticky top-0">
<Link href="/">
<PlaneLockup height={20} width={95} className="text-custom-text-100" />
</Link>
</div>
);
}
+11 -12
View File
@@ -1,22 +1,21 @@
import { ReactNode } from "react";
import Image from "next/image";
import Link from "next/link";
import { KeyRound, Mails } from "lucide-react";
// plane packages
import { SUPPORT_EMAIL, EAdminAuthErrorCodes, TAdminAuthErrorInfo } from "@plane/constants";
import { TGetBaseAuthenticationModeProps, TInstanceAuthenticationModes } from "@plane/types";
import type { TAdminAuthErrorInfo } from "@plane/constants";
import { SUPPORT_EMAIL, EAdminAuthErrorCodes } from "@plane/constants";
import type { TGetBaseAuthenticationModeProps, TInstanceAuthenticationModes } from "@plane/types";
import { resolveGeneralTheme } from "@plane/utils";
// components
import githubLightModeImage from "@/app/assets/logos/github-black.png?url";
import githubDarkModeImage from "@/app/assets/logos/github-white.png?url";
import GitlabLogo from "@/app/assets/logos/gitlab-logo.svg?url";
import GoogleLogo from "@/app/assets/logos/google-logo.svg?url";
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";
import GitlabLogo from "@/public/logos/gitlab-logo.svg";
import GoogleLogo from "@/public/logos/google-logo.svg";
export enum EErrorAlertType {
BANNER_ALERT = "BANNER_ALERT",
@@ -27,7 +26,7 @@ export enum EErrorAlertType {
}
const errorCodeMessages: {
[key in EAdminAuthErrorCodes]: { title: string; message: (email?: string | undefined) => ReactNode };
[key in EAdminAuthErrorCodes]: { title: string; message: (email?: string | undefined) => React.ReactNode };
} = {
// admin
[EAdminAuthErrorCodes.ADMIN_ALREADY_EXIST]: {
@@ -135,7 +134,7 @@ export const getBaseAuthenticationModes: (props: TGetBaseAuthenticationModeProps
key: "google",
name: "Google",
description: "Allow members to log in or sign up for Plane with their Google accounts.",
icon: <Image src={GoogleLogo} height={20} width={20} alt="Google Logo" />,
icon: <img src={GoogleLogo} height={20} width={20} alt="Google Logo" />,
config: <GoogleConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
@@ -143,7 +142,7 @@ export const getBaseAuthenticationModes: (props: TGetBaseAuthenticationModeProps
name: "GitHub",
description: "Allow members to log in or sign up for Plane with their GitHub accounts.",
icon: (
<Image
<img
src={resolveGeneralTheme(resolvedTheme) === "dark" ? githubDarkModeImage : githubLightModeImage}
height={20}
width={20}
@@ -156,7 +155,7 @@ export const getBaseAuthenticationModes: (props: TGetBaseAuthenticationModeProps
key: "gitlab",
name: "GitLab",
description: "Allow members to log in or sign up to plane with their GitLab accounts.",
icon: <Image src={GitlabLogo} height={20} width={20} alt="GitLab Logo" />,
icon: <img src={GitlabLogo} height={20} width={20} alt="GitLab Logo" />,
config: <GitlabConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
];
+19 -3
View File
@@ -1,9 +1,25 @@
"use client";
import { useEffect } from "react";
import { observer } from "mobx-react";
import { useRouter } from "next/navigation";
import { Outlet } from "react-router";
// hooks
import { useUser } from "@/hooks/store/use-user";
function RootLayout() {
// router
const { replace } = useRouter();
// store hooks
const { isUserLoggedIn } = useUser();
useEffect(() => {
if (isUserLoggedIn === true) replace("/general");
}, [replace, isUserLoggedIn]);
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<div className="relative z-10 flex flex-col items-center w-screen h-screen overflow-hidden overflow-y-auto pt-6 pb-10 px-8">
{children}
<Outlet />
</div>
);
}
export default observer(RootLayout);
+8 -4
View File
@@ -1,5 +1,3 @@
"use client";
import { observer } from "mobx-react";
// components
import { LogoSpinner } from "@/components/common/logo-spinner";
@@ -8,9 +6,10 @@ import { InstanceSetupForm } from "@/components/instance/setup-form";
// hooks
import { useInstance } from "@/hooks/store";
// components
import type { Route } from "./+types/page";
import { InstanceSignInForm } from "./sign-in-form";
const HomePage = () => {
function HomePage() {
// store hooks
const { instance, error } = useInstance();
@@ -35,6 +34,11 @@ const HomePage = () => {
// if instance is fetched and setup is done, show sign in form
return <InstanceSignInForm />;
};
}
export default observer(HomePage);
export const meta: Route.MetaFunction = () => [
{ title: "Admin Instance Setup & Sign-In" },
{ name: "description", content: "Configure your Plane instance or sign in to the admin portal." },
];
+5 -6
View File
@@ -1,10 +1,9 @@
"use client";
import { FC, useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import { useSearchParams } from "next/navigation";
import { Eye, EyeOff } from "lucide-react";
// plane internal packages
import { API_BASE_URL, EAdminAuthErrorCodes, TAdminAuthErrorInfo } from "@plane/constants";
import type { EAdminAuthErrorCodes, TAdminAuthErrorInfo } from "@plane/constants";
import { API_BASE_URL } from "@plane/constants";
import { Button } from "@plane/propel/button";
import { AuthService } from "@plane/services";
import { Input, Spinner } from "@plane/ui";
@@ -44,7 +43,7 @@ const defaultFromData: TFormData = {
password: "",
};
export const InstanceSignInForm: FC = () => {
export function InstanceSignInForm() {
// search params
const searchParams = useSearchParams();
const emailParam = searchParams.get("email") || undefined;
@@ -191,4 +190,4 @@ export const InstanceSignInForm: FC = () => {
</div>
</>
);
};
}
+1 -6
View File
@@ -1,14 +1,9 @@
import { FC, ReactNode } from "react";
import { observer } from "mobx-react";
import useSWR from "swr";
// hooks
import { useInstance } from "@/hooks/store";
type InstanceProviderProps = {
children: ReactNode;
};
export const InstanceProvider: FC<InstanceProviderProps> = observer((props) => {
export const InstanceProvider = observer(function InstanceProvider(props: React.PropsWithChildren) {
const { children } = props;
// store hooks
const { fetchInstanceInfo } = useInstance();
+4 -6
View File
@@ -1,6 +1,4 @@
"use client";
import { ReactNode, createContext } from "react";
import { createContext } from "react";
// plane admin store
import { RootStore } from "@/plane-admin/store/root.store";
@@ -23,12 +21,12 @@ function initializeStore(initialData = {}) {
}
export type StoreProviderProps = {
children: ReactNode;
children: React.ReactNode;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
initialState?: any;
};
export const StoreProvider = ({ children, initialState = {} }: StoreProviderProps) => {
export function StoreProvider({ children, initialState = {} }: StoreProviderProps) {
const store = initializeStore(initialState);
return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>;
};
}
+2 -4
View File
@@ -1,10 +1,8 @@
"use client";
import { useTheme } from "next-themes";
import { Toast } from "@plane/propel/toast";
import { resolveGeneralTheme } from "@plane/utils";
export const ToastWithTheme = () => {
export function ToastWithTheme() {
const { resolvedTheme } = useTheme();
return <Toast theme={resolveGeneralTheme(resolvedTheme)} />;
};
}
+2 -8
View File
@@ -1,16 +1,10 @@
"use client";
import { FC, ReactNode, useEffect } from "react";
import { useEffect } from "react";
import { observer } from "mobx-react";
import useSWR from "swr";
// hooks
import { useInstance, useTheme, useUser } from "@/hooks/store";
interface IUserProvider {
children: ReactNode;
}
export const UserProvider: FC<IUserProvider> = observer(({ children }) => {
export const UserProvider = observer(function UserProvider({ children }: React.PropsWithChildren) {
// hooks
const { isSidebarCollapsed, toggleSidebar } = useTheme();
const { currentUser, fetchCurrentUser } = useUser();

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Before

Width:  |  Height:  |  Size: 466 B

After

Width:  |  Height:  |  Size: 466 B

Before

Width:  |  Height:  |  Size: 761 B

After

Width:  |  Height:  |  Size: 761 B

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

Before

Width:  |  Height:  |  Size: 954 KiB

After

Width:  |  Height:  |  Size: 954 KiB

Before

Width:  |  Height:  |  Size: 418 KiB

After

Width:  |  Height:  |  Size: 418 KiB

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 640 640" width="32" height="32"><path d="m395.9 484.2-126.9-61c-12.5-6-17.9-21.2-11.8-33.8l61-126.9c6-12.5 21.2-17.9 33.8-11.8 17.2 8.3 27.1 13 27.1 13l-.1-109.2 16.7-.1.1 117.1s57.4 24.2 83.1 40.1c3.7 2.3 10.2 6.8 12.9 14.4 2.1 6.1 2 13.1-1 19.3l-61 126.9c-6.2 12.7-21.4 18.1-33.9 12" style="fill:#fff"/><path d="M622.7 149.8c-4.1-4.1-9.6-4-9.6-4s-117.2 6.6-177.9 8c-13.3.3-26.5.6-39.6.7v117.2c-5.5-2.6-11.1-5.3-16.6-7.9 0-36.4-.1-109.2-.1-109.2-29 .4-89.2-2.2-89.2-2.2s-141.4-7.1-156.8-8.5c-9.8-.6-22.5-2.1-39 1.5-8.7 1.8-33.5 7.4-53.8 26.9C-4.9 212.4 6.6 276.2 8 285.8c1.7 11.7 6.9 44.2 31.7 72.5 45.8 56.1 144.4 54.8 144.4 54.8s12.1 28.9 30.6 55.5c25 33.1 50.7 58.9 75.7 62 63 0 188.9-.1 188.9-.1s12 .1 28.3-10.3c14-8.5 26.5-23.4 26.5-23.4S547 483 565 451.5c5.5-9.7 10.1-19.1 14.1-28 0 0 55.2-117.1 55.2-231.1-1.1-34.5-9.6-40.6-11.6-42.6M125.6 353.9c-25.9-8.5-36.9-18.7-36.9-18.7S69.6 321.8 60 295.4c-16.5-44.2-1.4-71.2-1.4-71.2s8.4-22.5 38.5-30c13.8-3.7 31-3.1 31-3.1s7.1 59.4 15.7 94.2c7.2 29.2 24.8 77.7 24.8 77.7s-26.1-3.1-43-9.1m300.3 107.6s-6.1 14.5-19.6 15.4c-5.8.4-10.3-1.2-10.3-1.2s-.3-.1-5.3-2.1l-112.9-55s-10.9-5.7-12.8-15.6c-2.2-8.1 2.7-18.1 2.7-18.1L322 273s4.8-9.7 12.2-13c.6-.3 2.3-1 4.5-1.5 8.1-2.1 18 2.8 18 2.8L467.4 315s12.6 5.7 15.3 16.2c1.9 7.4-.5 14-1.8 17.2-6.3 15.4-55 113.1-55 113.1" style="fill:#609926"/><path d="M326.8 380.1c-8.2.1-15.4 5.8-17.3 13.8s2 16.3 9.1 20c7.7 4 17.5 1.8 22.7-5.4 5.1-7.1 4.3-16.9-1.8-23.1l24-49.1c1.5.1 3.7.2 6.2-.5 4.1-.9 7.1-3.6 7.1-3.6 4.2 1.8 8.6 3.8 13.2 6.1 4.8 2.4 9.3 4.9 13.4 7.3.9.5 1.8 1.1 2.8 1.9 1.6 1.3 3.4 3.1 4.7 5.5 1.9 5.5-1.9 14.9-1.9 14.9-2.3 7.6-18.4 40.6-18.4 40.6-8.1-.2-15.3 5-17.7 12.5-2.6 8.1 1.1 17.3 8.9 21.3s17.4 1.7 22.5-5.3c5-6.8 4.6-16.3-1.1-22.6 1.9-3.7 3.7-7.4 5.6-11.3 5-10.4 13.5-30.4 13.5-30.4.9-1.7 5.7-10.3 2.7-21.3-2.5-11.4-12.6-16.7-12.6-16.7-12.2-7.9-29.2-15.2-29.2-15.2s0-4.1-1.1-7.1c-1.1-3.1-2.8-5.1-3.9-6.3 4.7-9.7 9.4-19.3 14.1-29-4.1-2-8.1-4-12.2-6.1-4.8 9.8-9.7 19.7-14.5 29.5-6.7-.1-12.9 3.5-16.1 9.4-3.4 6.3-2.7 14.1 1.9 19.8z" style="fill:#609926"/></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Before

Width:  |  Height:  |  Size: 742 B

After

Width:  |  Height:  |  Size: 742 B

Before

Width:  |  Height:  |  Size: 702 B

After

Width:  |  Height:  |  Size: 702 B

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

+35
View File
@@ -0,0 +1,35 @@
/**
* Ensures that a URL has a trailing slash while preserving query parameters and fragments
* @param url - The URL to process
* @returns The URL with a trailing slash added to the pathname (if not already present)
*/
export function ensureTrailingSlash(url: string): string {
try {
const fallbackBaseUrl =
typeof window !== "undefined" && window.location.origin ? window.location.origin : "http://dummy.com";
// Handle relative URLs by creating a URL object with a fallback base URL
const urlObj = new URL(url, fallbackBaseUrl);
// Don't modify root path
if (urlObj.pathname === "/") {
return url;
}
// Add trailing slash if it doesn't exist
if (!urlObj.pathname.endsWith("/")) {
urlObj.pathname += "/";
}
// For relative URLs, return just the path + search + hash
if (url.startsWith("/")) {
return urlObj.pathname + urlObj.search + urlObj.hash;
}
// For absolute URLs, return the full URL
return urlObj.toString();
} catch (error) {
// If URL parsing fails, return the original URL
console.warn("Failed to parse URL for trailing slash enforcement:", url, error);
return url;
}
}
+14
View File
@@ -0,0 +1,14 @@
import React from "react";
// Minimal shim so code using next/image compiles under React Router + Vite
// without changing call sites. It just renders a native img.
type NextImageProps = React.ImgHTMLAttributes<HTMLImageElement> & {
src: string;
};
function Image({ src, alt = "", ...rest }: NextImageProps) {
return <img src={src} alt={alt} {...rest} />;
}
export default Image;
+17
View File
@@ -0,0 +1,17 @@
import React from "react";
import { Link as RRLink } from "react-router";
import { ensureTrailingSlash } from "./helper";
type NextLinkProps = React.ComponentProps<"a"> & {
href: string;
replace?: boolean;
prefetch?: boolean; // next.js prop, ignored
scroll?: boolean; // next.js prop, ignored
shallow?: boolean; // next.js prop, ignored
};
function Link({ href, replace, prefetch: _prefetch, scroll: _scroll, shallow: _shallow, ...rest }: NextLinkProps) {
return <RRLink to={ensureTrailingSlash(href)} replace={replace} {...rest} />;
}
export default Link;
+32
View File
@@ -0,0 +1,32 @@
import { useMemo } from "react";
import { useLocation, useNavigate, useSearchParams as useSearchParamsRR } from "react-router";
import { ensureTrailingSlash } from "./helper";
export function useRouter() {
const navigate = useNavigate();
return useMemo(
() => ({
push: (to: string) => navigate(ensureTrailingSlash(to)),
replace: (to: string) => navigate(ensureTrailingSlash(to), { replace: true }),
back: () => navigate(-1),
forward: () => navigate(1),
refresh: () => {
location.reload();
},
prefetch: async (_to: string) => {
// no-op in this shim
},
}),
[navigate]
);
}
export function usePathname(): string {
const { pathname } = useLocation();
return pathname;
}
export function useSearchParams(): URLSearchParams {
const [searchParams] = useSearchParamsRR();
return searchParams;
}
+36
View File
@@ -0,0 +1,36 @@
import React from "react";
import { Link } from "react-router";
// ui
import { Button } from "@plane/propel/button";
// images
import Image404 from "@/app/assets/images/404.svg?url";
function PageNotFound() {
return (
<div className={`h-screen w-full overflow-hidden bg-custom-background-100`}>
<div className="grid h-full place-items-center p-4">
<div className="space-y-8 text-center">
<div className="relative mx-auto h-60 w-60 lg:h-80 lg:w-80">
<img src={Image404} alt="404 - Page not found" className="h-full w-full object-contain" />
</div>
<div className="space-y-2">
<h3 className="text-lg font-semibold">Oops! Something went wrong.</h3>
<p className="text-sm text-custom-text-200">
Sorry, the page you are looking for cannot be found. It may have been removed, had its name changed, or is
temporarily unavailable.
</p>
</div>
<Link to="/general/">
<span className="flex justify-center py-4">
<Button variant="neutral-primary" size="md">
Go to general settings
</Button>
</span>
</Link>
</div>
</div>
</div>
);
}
export default PageNotFound;
+34
View File
@@ -0,0 +1,34 @@
/* eslint-disable import/order */
import * as Sentry from "@sentry/react-router";
import { startTransition, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import { HydratedRouter } from "react-router/dom";
Sentry.init({
dsn: process.env.VITE_SENTRY_DSN,
environment: process.env.VITE_SENTRY_ENVIRONMENT,
sendDefaultPii: process.env.VITE_SENTRY_SEND_DEFAULT_PII ? process.env.VITE_SENTRY_SEND_DEFAULT_PII === "1" : false,
release: process.env.VITE_APP_VERSION,
tracesSampleRate: process.env.VITE_SENTRY_TRACES_SAMPLE_RATE
? parseFloat(process.env.VITE_SENTRY_TRACES_SAMPLE_RATE)
: 0.1,
profilesSampleRate: process.env.VITE_SENTRY_PROFILES_SAMPLE_RATE
? parseFloat(process.env.VITE_SENTRY_PROFILES_SAMPLE_RATE)
: 0.1,
replaysSessionSampleRate: process.env.VITE_SENTRY_REPLAYS_SESSION_SAMPLE_RATE
? parseFloat(process.env.VITE_SENTRY_REPLAYS_SESSION_SAMPLE_RATE)
: 0.1,
replaysOnErrorSampleRate: process.env.VITE_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE
? parseFloat(process.env.VITE_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE)
: 1.0,
integrations: [],
});
startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<HydratedRouter />
</StrictMode>
);
});
-9
View File
@@ -1,9 +0,0 @@
"use client";
export default function RootErrorPage() {
return (
<div>
<p>Something went wrong.</p>
</div>
);
}
-39
View File
@@ -1,39 +0,0 @@
import { ReactNode } from "react";
import { Metadata } from "next";
// plane imports
import { ADMIN_BASE_PATH } from "@plane/constants";
// styles
import "@/styles/globals.css";
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 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`}>{children}</body>
</html>
);
}
@@ -1,25 +1,24 @@
"use client";
import { ThemeProvider } from "next-themes";
import { SWRConfig } from "swr";
// providers
import { InstanceProvider } from "./instance.provider";
import { StoreProvider } from "./store.provider";
import { ToastWithTheme } from "./toast";
import { UserProvider } from "./user.provider";
import { AppProgressBar } from "@/lib/b-progress";
import { InstanceProvider } from "./(all)/instance.provider";
import { StoreProvider } from "./(all)/store.provider";
import { ToastWithTheme } from "./(all)/toast";
import { UserProvider } from "./(all)/user.provider";
const DEFAULT_SWR_CONFIG = {
refreshWhenHidden: false,
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnMount: true,
refreshInterval: 600000,
refreshInterval: 600_000,
errorRetryCount: 3,
};
export default function InstanceLayout({ children }: { children: React.ReactNode }) {
export function AppProviders({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider themes={["light", "dark"]} defaultTheme="system" enableSystem>
<AppProgressBar />
<ToastWithTheme />
<SWRConfig value={DEFAULT_SWR_CONFIG}>
<StoreProvider>
+80
View File
@@ -0,0 +1,80 @@
import type { ReactNode } from "react";
import * as Sentry from "@sentry/react-router";
import { Links, Meta, Outlet, Scripts } from "react-router";
import type { LinksFunction } from "react-router";
import appleTouchIcon from "@/app/assets/favicon/apple-touch-icon.png?url";
import favicon16 from "@/app/assets/favicon/favicon-16x16.png?url";
import favicon32 from "@/app/assets/favicon/favicon-32x32.png?url";
import faviconIco from "@/app/assets/favicon/favicon.ico?url";
import { LogoSpinner } from "@/components/common/logo-spinner";
import globalStyles from "@/styles/globals.css?url";
import type { Route } from "./+types/root";
import { AppProviders } from "./providers";
const APP_TITLE = "Plane | Simple, extensible, open-source project management tool.";
const APP_DESCRIPTION =
"Open-source project management tool to manage work items, sprints, and product roadmaps with peace of mind.";
export const links: LinksFunction = () => [
{ rel: "apple-touch-icon", sizes: "180x180", href: appleTouchIcon },
{ rel: "icon", type: "image/png", sizes: "32x32", href: favicon32 },
{ rel: "icon", type: "image/png", sizes: "16x16", href: favicon16 },
{ rel: "shortcut icon", href: faviconIco },
{ rel: "manifest", href: `/site.webmanifest.json` },
{ rel: "stylesheet", href: globalStyles },
];
export function Layout({ children }: { children: ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body className="antialiased" suppressHydrationWarning>
<AppProviders>{children}</AppProviders>
<Scripts />
</body>
</html>
);
}
export const meta: Route.MetaFunction = () => [
{ title: APP_TITLE },
{ name: "description", content: APP_DESCRIPTION },
{ property: "og:title", content: APP_TITLE },
{ property: "og:description", content: APP_DESCRIPTION },
{ property: "og:url", content: "https://plane.so/" },
{
name: "keywords",
content:
"software development, customer feedback, software, accelerate, code management, release management, project management, work items tracking, agile, scrum, kanban, collaboration",
},
{ name: "twitter:site", content: "@planepowers" },
];
export default function Root() {
return <Outlet />;
}
export function HydrateFallback() {
return (
<div className="relative flex h-screen w-full items-center justify-center">
<LogoSpinner />
</div>
);
}
export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
if (error) {
Sentry.captureException(error);
}
return (
<div>
<p>Something went wrong.</p>
</div>
);
}
+21
View File
@@ -0,0 +1,21 @@
import { index, layout, route } from "@react-router/dev/routes";
import type { RouteConfig } from "@react-router/dev/routes";
export default [
layout("./(all)/(home)/layout.tsx", [index("./(all)/(home)/page.tsx")]),
layout("./(all)/(dashboard)/layout.tsx", [
route("general", "./(all)/(dashboard)/general/page.tsx"),
route("workspace", "./(all)/(dashboard)/workspace/page.tsx"),
route("workspace/create", "./(all)/(dashboard)/workspace/create/page.tsx"),
route("email", "./(all)/(dashboard)/email/page.tsx"),
route("authentication", "./(all)/(dashboard)/authentication/page.tsx"),
route("authentication/github", "./(all)/(dashboard)/authentication/github/page.tsx"),
route("authentication/gitlab", "./(all)/(dashboard)/authentication/gitlab/page.tsx"),
route("authentication/google", "./(all)/(dashboard)/authentication/google/page.tsx"),
route("authentication/gitea", "./(all)/(dashboard)/authentication/gitea/page.tsx"),
route("ai", "./(all)/(dashboard)/ai/page.tsx"),
route("image", "./(all)/(dashboard)/image/page.tsx"),
]),
// Catch-all route for 404 handling - must be last
route("*", "./components/404.tsx"),
] satisfies RouteConfig;
+12
View File
@@ -0,0 +1,12 @@
declare module "next/link" {
type Props = React.ComponentProps<"a"> & {
href: string;
replace?: boolean;
prefetch?: boolean;
scroll?: boolean;
shallow?: boolean;
};
const Link: React.FC<Props>;
export default Link;
}
+13
View File
@@ -0,0 +1,13 @@
declare module "next/navigation" {
export function useRouter(): {
push: (to: string) => void;
replace: (to: string) => void;
back: () => void;
forward: () => void;
refresh: () => void;
prefetch: (to: string) => Promise<void> | void;
};
export function usePathname(): string;
export function useSearchParams(): URLSearchParams;
}
+5
View File
@@ -0,0 +1,5 @@
declare module "virtual:react-router/server-build" {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const build: any;
export default build;
}
@@ -1,17 +1,24 @@
import { observer } from "mobx-react";
import Image from "next/image";
import { useTheme } from "next-themes";
import { KeyRound, Mails } from "lucide-react";
// types
import {
import type {
TGetBaseAuthenticationModeProps,
TInstanceAuthenticationMethodKeys,
TInstanceAuthenticationModes,
} from "@plane/types";
import { resolveGeneralTheme } from "@plane/utils";
// components
import giteaLogo from "@/app/assets/logos/gitea-logo.svg?url";
import githubLightModeImage from "@/app/assets/logos/github-black.png?url";
import githubDarkModeImage from "@/app/assets/logos/github-white.png?url";
import GitlabLogo from "@/app/assets/logos/gitlab-logo.svg?url";
import GoogleLogo from "@/app/assets/logos/google-logo.svg?url";
import OIDCLogo from "@/app/assets/logos/oidc-logo.svg?url";
import SAMLLogo from "@/app/assets/logos/saml-logo.svg?url";
import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
import { EmailCodesConfiguration } from "@/components/authentication/email-config-switch";
import { GiteaConfiguration } from "@/components/authentication/gitea-config";
import { GithubConfiguration } from "@/components/authentication/github-config";
import { GitlabConfiguration } from "@/components/authentication/gitlab-config";
import { GoogleConfiguration } from "@/components/authentication/google-config";
@@ -19,12 +26,6 @@ import { PasswordLoginConfiguration } from "@/components/authentication/password
// plane admin components
import { UpgradeButton } from "@/plane-admin/components/common";
// assets
import githubLightModeImage from "@/public/logos/github-black.png";
import githubDarkModeImage from "@/public/logos/github-white.png";
import GitlabLogo from "@/public/logos/gitlab-logo.svg";
import GoogleLogo from "@/public/logos/google-logo.svg";
import OIDCLogo from "@/public/logos/oidc-logo.svg";
import SAMLLogo from "@/public/logos/saml-logo.svg";
export type TAuthenticationModeProps = {
disabled: boolean;
@@ -56,7 +57,7 @@ export const getAuthenticationModes: (props: TGetBaseAuthenticationModeProps) =>
key: "google",
name: "Google",
description: "Allow members to log in or sign up for Plane with their Google accounts.",
icon: <Image src={GoogleLogo} height={20} width={20} alt="Google Logo" />,
icon: <img src={GoogleLogo} height={20} width={20} alt="Google Logo" />,
config: <GoogleConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
@@ -64,7 +65,7 @@ export const getAuthenticationModes: (props: TGetBaseAuthenticationModeProps) =>
name: "GitHub",
description: "Allow members to log in or sign up for Plane with their GitHub accounts.",
icon: (
<Image
<img
src={resolveGeneralTheme(resolvedTheme) === "dark" ? githubDarkModeImage : githubLightModeImage}
height={20}
width={20}
@@ -77,14 +78,21 @@ export const getAuthenticationModes: (props: TGetBaseAuthenticationModeProps) =>
key: "gitlab",
name: "GitLab",
description: "Allow members to log in or sign up to plane with their GitLab accounts.",
icon: <Image src={GitlabLogo} height={20} width={20} alt="GitLab Logo" />,
icon: <img src={GitlabLogo} height={20} width={20} alt="GitLab Logo" />,
config: <GitlabConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "gitea",
name: "Gitea",
description: "Allow members to log in or sign up to plane with their Gitea accounts.",
icon: <img src={giteaLogo} height={20} width={20} alt="Gitea Logo" />,
config: <GiteaConfiguration disabled={disabled} updateConfig={updateConfig} />,
},
{
key: "oidc",
name: "OIDC",
description: "Authenticate your users via the OpenID Connect protocol.",
icon: <Image src={OIDCLogo} height={22} width={22} alt="OIDC Logo" />,
icon: <img src={OIDCLogo} height={22} width={22} alt="OIDC Logo" />,
config: <UpgradeButton />,
unavailable: true,
},
@@ -92,13 +100,13 @@ export const getAuthenticationModes: (props: TGetBaseAuthenticationModeProps) =>
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" />,
icon: <img 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) => {
export const AuthenticationModes = observer(function AuthenticationModes(props: TAuthenticationModeProps) {
const { disabled, updateConfig } = props;
// next-themes
const { resolvedTheme } = useTheme();
@@ -1,5 +1,3 @@
"use client";
import React from "react";
// icons
import { SquareArrowOutUpRight } from "lucide-react";
@@ -7,9 +5,15 @@ import { SquareArrowOutUpRight } from "lucide-react";
import { getButtonStyling } from "@plane/propel/button";
import { cn } from "@plane/utils";
export const UpgradeButton: React.FC = () => (
<a href="https://plane.so/pricing?mode=self-hosted" target="_blank" className={cn(getButtonStyling("primary", "sm"))}>
Upgrade
<SquareArrowOutUpRight className="h-3.5 w-3.5 p-0.5" />
</a>
);
export function UpgradeButton() {
return (
<a
href="https://plane.so/pricing?mode=self-hosted"
target="_blank"
className={cn(getButtonStyling("primary", "sm"))}
>
Upgrade
<SquareArrowOutUpRight className="h-3.5 w-3.5 p-0.5" />
</a>
);
}
@@ -1,6 +1,3 @@
"use client";
import { FC } from "react";
// helpers
import { cn } from "@plane/utils";
@@ -14,7 +11,7 @@ type Props = {
unavailable?: boolean;
};
export const AuthenticationMethodCard: FC<Props> = (props) => {
export function AuthenticationMethodCard(props: Props) {
const { name, description, icon, config, disabled = false, withBorder = true, unavailable = false } = props;
return (
@@ -53,4 +50,4 @@ export const AuthenticationMethodCard: FC<Props> = (props) => {
<div className={`shrink-0 ${disabled && "opacity-70"}`}>{config}</div>
</div>
);
};
}
@@ -1,9 +1,7 @@
"use client";
import React from "react";
import { observer } from "mobx-react";
// hooks
import { TInstanceAuthenticationMethodKeys } from "@plane/types";
import type { TInstanceAuthenticationMethodKeys } from "@plane/types";
import { ToggleSwitch } from "@plane/ui";
import { useInstance } from "@/hooks/store";
// ui
@@ -14,7 +12,7 @@ type Props = {
updateConfig: (key: TInstanceAuthenticationMethodKeys, value: string) => void;
};
export const EmailCodesConfiguration: React.FC<Props> = observer((props) => {
export const EmailCodesConfiguration = observer(function EmailCodesConfiguration(props: Props) {
const { disabled, updateConfig } = props;
// store
const { formattedConfig } = useInstance();
@@ -0,0 +1,56 @@
import React from "react";
import { observer } from "mobx-react";
import Link from "next/link";
// icons
import { Settings2 } from "lucide-react";
// plane internal packages
import type { TInstanceAuthenticationMethodKeys } from "@plane/types";
import { ToggleSwitch, getButtonStyling } from "@plane/ui";
import { cn } from "@plane/utils";
// hooks
import { useInstance } from "@/hooks/store";
type Props = {
disabled: boolean;
updateConfig: (key: TInstanceAuthenticationMethodKeys, value: string) => void;
};
export const GiteaConfiguration = observer(function GiteaConfiguration(props: Props) {
const { disabled, updateConfig } = props;
// store
const { formattedConfig } = useInstance();
// derived values
const GiteaConfig = formattedConfig?.IS_GITEA_ENABLED ?? "";
const GiteaConfigured =
!!formattedConfig?.GITEA_HOST && !!formattedConfig?.GITEA_CLIENT_ID && !!formattedConfig?.GITEA_CLIENT_SECRET;
return (
<>
{GiteaConfigured ? (
<div className="flex items-center gap-4">
<Link href="/authentication/gitea" className={cn(getButtonStyling("link-primary", "md"), "font-medium")}>
Edit
</Link>
<ToggleSwitch
value={Boolean(parseInt(GiteaConfig))}
onChange={() => {
Boolean(parseInt(GiteaConfig)) === true
? updateConfig("IS_GITEA_ENABLED", "0")
: updateConfig("IS_GITEA_ENABLED", "1");
}}
size="sm"
disabled={disabled}
/>
</div>
) : (
<Link
href="/authentication/gitea"
className={cn(getButtonStyling("neutral-primary", "sm"), "text-custom-text-300")}
>
<Settings2 className="h-4 w-4 p-0.5 text-custom-text-300/80" />
Configure
</Link>
)}
</>
);
});

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