Compare commits

...

1804 Commits

Author SHA1 Message Date
sriram veeraghanta
f751619759 Merge pull request #2312 from makeplane/stage-release
release: stage release to production
2023-09-29 18:08:04 +05:30
sriram veeraghanta
adf49782ba Merge pull request #2311 from makeplane/develop
promote: develop to stage release
2023-09-29 18:07:14 +05:30
sriram veeraghanta
843ba5bb63 fix: unsplash api fix (#2310) 2023-09-29 18:06:33 +05:30
sriram veeraghanta
8d4ac9b430 Merge pull request #2309 from makeplane/stage-release
release: stage release to production
2023-09-29 17:40:17 +05:30
sriram veeraghanta
7c125075b1 Merge pull request #2308 from makeplane/develop
promote: develop to stage release
2023-09-29 16:43:11 +05:30
Anmol Singh Bhatia
4cab00ec79 fix: workspace view filters count fix (#2307) 2023-09-29 16:40:02 +05:30
Bavisetti Narayan
f1879a404d dev: updated migrations for 0.13-dev (#2305)
* chore: epoch migration batch size changed

* chore: reoredered the migration files

* dev: updated migrations for 0.13-dev

* chore: added epoch field

* dev: merged the migration files
2023-09-29 16:12:54 +05:30
sriram veeraghanta
26bb51e686 Merge pull request #2304 from makeplane/develop
promote: develop to stage release
2023-09-29 15:31:31 +05:30
Anmol Singh Bhatia
1b28125919 chore: workspace view order by removed (#2303) 2023-09-29 15:29:50 +05:30
Anmol Singh Bhatia
2a770e4a95 chore: workspace view mutation fix ,bug fixes and code refactor (#2301)
* chore: workspace view mutation fix ,bug fixes and code refactor

* chore: update workspace view toast alert added
2023-09-29 15:05:27 +05:30
sriram veeraghanta
fbf88c3196 Merge pull request #2296 from makeplane/develop
promote: develop to stage release
2023-09-29 12:52:23 +05:30
Anmol Singh Bhatia
459999e8c9 chore: global issues ui improvement and bug fixes (#2300) 2023-09-29 12:36:38 +05:30
Nikhil
6cb4b222d0 chore: label create error (#2299) 2023-09-29 12:27:19 +05:30
Anmol Singh Bhatia
a048e513b7 chore: workspace view display filters and properties , code refactor (#2295)
* chore: spreadsheet view context

* chore: spreadsheet context provider

* chore: spreadsheet view context

* chore: display filters and properties added in workspace view and code refactor

* fix: build error fix

* chore: set sub-issue display option to false for global views

---------

Co-authored-by: gurusainath <gurusainath007@gmail.com>
2023-09-28 20:34:57 +05:30
Nikhil
4503810aeb fix: notifications for created by me and assigned to me (#2292) 2023-09-28 15:37:42 +05:30
Dakshesh Jain
ec91a0d2e5 fix: ui and bugs (#2289)
* fix: 24 character limit on first & last name in onboarding page

* fix: no option: 'Add Issue' in archive issue page

* fix: in archive issue directly sending to issue detail page

* fix: issue type showing in archive issue

* fix: custom menu overflowing

* fix: changing subscriber in filters has no effect

* style: border in quick-add

* fix: on onboarding member role overflowing

* fix: inconsistent icons in issue detail

* style: spacing, borders and shadows in quick-add

* fix: custom menu truncate
2023-09-28 14:02:03 +05:30
Anmol Singh Bhatia
60a69e28e3 fix: issue activity estimate value bug fix (#2281)
* fix: issue activity estimate value bug fix

* fix: activity typo fix
2023-09-28 13:18:35 +05:30
Aaryan Khandelwal
34af666b5f chore: fetch issues from previous and next month in the calendar view (#2282) 2023-09-28 13:17:46 +05:30
Nikhil
6afbd3f1ba chore: views (#2288)
* chore: global views order by

* chore: update permissions for global views

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2023-09-28 13:16:31 +05:30
Nikhil
32d2f912f7 fix: inbox issue deletes (#2290) 2023-09-28 13:14:37 +05:30
Bavisetti Narayan
9dd22f07f4 chore: removed project filter (#2284) 2023-09-27 19:16:22 +05:30
Bavisetti Narayan
7404fe71b1 chore: sort order and issue props for global views (#2283) 2023-09-27 17:30:52 +05:30
sriram veeraghanta
dc2b4de95e Merge pull request #2265 from makeplane/stage/dev-release-0-13
promote: Develop to Stage
2023-09-27 15:16:06 +05:30
sriram veeraghanta
62ba8d5e9f Merge branch 'develop' of github.com:makeplane/plane into stage/dev-release-0-13 2023-09-27 15:08:15 +05:30
Nikhil
7b453dd6b5 chore: make target dates inclusive when filtering (#2276) 2023-09-27 15:06:23 +05:30
Bavisetti Narayan
191aecaaac chore: updated created at in draft issue (#2278) 2023-09-27 15:05:49 +05:30
Dakshesh Jain
e00ae0b48a style: calender quick-add same width as single date (#2280)
* style: calender quick-add same width as single date

* style: margin bottom in quick-add in spreadsheet view

* fix: quick add opening in list-layout

* style: reduced margin left
2023-09-27 15:02:35 +05:30
Aaryan Khandelwal
a243bb6a15 chore: gantt chart empty state (#2279)
* chore: gantt empty state

* chore: Add heading to the gantt sidebar
2023-09-27 14:53:26 +05:30
Aaryan Khandelwal
b3be363b00 chore: handle calendar date range in frontend (#2277) 2023-09-27 14:41:32 +05:30
Aaryan Khandelwal
5298f1e53c fix: block click happening while moving (#2275) 2023-09-27 13:08:35 +05:30
Dakshesh Jain
2d8cbccfbc style: gantt layout quick-add padding (#2272)
* fix: 'Last Drafted Issue' making sidebar look weird on collapsed

* feat: scroll to the bottom when issue is created

* fix: 'Add Issue' button overlapping issue card in spreadsheet view

* fix: wrong placement of quick-add in calender layout

* fix: spacing for issue card in spreadsheet view

* style: gantt layout quick-add padding

style: removed 'State group' from draft issue

* style: decrese shadow, quick-add position on calender layout, and 'add issue' sticky

* style: button color
2023-09-27 08:51:29 +05:30
Anmol Singh Bhatia
3a6d72e4b6 feat: workspace global view, style: spreadsheet view revamp (#2273)
* chore: workspace view types, services and hooks added

* style: spreadsheet view revamp and code refactor

* feat: workspace view

* fix: build fix

* chore: sidebar workspace issues redirection updated
2023-09-26 19:56:59 +05:30
sriramveeraghanta
698b42768e Merge branch 'develop' of github.com:makeplane/plane into stage/dev-release-0-13 2023-09-26 19:49:44 +05:30
Aaryan Khandelwal
a187e7765c fix: user dashboard greeting timezone (#2267)
* chore: user greeting timezone

* fix: group by labels not working on workspace level
2023-09-26 18:08:01 +05:30
Thomas
4c333d5767 chore: add instructions to contributing guide (#2270)
* chore: add instructions to contributing guide

* dev: update contributing.md to use the new configuration

---------

Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
2023-09-26 18:06:48 +05:30
Dakshesh Jain
b317a14983 fix: bugs in quick-add and draft issues (#2269)
* fix: 'Last Drafted Issue' making sidebar look weird on collapsed

* feat: scroll to the bottom when issue is created

* fix: 'Add Issue' button overlapping issue card in spreadsheet view

* fix: wrong placement of quick-add in calender layout

* fix: spacing for issue card in spreadsheet view
2023-09-26 17:35:51 +05:30
Bavisetti Narayan
6e0999c35a dev: re-split migrations into two different files (#2268)
* dev: split issue activity migration separate files

* dev: resplit migrations into two different files

* dev: changed the batch size
2023-09-26 16:25:52 +05:30
Bavisetti Narayan
52b57b1e37 dev: migration for 0.13 (#2266)
* dev: updated migrations

* dev: migration for 0.13
2023-09-26 14:18:06 +05:30
Henit Chobisa
88a35efa06 [fix] nginx continuously rewriting and reloading on index page of spaces app (#2236)
* chore: shifted index page to /home route

* chore: added rewrite logic, to rewrite index to /home

* chore: routed home to login route as login page

* chore: updated nginx config to route to login

* chore: updated path for home
2023-09-26 13:46:38 +05:30
sriramveeraghanta
ab028a317b chore: dev merge fixes 2023-09-26 13:32:13 +05:30
Nikhil
d38594376b fix: n+1 queries for cycle list and project member endpoints (#2257) 2023-09-26 13:11:23 +05:30
Nikhil
dae8ca6053 fix: issue automation iterable error (#2208) 2023-09-26 13:11:00 +05:30
Aaryan Khandelwal
6d3bd78052 chore: add tooltip to show full time on activity logs (#2235) 2023-09-26 13:10:28 +05:30
guru_sainath
1ad99873a9 feat: Add peek overview in sub issues and updated UI for empty states. (#2263) 2023-09-26 13:09:08 +05:30
Dakshesh Jain
7db78594dc fix: draft issue delete not working (#2249)
* fix: draft issue not deleting, project can't be changed in draft issue modal

* fix: removed mutation for view where draft issues are not shown

* fix: inline create issue for draft issue

* fix: clearing data from localstorage on discard click
2023-09-25 19:11:10 +05:30
Dakshesh Jain
5e8d523ed4 feat: quick-add placement in spreadsheet and gantt (#2259)
* feat: sticking quick-add at the bottom of the screen

fix: opening create issue modal instead of quick-add in draft-issues, my-issue and profile page

* fix: build error due to dynamic import
2023-09-25 19:08:26 +05:30
Anmol Singh Bhatia
de7a672b79 fix: bug fixes and ui improvement (#2250) 2023-09-25 16:15:49 +05:30
Rhea Jain
0e96eddb57 rename view to layout (#2255)
Co-authored-by: Your Name <you@example.com>
2023-09-25 13:38:49 +05:30
Anmol Singh Bhatia
afa10d7195 fix: sub issue state and member select build error (#2254) 2023-09-25 13:18:03 +05:30
Anmol Singh Bhatia
68c8741f93 fix: bug fix related to fetching dropdown options for the profile issue (#2246) 2023-09-25 12:18:35 +05:30
Bavisetti Narayan
e8d303dd10 chore: changed priority props in workspace and project (#2253) 2023-09-22 19:48:07 +05:30
Anmol Singh Bhatia
c9a6380636 style: settings page improvement (#2211)
* style: settings page improvement

* style: toggle switch styling

---------

Co-authored-by: Anmol Singh Bhatia <asb@Anmols-MacBook-Pro.local>
2023-09-22 18:47:10 +05:30
guru_sainath
1aadbee7e2 fix: resolved pending issue graph in analytics, user wishes in dashboard, and typo in projects list (#2247) 2023-09-22 17:43:23 +05:30
Bavisetti Narayan
02060f654c chore: added epoch in draft (#2244)
* chore: added epoch in draft

* chore: removed extra spaces
2023-09-22 16:32:53 +05:30
Dakshesh Jain
771ca585db feat: quick add (#2240)
* feat: quick add

* style: made text color muted
2023-09-22 15:31:54 +05:30
Nikhil
daa0b16960 fix: cycle and module stats when issues are archived (#2185)
* fix: cycle and module stats when issues are archived

* fix: added draft filter

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2023-09-22 15:17:31 +05:30
Bavisetti Narayan
0005ff5f99 fix: changed priority from None to none (#2229) 2023-09-22 14:44:53 +05:30
Bavisetti Narayan
0c7b7c4e94 chore: added state and priority order in workspace user profile (#2241) 2023-09-22 14:43:55 +05:30
Nikhil
4d835c5b4a chore: updated docker naming conventions (#2239)
* naming convention changes

* dev: update docker-compose-hub in consistent with docker-compose

* dev: updated docker container name

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
2023-09-22 13:21:55 +05:30
Bavisetti Narayan
c7092edb61 fix: aws region name (#2234) 2023-09-22 13:00:13 +05:30
guru_sainath
73afb8f4d8 fix: issues resolved in sub issues (#2238) 2023-09-21 19:12:20 +05:30
Aaryan Khandelwal
978909c021 fix: profile issues layout switch (#2228) 2023-09-21 16:04:57 +05:30
Aaryan Khandelwal
de9f34cac3 fix: activity label color (#2227) 2023-09-21 16:04:05 +05:30
Aaryan Khandelwal
e3793f4464 fix: handle no issues in custom analytics (#2226) 2023-09-21 16:03:33 +05:30
Aaryan Khandelwal
1621125f6d refactor: product updates modal layout (#2225) 2023-09-21 16:03:06 +05:30
guru_sainath
bd077e6500 Implemented nested issues in the sub issues section in issue detail page (#2233)
* feat: subissues infinte level

* feat: updated UI for sub issues

* feat: subissues new ui and nested sub issues in issue detail

* chore: removed repeated code
2023-09-21 15:39:45 +05:30
Bavisetti Narayan
60ae940d40 chore: sub issues count in individual issue (#2221) 2023-09-20 17:00:03 +05:30
Dakshesh Jain
cdfff12f4f fix: fields not getting selected in the create issue form (#2212)
* fix: hydration error and draft issue workflow

* fix: build error

* fix: properties getting de-selected after create, module & cycle not getting auto-select on the form

* fix: display layout, props being updated directly
2023-09-20 13:06:51 +05:30
Anmol Singh Bhatia
e01a0d20fe chore: dynamic position dropdown (#2138)
* chore: dynamic position state dropdown for issue view

* style: state select dropdown styling

* fix: state icon attribute names

* chore: state select dynamic dropdown

* chore: member select dynamic dropdown

* chore: label select dynamic dropdown

* chore: priority select dynamic dropdown

* chore: label select dropdown improvement

* refactor: state dropdown location

* chore: dropdown improvement and code refactor

* chore: dynamic dropdown hook type added

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-09-20 12:24:52 +05:30
Bavisetti Narayan
63c4792e70 fix: changed time to timestamp (#2217) 2023-09-19 21:36:39 +05:30
Bavisetti Narayan
ce562fa3ea fix: migration files (#2215) 2023-09-19 20:15:02 +05:30
Bavisetti Narayan
a6a0eb9774 chore: added epoch in issue activity (#2187) 2023-09-19 19:46:57 +05:30
Bavisetti Narayan
d603c1e8f0 fix: tracking logs for issue activity (#2213) 2023-09-19 19:46:03 +05:30
Bavisetti Narayan
405ef9314f feat: workspace views (#2005)
* feat: workspace views

* fix: added project member filter

* fix: added pagination in workspace views

* fix: filters and group up by for workspace issues

* fix: changed name workspace view to global view

* fix: reordered the urls
2023-09-19 19:45:37 +05:30
Nikhil
926d2ae0a0 dev: self hosted settings file (#2202)
* dev: self hosted settings file

* dev: add analytics and dockerized variable in settings

* dev: update .env.example and docker compose file also

* dev: self hosted setup minio
2023-09-19 18:30:56 +05:30
M. Palanikannan
11258686ad [fix]: Removing dependency on tiptap pro extension (#2209)
* removing dependency on tiptap pro extension

* updated docs to remove tiptap pro setup instructions

* chore: removed pro extension promt from setup.sh

* chore: Removed Pro Extension Setup from CI

---------

Co-authored-by: Henit Chobisa <chobisa.henit@gmail.com>
2023-09-19 16:44:12 +05:30
Dakshesh Jain
f6b92fc953 fix: activity not coming for blocking/blocked, 'related to' and duplicate (#2189)
* fix: activity not coming for duplicate, relatesd to and for blocked/blocking

refactor: mutation logic to use relation id instead of issue id

* fix: mutation logic and changed keys to be aligned with api

* fix: build error
2023-09-19 12:58:00 +05:30
Dakshesh Jain
79bf7d4c0c fix: hydration error and draft issue workflow (#2199)
* fix: hydration error and draft issue workflow

* fix: build error
2023-09-19 12:56:32 +05:30
Anmol Singh Bhatia
5d331477ef chore: settings bug fixes and ui improvement (#2198)
* fix: settings bug fixes and ui improvement

* chore: setting sidebar scroll fix & code refactor
2023-09-15 19:30:53 +05:30
sriram veeraghanta
3d72279edb Merge pull request #2196 from makeplane/fix/bug_fix
fix: document bug fix
2023-09-15 15:42:43 +05:30
Anmol Singh Bhatia
c107b36d34 fix: document bug fix 2023-09-15 15:41:10 +05:30
Anmol Singh Bhatia
ccffbe1b4e style: workspace and profile setting revamp (#2193)
* chore: custom theme mode svg added

* style: workspace settings ui revamp

* style: project settings and image upload modal improvement

* style: profile setting ui revamp

* chore: settings ui improvement and bug fixes
2023-09-15 15:03:32 +05:30
Bavisetti Narayan
9bfdcff44d chore: changed old values (#2194) 2023-09-15 14:18:30 +05:30
Bavisetti Narayan
b274a21ca5 chore: changed issue relation history logs (#2192)
* chore: changed issue relation history logs

* chore: change field name
2023-09-15 13:12:28 +05:30
Dakshesh Jain
32d945be0d fix: edit/delete for draft issue (#2190)
* fix: edit/delete

* fix: build issue

* fix: draft issue modal opening in kanban card
2023-09-15 12:51:10 +05:30
Dakshesh Jain
eda4da8aed feat: draft issues (#2188)
* feat: draft issue

issues can be saved as draft

* style: modal position
2023-09-14 18:38:31 +05:30
sriram veeraghanta
759a604cb8 fix: posthog integration (#2186) 2023-09-14 16:38:41 +05:30
sriram veeraghanta
6659cfc8b0 fix: track events issue and env variables fixes (#2184)
* fix: track event fixes

* fix: adding env variables to trubo
2023-09-14 16:05:31 +05:30
Bavisetti Narayan
a53b428bbd chore: endpoints and history logs for issue draft (#2180)
* chore: history logs for issue draft

* fix: created seperated endpoints for issue drafts

* fix: fixed the typo
2023-09-14 15:38:11 +05:30
Bavisetti Narayan
4e0e02522f fix: changed payload for issue subgroups (#2181)
* fix: sub groups in cycle module and my issues

* fix: changed payload for issue subgroups
2023-09-14 15:29:35 +05:30
sriram veeraghanta
f983d787b4 env and docker fixes (#2182) 2023-09-14 12:26:07 +05:30
Anmol Singh Bhatia
87abf3ccb1 style: project setting ui revamp (#2177)
* style: project settings navigation sidebar added

* chore: emoji and image picker close on outside click added

* style: project setting general page revamp

* style: project setting member page revamp

* style: project setting features page revamp

* style: project setting state page revamp

* style: project setting integrations page revamp

* style: project setting estimates page revamp

* style: project setting automation page revamp

* style: project setting label page revamp

* chore: member select improvement for member setting page

* chore: toggle switch component improvement

* style: project automation setting ui improvement

* style: module icon added

* style: toggle switch improvement

* style: ui and spacing consistency

* style: project label setting revamp

* style: project state setting ui improvement

* chore: integration setting repo select validation

* chore: code refactor

* fix: build fix
2023-09-13 23:09:55 +05:30
Henit Chobisa
d0f6ca3bac [chore] Update setup.sh, with removed replacement script & added project-level ENVs (#2115)
* chore: Updated Setup Script for Splitting Env File

* chore: updated dockerfile for using inproject env varaibles

* chore: removed husky replacement script

* chore: updated shell script using sed

* chore: updated dockerfiles with removed cp statement

* chore: added example env for apiserver

* chore: refactored secret generation for backend

* chore: removed replacement script

* chore: updated docker-compose with removed env variables

* chore: resolved comments in setup.sh and docker-compose

* chore: removed secret key placeholder in apiserver example env

* chore: updated root env for project less env variables

* chore: removed project level env update from root env logic

* chore: updated API_BASE_URL in .env.example

* chore: restored docker argument as env NEXT_PUBLIC_API_BASE_URL

* chore: added pg missing env variables

* [chore] Updated web and deploy backend configuration for reverse proxy & decoupled Plane Deploy URL generation for web (#2135)

* chore: removed api url build arg from compose

* chore: set public api default argument to black string for self hosted

* chore: updated web services to accept blank string as API URL

* chore: added env variables for pg compose service

* chore: modified space app services to use accept empty string as api base

* chore: conditionally trigger web url value based on argument

* fix: made web to use identical host with spaces suffix on absense of Deploy URL for deploy

* chore: added example env for PUBLIC_DEPLOY Env

* chore: updated web dockerfile with addition as PLANE_DEPLOY Argument

* API BASE URL global update

* API BASE URL replace with api server

* api base url fixes

* typo  fixes

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>

* dev: remove API_BASE_URL from environment variable

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2023-09-13 20:21:02 +05:30
Ankush Deshmukh
af73bbe718 typo: changed customize to customise in project automation settings (#2153)
Co-authored-by: Neo <neo@Neos-MacBook-Pro.local>
2023-09-13 20:15:48 +05:30
Bavisetti Narayan
9033ceb03c fix: sub groups in cycle module and my issues (#2176) 2023-09-13 19:50:34 +05:30
Dakshesh Jain
9bac7cb036 feat: issue link to create relation between issues (#2171)
* feat: issue linking

* fix: search params to filter out selected issue

* style: changed icons

* fix: build error on web-view

* fix: build error

* fix: build error on web-view component
2023-09-13 19:41:11 +05:30
Anmol Singh Bhatia
32d08570e7 chore: peek overview for issue view and my issue view (#2172)
* chore: peak overview for issue view and my issue view

* fix: profile issue peak overview mutation fix

* chore: code refactor

* fix: image prefix url fix
2023-09-13 19:33:58 +05:30
Bavisetti Narayan
1b1ed37405 chore: changed default props for worskpace and project members (#2175) 2023-09-13 19:13:31 +05:30
Bavisetti Narayan
42d38f7531 feat: changed payload for swimlanes (#2173) 2023-09-13 18:25:57 +05:30
Bavisetti Narayan
61672f47ac fix: migration files (#2169) 2023-09-13 13:23:40 +05:30
Dakshesh Jain
23e62c83eb refactor: switched priority null -> 'none' (#2166) 2023-09-13 13:22:31 +05:30
sriram veeraghanta
e58b76c8a6 fix: tailwind common config (#2168) 2023-09-13 12:50:04 +05:30
Anmol Singh Bhatia
4ce01ca4f8 fix: calendar issues display filters loop fix (#2167) 2023-09-13 12:37:58 +05:30
Bavisetti Narayan
a34b0b059d feat: add a relation to an issue (#1995)
* feat: add issue relation to an issue

* fix: deleted the migration file

* fix: changed link to relates to in choice fields

* fix: added the migration file

* fix: changed migration file

* fix: project id issue fixed

* fix: added issue in the payload

* fix: changed the query param for blocker
2023-09-13 12:25:10 +05:30
Bavisetti Narayan
164e0b9301 chore: changed view props (#2146)
* chore: changed view props

* fix: changed the keywords
2023-09-13 12:12:21 +05:30
Bavisetti Narayan
5a91031243 feat: issue drafts (#2161) 2023-09-13 12:10:22 +05:30
Bavisetti Narayan
47bec7704b chore: priority migration (#2162) 2023-09-13 12:06:38 +05:30
sriram veeraghanta
b9c935092a chore: eslint config package fixes (#2165)
* eslint fixes

* lint rules added
2023-09-13 12:06:17 +05:30
Aaryan Khandelwal
3a2a329000 fix: view props undefined (#2160) 2023-09-12 22:51:13 +05:30
Aaryan Khandelwal
8e9a4dca78 refactor: view props structure (#2159)
* chore: update view_props types

* refactor: view props structure
2023-09-12 22:27:15 +05:30
sriram veeraghanta
2bc05cc7b7 Merge pull request #2157 from makeplane/stage-release
release: self hosting fixes
2023-09-12 21:50:34 +05:30
sriram veeraghanta
14fe545709 Merge pull request #2156 from makeplane/stage/self-hosted-fixes
fix: selfhosted fixes
2023-09-12 21:06:01 +05:30
sriram veeraghanta
bc99ec0f1d fix: selfhosted fixes (#2154)
* fix: selfhosted fixes

* fix: updated env example
2023-09-12 21:03:42 +05:30
sriram veeraghanta
cdb888c23e fix: selfhosted fixes (#2154)
* fix: selfhosted fixes

* fix: updated env example
2023-09-12 20:32:26 +05:30
Dakshesh Jain
2186db8bba feat: users can select timezone during onboarding (#2148)
feat: using Intl timezone will be automatically selected but they have the option to change it
2023-09-12 13:35:15 +05:30
Bavisetti Narayan
9bff10de6d chore: changed issue priority from NULL to none (#2142)
* chore: changed issue priority from NULL to none

* fix: deleted the migration file
2023-09-12 13:06:49 +05:30
sriram veeraghanta
cc63f67654 Merge pull request #2143 from makeplane/stage-release
promote: stage-release to master
2023-09-11 18:21:51 +05:30
sriram veeraghanta
b8dd9ca729 Merge pull request #2144 from makeplane/develop
promote: develop to stage release
2023-09-11 18:11:30 +05:30
Henit Chobisa
6867154963 chore: added pre-release tag for workflow publications (#2133)
* chore: added pre-release tag for workflow publications

* chore: added backend services under a single image

* chore: exposed backend port for compose hub

* chore: removed backend exposed ports
2023-09-11 18:02:56 +05:30
Nikhil
73b360c2fd Merge pull request #2140 from makeplane/develop
promote: develop to stage-release
2023-09-11 14:39:11 +05:30
Aaryan Khandelwal
7bb73b74ba refactor: priority icon component (#2132) 2023-09-11 14:35:58 +05:30
Dakshesh Jain
991258084e fix: query checking (#2137)
fix: the logic should be to check if object exist not if it's true or false
2023-09-11 13:21:50 +05:30
Thomas
1a37668f0b fix: husky was removed in commit #2086, but prepare still uses it (#2128) 2023-09-11 13:05:09 +05:30
M. Palanikannan
4447a4b519 fix: Tiptap comment card fix for space (#2129)
* fix:(space) fixed comment card's editor integration

* regression: removed content being set twice

* chore: added controller to manage tiptap editor

* chore: remove unused functions

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-09-11 12:54:19 +05:30
Dakshesh Jain
7842c4b2ea fix: authorize editor (#2122) 2023-09-11 12:24:46 +05:30
Aaryan Khandelwal
8de93d0081 chore: remove getServerSideProps (#2130) 2023-09-11 12:13:00 +05:30
Aaryan Khandelwal
5b228bd1eb chore: update state icons and colors (#2126)
* chore: update state icons and colors

* chore: update icons
2023-09-11 11:45:28 +05:30
Dakshesh Jain
ad8a011bb9 fix: issue activity (#2127) 2023-09-11 11:44:16 +05:30
Aaryan Khandelwal
49d0b3f4a1 fix: handleClose function of the export modal (#2124) 2023-09-08 13:29:06 +05:30
Aaryan Khandelwal
1872dff00d fix: custom date filter not working on my issues and profile issues (#2123) 2023-09-08 13:28:32 +05:30
Dakshesh Jain
faa6a2bcbc feat: select blocker, blocking, and parent (#2121)
* feat: update, delete link

refactor: using old fetch-key

* feat: issue activity with ability to view & add comment

feat: click on view more to view more options in the issue detail

* fix: upload image not working on mobile

* feat: select blocker, blocking, and parent

dev: auth layout for web-view, console.log callback for web-view

* style: made design consistant

* fix: displaying page only on web-view

* style: removed overflow hidden
2023-09-07 18:42:24 +05:30
sriram veeraghanta
6d52707ff5 editor fixes for space (#2119) 2023-09-07 15:09:16 +05:30
Nikhil
8ba482bc9c chore: response status for project views update (#2111)
* chore: response status for project views update

* dev: remove 200 OK response from empty contents
2023-09-07 14:49:45 +05:30
Aaryan Khandelwal
5989f2476a fix: update plane logo (#2118) 2023-09-07 13:41:29 +05:30
Aaryan Khandelwal
8ea6dd4e84 fix: onboarding role select dropdown text color (#2117) 2023-09-07 13:40:50 +05:30
Nikhil
39bc975994 fix: remove triage issue status from public boards (#2110) 2023-09-07 13:21:58 +05:30
Nikhil
866eead35f fix: issue comment ordering for public boards (#2108) 2023-09-07 13:21:05 +05:30
Nikhil
9c3510851d dev: update python packages (#2095) 2023-09-07 13:20:32 +05:30
Aaryan Khandelwal
81436902a3 chore: option to switch access of a comment (#2116) 2023-09-07 12:54:30 +05:30
Aaryan Khandelwal
d26aa1b2da chore: render proper icons for due dates (#2114) 2023-09-07 12:53:49 +05:30
M. Palanikannan
b47c7d363f fix: Improved Image Deletion Logic, Image ID Issue in Modals and Performance Optimization in Editor (#2092)
* added improved delete logic in modals

* added better ts support

* impoved complexity to O(1) from O(n) for large docs

* regression: removed ts nocheck
2023-09-07 12:22:02 +05:30
Aaryan Khandelwal
85f797058d fix: edit issue comment mutation (#2109) 2023-09-06 19:02:59 +05:30
Dakshesh Jain
1655d0cb1c feat: view, create, update and delete comment (#2106)
* feat: update, delete link

refactor: using old fetch-key

* feat: issue activity with ability to view & add comment

feat: click on view more to view more options in the issue detail

* fix: upload image not working on mobile
2023-09-06 17:08:19 +05:30
Anmol Singh Bhatia
58562dc4b7 fix: ui improvement and bug fixes (#2105)
* chore: workspace level typo fix

* fix: setting opacity fix
2023-09-06 16:15:21 +05:30
Nikhil
2ad46d7bfa fix: public issue list endpoint n+1 (#2099) 2023-09-06 16:04:12 +05:30
Nikhil
4f0cac37db fix: issue object for filtering (#2102) 2023-09-06 16:03:41 +05:30
sriram veeraghanta
b46a7481ae Merge pull request #2101 from makeplane/fix/gantt_issues
fix: don't render invalid dated blocks on the gantt chart
2023-09-06 15:00:03 +05:30
sriram veeraghanta
f11ae00201 Merge pull request #2100 from makeplane/feat/comment_reactions
feat: plane space comment reactions
2023-09-06 14:52:55 +05:30
Aaryan Khandelwal
c5612ee7a3 fix: don't render invalid dated cycles and modules 2023-09-06 12:26:51 +05:30
Aaryan Khandelwal
0dd336aec8 fix: don't render invalid dated issues 2023-09-06 12:25:34 +05:30
sriram veeraghanta
4b364f72b5 Merge pull request #2096 from makeplane/fix/login_redirection
fix: redirection after signing in on space
2023-09-06 12:21:08 +05:30
Aaryan Khandelwal
6d13332818 style: add shadow to reaction selector 2023-09-06 12:17:47 +05:30
Aaryan Khandelwal
ac4127c93d chore: add tooltip for user info 2023-09-06 12:04:18 +05:30
Aaryan Khandelwal
60c3d1a6e9 feat: comment reactions 2023-09-06 11:59:57 +05:30
sriram veeraghanta
70ed3c1fdf Merge pull request #2097 from makeplane/feat/issue_detail_for_webview
feat: issue detail for web-view
2023-09-05 17:56:33 +05:30
dakshesh14
b40059ea21 feat: add links and permission to perform actions
refactor: divided file into components
2023-09-05 17:06:17 +05:30
Bavisetti Narayan
90276073cd fix: validation in automation task (#2094) 2023-09-05 16:53:53 +05:30
Aaryan Khandelwal
8d5ff1a628 fix: redirection after signing in on space 2023-09-05 16:12:17 +05:30
dakshesh14
065a4a3cf7 feat: issue detail for web view 2023-09-05 14:42:34 +05:30
MengYX
928ae775f4 fix: replace Completion with ChatCompletion to use gpt-3.5-turbo model (#2066)
According to https://platform.openai.com/docs/guides/gpt/chat-completions-vs-completions , GPT-3.5 Turbo & GPT-4 is not working on **Legacy** Completions API
2023-09-05 13:11:31 +05:30
sriram veeraghanta
80bcca71ff Merge pull request #2091 from makeplane/stage-release
promote: stage release to master
2023-09-04 19:14:29 +05:30
sriram veeraghanta
3db0ec819a Merge pull request #2090 from makeplane/develop
Promote: Develop to Stage Release
2023-09-04 18:53:41 +05:30
Aaryan Khandelwal
900a4fcb0e fix: profile time according to the user timezone (#2089) 2023-09-04 18:48:33 +05:30
Nikhil
19c65b26d6 dev: docker environment deploy fixes (#2087)
* chore: updated space and web dockerfiles

* chore: updated compose file params

* updated nextjs config for basepath

* chore: updated package.json with new packages

* chore: modified space and web dockerfiles

* dev: update deploy configuration for deploy images

* dev: update docker folder for web

* dev: add semi colon for module exports

---------

Co-authored-by: Henit Chobisa <chobisa.henit@gmail.com>
2023-09-04 18:46:10 +05:30
Anmol Singh Bhatia
71394d3316 chore: add issue option removed from subscribed issue page (#2088)
* chore: condition for subscribed page add issue option

* chore: condition for subscribed page add issue option
2023-09-04 18:42:31 +05:30
sriram veeraghanta
414ea7371d Merge pull request #2085 from makeplane/develop
Promote: Develop to Stage Release
2023-09-04 18:16:47 +05:30
sriram veeraghanta
9423472838 Env Fixes (#2086)
* fixing env issues

* removing husky
2023-09-04 18:03:31 +05:30
sriram veeraghanta
729eabdd3f next config fixes in space app (#2084) 2023-09-04 17:55:40 +05:30
Aaryan Khandelwal
03f204a71c chore: invalid url content (#2082) 2023-09-04 17:27:29 +05:30
guru_sainath
faf5a274cb fix: mutation latency in sidebar projects when user leaves the project (#2083)
* fix: mutation latency in sidebar projects when user leaves the project

* chore: remove console
2023-09-04 17:24:52 +05:30
Aaryan Khandelwal
2c9c8d5a89 feat: landing page after logging in (#2081) 2023-09-04 16:55:43 +05:30
Aaryan Khandelwal
5e02ad8104 fix: project invite modal members filter function (#2080) 2023-09-04 16:35:28 +05:30
Aaryan Khandelwal
f554ad95e9 fix: favicon path on Plane space (#2077)
* fix: favicon path

* chore: add webmanifest file

* favicon fixes with nginx

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
2023-09-04 16:34:53 +05:30
Aaryan Khandelwal
59b69d3072 chore: add the env example files (#2078) 2023-09-04 15:59:51 +05:30
guru_sainath
ccbb54bb87 feat: Leaving from project for viewer and guest roles has implemented (#2079)
* feat: leave project services and components

* feat: Leaving from project for viewer and guest roles has implemented

---------

Co-authored-by: dakshesh14 <dakshesh.jain14@gmail.com>
2023-09-04 15:53:46 +05:30
sriram veeraghanta
2b84b7c18d Merge pull request #2076 from makeplane/develop
Promote: Develop to Stage Release
2023-09-04 14:48:53 +05:30
Aaryan Khandelwal
8f46492c42 fix: copy link button not working on the peek overview (#2075)
* fix: copy issue link from the peek overview

* refactor: peek overview layout
2023-09-04 14:47:28 +05:30
Nikhil
58e23304a7 fix: state ordering for projects (#2073) 2023-09-04 14:38:39 +05:30
Nikhil
dc26e1ea50 chore: cycle update errors (#2070) 2023-09-04 14:37:29 +05:30
Aaryan Khandelwal
f583789584 chore: add authorization to the gantt chart (#2074) 2023-09-04 13:08:49 +05:30
Aaryan Khandelwal
9d9c1a86bf fix: state group icon (#2072) 2023-09-04 13:02:47 +05:30
Aaryan Khandelwal
4559a1bd5d refactor: publish project store (#2068) 2023-09-04 12:34:12 +05:30
sriram veeraghanta
0de62b3b0c removing gitpod config (#2071) 2023-09-04 12:08:58 +05:30
sriram veeraghanta
d3a9a764dc fix: space redirections (#2069) 2023-09-04 01:50:49 +05:30
sriram veeraghanta
4ea52302ba fixing vercel deployments by switching next config using env (#2067) 2023-09-03 20:55:37 +05:30
sriram veeraghanta
1e152c666c New Directory Setup (#2065)
* chore: moved app & space from apps to root

* chore: modified workspace configuration

* chore: modified dockerfiles for space and web

* chore: modified icons for space

* feat: updated files for new svg icons supported by next-images

* chore: added /spaces base path for next

* chore: added compose config for space

* chore: updated husky configuration

* chore: updated workflows for new configuration

* chore: changed app name to web

* fix: resolved build errors with web

* chore: reset file tracing root for both projects

* chore: added nginx config for deploy

* fix: eslint and tsconfig settings for space app

* husky setup fixes based on new dir

* eslint fixes

* prettier formatting

---------

Co-authored-by: Henit Chobisa <chobisa.henit@gmail.com>
2023-09-03 18:50:30 +05:30
Aaryan Khandelwal
20e36194b4 fix: peek overview layout switch (#2064) 2023-09-03 11:25:37 +05:30
Nikhil
874d6e951b dev: updated error handling for project deploy board attributes (#2062)
* dev: updated error handling for project deploy board attributes

* dev: reaction integrity handling
2023-09-02 19:43:17 +05:30
Henit Chobisa
63d799310b [chore] Added Husky for Automating Building and Linting Projects Before Push (#2032)
* chore: Added Husky as Root Dependency

* chore: Added Husky Prepush Script

* chore: Modified Husky Pre-Push Script to Conditionally Build Projects

* chore: added husky as dev dependency
2023-09-02 13:47:21 +05:30
M. Palanikannan
abe8df4eca added table-icons for left,right columns and top,bottom rows (#2061) 2023-09-02 00:45:34 +05:30
sriram veeraghanta
674347c99e Merge pull request #2060 from makeplane/develop
Promote: Develop to Stage Release
2023-09-01 20:56:31 +05:30
Aaryan Khandelwal
0196fee7e3 fix: sidebar cycle and module select (#2056) 2023-09-01 20:54:14 +05:30
sriram veeraghanta
c1102180e6 Merge pull request #2059 from makeplane/develop
Promote: Develop to Stage Release
2023-09-01 20:53:35 +05:30
sriram veeraghanta
a6cd0809fa Merge pull request #2058 from makeplane/dev-deploy-fixes
fix: speeding up reactions and votes 🚀
2023-09-01 20:52:42 +05:30
sriram veeraghanta
2155a336ed peekover mutation fixes 2023-09-01 20:52:12 +05:30
sriram veeraghanta
1732945ec6 fix: speeding up reactions and votes 🚀 2023-09-01 20:38:53 +05:30
Nikhil
71c8f79276 fix: issue vote constraints (#2057) 2023-09-01 18:46:38 +05:30
sriram veeraghanta
650c0c3b78 promote: develop to stage-release (#2045)
promote: develop to stage-release
2023-09-01 17:23:26 +05:30
Aaryan Khandelwal
f71a62f142 style: sign in page bg color (#2055) 2023-09-01 17:21:52 +05:30
Aaryan Khandelwal
54d781ef91 fix: auth screens (#2054) 2023-09-01 17:10:06 +05:30
Anmol Singh Bhatia
441e83eba6 fix: notification count mutation fix (#2053) 2023-09-01 17:08:02 +05:30
Anmol Singh Bhatia
74bf9062b4 chore: bug fixes and ui/ux enhancements (#2036) 2023-09-01 16:52:44 +05:30
sriram veeraghanta
8a95a41100 feat: Converting space app to pages dir (#2052)
Co-authored-by: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Bavisetti Narayan <narayan@Bavisettis-MacBook-Pro.local>
Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: M. Palanikannan <73993394+Palanikannan1437@users.noreply.github.com>
Co-authored-by: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com>
Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
2023-09-01 16:42:30 +05:30
Nikhil
c03550656a chore: vote actor details (#2047)
* chore: vote actor details

* dev: add field in serializer

* dev: remove _id in workspace and project
2023-09-01 15:58:25 +05:30
Nikhil
82a48d4805 chore: reaction serializers (#2046)
* dev: chore reaction serializers

* fix: remove issue reaction lite serializer
2023-09-01 15:55:21 +05:30
Nikhil
f4fa2e011a feat: leave project and workspace endpoint (#2042)
* feat: leave project and workspace endpoint

* fix: argument error

* dev: update endpoint status
2023-09-01 15:55:06 +05:30
Kritika Upadhyay
42ece0d784 chore: updates project invite placeholder (#2049) 2023-09-01 15:37:27 +05:30
Bavisetti Narayan
1e9f0823f8 fix: imported uuid (#2048) 2023-09-01 14:41:20 +05:30
Aaryan Khandelwal
4ba3ef5c24 fix: peek overview bugs (#2043)
* fix: side peek modal shaking

* refactor: peek overview layout

* fix: date selector, activity mutation

* fix: delete issue handler

* fix: assignees mutation
2023-09-01 13:52:55 +05:30
Nikhil
c6d9ace6a2 dev: migrations for v0.12 release (#2044) 2023-09-01 13:20:52 +05:30
Aaryan Khandelwal
0d4bcd2758 fix: Gantt chart bugs (#2024)
* fix: only left mouse button should trigger all the events

* fix: extra block shadow
2023-09-01 11:23:43 +05:30
Nikhil
3a0d96a48d chore: cycle endpoint to return display name as well in the assignee distribution (#2041)
* chore: cycle endpoint to return display name as well in the assignee distribution

* fix: value error
2023-09-01 11:21:34 +05:30
Lakhan Baheti
eab1d9329b feat: editor for issue description (#2038) 2023-09-01 10:59:17 +05:30
Nikhil
099bce87b5 chore: public board endpoints (#2030) 2023-09-01 00:08:40 +05:30
Nikhil
b496a62540 fix: subscribed issues are filtering (#2037) 2023-08-31 19:07:56 +05:30
Aaryan Khandelwal
af929ab741 style: tiptap table (#2033) 2023-08-31 16:30:28 +05:30
M. Palanikannan
38b7f4382f [feat]: Tiptap table integration (#2008)
* added basic table support

* fixed table position at bottom

* fixed image node deletion logic's regression issue

* added compatible styles

* enabled slash commands

* disabled slash command and bubble menu's node selector for table cells

* added dropcursor support to type below the table/image

* blocked image uploads for handledrop and paste actions
2023-08-31 13:41:41 +05:30
Nikhil
320608ea73 chore: return issue votes in public issue list endpoint (#2026) 2023-08-31 11:32:58 +05:30
Aaryan Khandelwal
5e00ffee05 fix: bugs on the user profile page (#2018) 2023-08-30 17:28:17 +05:30
Aaryan Khandelwal
54527cc2bb dev: revamp publish project modal (#2022)
* dev: revamp publish project modal

* chore: sidebar dropdown text
2023-08-30 17:27:49 +05:30
Bavisetti Narayan
6c6b81bea7 chore: tracking the history of issue reactions and votes. (#2020)
* chore: tracking the issues reaction and vote history

* fix: changed the keywords for vote and reaction

* chore: added validation
2023-08-30 16:38:04 +05:30
Aaryan Khandelwal
f5a076e9a9 dev: revamp peek overview (#2021)
* dev: mobx for issues store

* refactor: peek overview component

* chore: update open issue button

* fix: issue mutation after any crud action

* chore: remove peek overview from gantt

* chore: refactor code
2023-08-30 13:26:28 +05:30
Bavisetti Narayan
17aff1f369 fix: asset key validation (#1938)
* fix: asset key validation

* chore: asset key validation in user assets

---------

Co-authored-by: Bavisetti Narayan <narayan@Bavisettis-MacBook-Pro.local>
2023-08-30 12:20:13 +05:30
Nikhil
761a1eb41a fix: user created by stats (#2016) 2023-08-30 12:18:56 +05:30
Nikhil
426f65898b feat: user timezones (#2009)
* dev: user timezones

* feat: user timezones
2023-08-30 12:18:18 +05:30
Nikhil
23f5d5d172 chore: track public board comments and reaction users for public deploy boards (#1972)
* chore: track project deploy board comment and reaction users for public deploy boards

* dev: remove tracking from project viewsets
2023-08-30 12:15:08 +05:30
Aaryan Khandelwal
2e5ade05fe chore: update module status icons and colors (#2011)
* chore: update module status icons and colors

* refactor: import statements

* fix: add default alue to module status
2023-08-30 11:43:47 +05:30
Aaryan Khandelwal
168e79d6df style: revamp of the issue details sidebar (#2014) 2023-08-29 20:15:12 +05:30
Aaryan Khandelwal
d8bbdc14ac feat: access selector for comment (#2012)
* dev: access specifier for comment

* chore: change access order
2023-08-29 20:14:13 +05:30
Aaryan Khandelwal
fd0efb0242 fix: start date filter not working on the platform (#2007) 2023-08-29 20:11:38 +05:30
Aaryan Khandelwal
38a5623c43 dev: user timezone select option (#2002) 2023-08-29 20:11:06 +05:30
Nikhil
90cf39cf59 fix: access creation in comments (#2013) 2023-08-29 16:40:28 +05:30
Bavisetti Narayan
b2a41d3bf6 fix: issue votes (#2006)
* fix: issue votes

* fix: added default as 1 in vote

* fix: issue vote migration file
2023-08-29 15:02:29 +05:30
Bavisetti Narayan
1cf5e8d80a fix: only external comments will show in deploy boards (#2010) 2023-08-29 15:01:18 +05:30
Nikhil
1d30a9a0a8 chore: project public board issue retrieve (#2003)
* chore: project public board issue retrieve

* dev: project issues list endpoint

* fix: issue public retrieve endpoint
2023-08-29 15:00:26 +05:30
Bavisetti Narayan
91c10930a4 feat: mark all read notifications (#1963)
* feat: mark all read notifications

* fix: changed string to boolean

* fix: changed snoozed condition
2023-08-29 14:57:27 +05:30
Nikhil
5ad5da4fd7 dev: remove gunicorn config (#1999) 2023-08-29 13:45:25 +05:30
Nikhil
e1ad385688 fix: issue exports in self hosted instances (#1996)
* fix: issue exports in self hosted instances

* dev: remove print logs

* dev: update url creation function

* fix: changed the presigned url for self hosted exports

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2023-08-29 13:45:04 +05:30
Nikhil
abcdebef85 fix: n+1 in issue history and issue automation tasks (#1994) 2023-08-29 13:35:36 +05:30
Nikhil
3a41ec7442 chore: update user activity endpoint to return only workspace activities (#1980) 2023-08-29 13:35:13 +05:30
Nikhil
8581226e60 chore: improve access field for comments for public boards (#1956)
Co-authored-by: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com>
2023-08-29 13:34:38 +05:30
sriram veeraghanta
c65bbf865d fix: tiptap editor export fixes (#2001) 2023-08-28 15:54:49 +05:30
srinivas pendem
b2e5760391 bugfix: Export download next link changed to anchor (#2000)
* bugfix: Export download next link changd to anchot

* bugfix: user workspace service name update

---------

Co-authored-by: srinivaspendem <you@example.comsrinivaspendem2612@gmail.com>
2023-08-28 15:54:20 +05:30
Henit Chobisa
8a3b65a740 [chore] Update development workflows with every PR build and removed image update on every merge (#1985)
* chore: Combined Github Workflows for Release

* chore: Added Workflows for Building and Testing Changes
2023-08-28 13:36:08 +05:30
sriram veeraghanta
293d90ddda fix: Cycles and Modules Cards view responsiveness (#1997)
* fix: modules cards fixes

* fix:cycles responsive cards
2023-08-28 13:34:05 +05:30
Aaryan Khandelwal
485e56bcdf fix: my profile activity endpoint (#1983)
* fix: my profile activity endpoint

* chore: update service name
2023-08-28 13:29:48 +05:30
Aaryan Khandelwal
6e7701d854 chore: don't show completion percentage if user has no assigned issues (#1984) 2023-08-28 13:29:07 +05:30
Aaryan Khandelwal
a1acd2772e feat: mark all as read (#1982) 2023-08-28 13:26:38 +05:30
Aaryan Khandelwal
47abe9db5e dev: gantt chart revamp (#1900)
* style: gantt chart polishing

* chore: sidebar y-axis drag and drop

* chore: remove y-axis drag and drop from the main content

* refactor: drop end function

* refactor: resizing logic

* chore: x-axis block move

* chore: x-axis block move flag

* chore: update scroll end logic

* style: modules gantt chart

* style: block background tint

* refactor: context dispatcher types

* refactor: draggable component

* chore: filters added to gantt chart

* refactor: folder structure

* style: cycle blocks

* chore: move to block arrow

* chore: move to block on the right side arrow

* chore: added proper comments for functions

* refactor: blocks render logic

* fix: x-axis drag and drop

* chore: minor ui fixes

* chore: remove link tag from blocks

---------

Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-28 13:25:47 +05:30
sriram veeraghanta
a61e8370b5 fix: workspace accepted invitation redirects to the workspace (#1971)
* fix: workspace accepted invitation redirects to the workspace

* chore: removing logs

* fix: updating user last workspace id with newly joined one

* adding error toast
2023-08-28 13:25:09 +05:30
sriram veeraghanta
9f420a00d7 fix: create new project as fav (#1993) 2023-08-28 13:09:27 +05:30
Nikhil
a9ff4b8c93 fix: project members n+1 (#1975) 2023-08-27 20:31:32 +05:30
Aaryan Khandelwal
2b168edd99 feat: peek overview for spreadsheet issues (#1979)
* feat: peak overview for issues

* fix: peek spelling

* chore: truncate issue property labels

* style: full screen view designed

* chore: add comment section

* chore: copy link and delete options added

* chore: update icons

---------

Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-25 17:41:23 +05:30
Nikhil
93fa093a79 dev: update python runtime (#1981) 2023-08-25 17:23:07 +05:30
Nikhil
fd8c368c97 fix: add member role and member status in project create response (#1962) 2023-08-25 15:16:15 +05:30
sriram veeraghanta
0525e7d6b3 fix: workspace members reordering (#1978) 2023-08-25 13:38:50 +05:30
Aaryan Khandelwal
1530993b84 fix: tiptap editor max width (#1968)
Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-25 12:42:12 +05:30
Aaryan Khandelwal
d8b8c903f2 fix: issue activity redirection to cycle and module (#1973)
Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-25 12:21:11 +05:30
Aaryan Khandelwal
bf0d0503b2 fix: redirection after deleting a project (#1970)
Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-25 12:17:17 +05:30
Henit Chobisa
fe1b0c1d73 [chore] Fixed Github Workflows for Building and Pushing, frontend, backend, proxy & plane-deploy (#1959)
* chore: modified frontend github workflow

* chore: modified backend github workflows

* chore: added github workflow for build and push for plane-deploy

* chore: added github workflow for plane-proxy
2023-08-25 12:12:07 +05:30
Aaryan Khandelwal
ab4a17c178 chore: custom CSS shadow variables added (#1969)
* chore: custom shadow variables added

* fix: 2xs shade

---------

Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-24 23:07:20 +05:30
Aaryan Khandelwal
38934e8b99 chore: group by assignees option for project issues (#1957)
* dev: group by assignees option for project issues

* fix: no assignee title

---------

Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-24 19:46:12 +05:30
Aaryan Khandelwal
d18ac83909 feat: start date filter added across the platform (#1955)
Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-24 19:45:23 +05:30
sriram veeraghanta
802e6b3e8e fix: project member mutate issue (#1967) 2023-08-24 19:43:50 +05:30
sriram veeraghanta
489ef6a3cc Merge pull request #1966 from makeplane/fix/workspace-members-mutate
fix: workspace members mutate issue
2023-08-24 18:26:11 +05:30
sriram veeraghanta
bce8cae0da fix: mutate fixes 2023-08-24 18:21:57 +05:30
sriram veeraghanta
f97597958a fix: workspace memebers mutate issue 2023-08-24 17:44:20 +05:30
Nikhil
7fca01d8c9 feat: project deploy board endpoint (#1943) 2023-08-23 22:13:37 +05:30
Bavisetti Narayan
529ab19747 chore: removed extra exporter function (#1953) 2023-08-23 22:13:04 +05:30
sriram veeraghanta
6f397710ce Merge pull request #1951 from makeplane/stage-release
Promote: Stage release to Production
2023-08-23 16:18:08 +05:30
sriram veeraghanta
e6bd6b6a8c Merge pull request #1950 from makeplane/develop
Promote: Develop to Stage Release
2023-08-23 15:49:14 +05:30
Aaryan Khandelwal
2d1406953e fix: mutate projects list after joining (#1944)
Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-23 15:44:27 +05:30
Aaryan Khandelwal
a8fdd42cb9 fix: label color select popover overflow (#1949)
Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-23 15:43:09 +05:30
sriram veeraghanta
9d3952006b Merge pull request #1948 from makeplane/stage-release
Promot: Stage Release to Production
2023-08-23 14:51:27 +05:30
sriram veeraghanta
b75473a684 Merge pull request #1947 from makeplane/develop
Promote: Develop to Stage Release
2023-08-23 12:37:25 +05:30
Aaryan Khandelwal
561fb9815b chore: update export services icons (#1946)
Co-authored-by: Aaryan Khandelwal <aaryan610@Aaryans-MacBook-Pro.local>
2023-08-23 12:29:59 +05:30
Bavisetti Narayan
2cc67f6498 fix: date validation in cycle and module (#1945) 2023-08-23 12:17:20 +05:30
Nikhil
2f5bd58c61 Merge pull request #1941 from makeplane/stage-release
promote: stage-release to master
2023-08-22 19:37:49 +05:30
Nikhil
e833fccf61 Merge pull request #1940 from makeplane/develop
dev: deploy docker containers (#1939)
2023-08-22 19:34:13 +05:30
Nikhil
eee6658cc2 dev: deploy docker containers (#1939) 2023-08-22 19:33:29 +05:30
Nikhil
62ba9abdb4 Merge pull request #1936 from makeplane/stage-release
promote: stage-release to master
2023-08-22 13:57:57 +05:30
Nikhil
46b138eb0b Merge pull request #1934 from makeplane/develop
fix: aws region changed for exporter (#1933)
2023-08-22 13:51:20 +05:30
Bavisetti Narayan
68b438ab1a fix: aws region changed for exporter (#1933)
Co-authored-by: Bavisetti Narayan <narayan@Bavisettis-MacBook-Pro.local>
2023-08-22 13:18:15 +05:30
Nikhil
59bdf222f5 Merge pull request #1932 from makeplane/stage-release
promote: stage release to master
2023-08-22 01:34:37 +05:30
Nikhil
eb50ade5e3 Merge pull request #1931 from makeplane/develop
fix: access environment variables is changed in services (#1930)
2023-08-22 01:14:56 +05:30
guru_sainath
b406a70e72 fix: access environment variables is changed in services (#1930)
Co-authored-by: Sainath <sainath@Sainaths-MacBook-Pro.local>
2023-08-22 01:13:51 +05:30
Vamsi Kurama
85a08e4abd Merge pull request #1929 from makeplane/stage-release 2023-08-22 00:17:29 +05:30
Nikhil
aa2e1697b0 Merge pull request #1928 from makeplane/develop
promote: develop to stage-release
2023-08-21 20:51:46 +05:30
Aaryan Khandelwal
b02417120b chore: hide new issue button from my subscribed issues page (#1927) 2023-08-21 20:50:17 +05:30
Aaryan Khandelwal
d040394826 fix: create project button not appearing on the sidebar (#1926) 2023-08-21 20:44:51 +05:30
Nikhil
f7682c57ba fix: plane space start up command (#1925) 2023-08-21 20:25:12 +05:30
Nikhil
3beab9de6f Merge pull request #1923 from makeplane/develop
promote: develop to stage-release
2023-08-21 18:18:14 +05:30
guru_sainath
9bb6254515 chore: updated default api base_url (#1922) 2023-08-21 18:17:32 +05:30
Aaryan Khandelwal
ae052f1890 chore: update restricted workspace slugs (#1920) 2023-08-21 18:13:08 +05:30
Henit Chobisa
cfc7049343 Dockerrizing space project (#1921)
* chore: Added Dockerfile for Space Project

* fix: next js config to standalone mode

* fix: workedaround build error with rename 404 page

* chore: modified dockerfile with new conventions

* chore: modified dockercompose file for new plane-deploy

* fix: handled ts errors with possibly undefined states

* chore: updated main dockerfile with plane-deploy

* feat: included space project to start.sh

* chore: modified space project port while running in production

* chore: restored changes inside space project

* chore: added ngnix config for space project running :4000

* fix: Updated docker-compose files

* chore: added space url for ngnix config

* chore: Updated ngnix template

* chore: updated space url in compose hub file

* dev: updated dockerfile.space and start and replace script

* dev: equate hub and build docker files

* dev: revert workspace space page

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2023-08-21 18:12:41 +05:30
guru_sainath
41e55dff85 fix: build error for 404 and search params null check (#1919) 2023-08-21 12:43:41 +05:30
Aaryan Khandelwal
0bccb63a9f fix: module start and target date validations (#1914) 2023-08-21 11:46:02 +05:30
Aaryan Khandelwal
2eb956e97e refactor: project and workspace delete modals (#1915) 2023-08-21 11:44:59 +05:30
M. Palanikannan
d470adf262 fix: Image resize, Link selector in Modals, Delete/ sync images and so much more (#1896)
* added image-resizing support

* link form removed

* updated image upload logic and 35% default width on upload

* removed shadow, added alert if not saved and ts errors

* prevent enter key on Link selector to trigger modal submit

* added workspace slug to all tiptap instances

* added delete plugin with loading indicator

* added better syncing of "Saved" state of editor and Image uploads

* removed redundant description_html check
2023-08-19 18:58:54 +05:30
Aaryan Khandelwal
cebc8bdc8d fix: context menu dynamic positioning, multiple context menus opening issue (#1913)
* fix: context menu positioning

* fix: close already opened context menu on outside click
2023-08-19 18:50:12 +05:30
Anmol Singh Bhatia
64b5ba196f style: responsive empty state for profile stats (#1911) 2023-08-18 20:18:03 +05:30
Nikhil
13d21e752d Merge pull request #1910 from makeplane/develop
promote: develop to stage-release
2023-08-18 19:29:11 +05:30
Anmol Singh Bhatia
8d5018318d chore: add favorite project from sidebar (#1909) 2023-08-18 18:42:50 +05:30
Anmol Singh Bhatia
0fbdc0b157 style: consistent ui for create update issue modal (#1907) 2023-08-18 18:42:04 +05:30
Bavisetti Narayan
2f39181eb7 fix: priority ordering (#1908) 2023-08-18 18:27:29 +05:30
Dakshesh Jain
d825dc5579 style: showing first name for bot profile (#1894) 2023-08-18 17:15:20 +05:30
Aaryan Khandelwal
1f8117c987 fix: dashboard upcoming issues list (#1904) 2023-08-18 17:10:12 +05:30
Bavisetti Narayan
125e9090ea chore: module link model (#1905)
* chore: module link model

* chore: added migration
2023-08-18 15:50:48 +05:30
Bavisetti Narayan
02ac4cee22 chore: renamed target date to start date (#1902) 2023-08-18 15:25:42 +05:30
Anmol Singh Bhatia
93164755e2 style: analytics stats empty state (#1903) 2023-08-18 15:15:33 +05:30
Aaryan Khandelwal
6344f6f562 chore: set order by to manual on gantt chart (#1886) 2023-08-18 15:12:12 +05:30
Aaryan Khandelwal
b67e30fd9c chore: analytics start date property for x-axis and group (#1888) 2023-08-18 15:11:25 +05:30
Anmol Singh Bhatia
93fec2c678 fix: completed cycle validation , style: assignee count alignment fix (#1901)
* style: assignee count alignment fix

* fix: completed cycle validation
2023-08-18 14:23:13 +05:30
Anmol Singh Bhatia
c3c6ba9e34 chore: link edit functionality (#1895) 2023-08-18 12:03:31 +05:30
Anmol Singh Bhatia
d74ec7bda9 fix: ui improvement and bug fixes (#1883) 2023-08-18 12:01:51 +05:30
Henit Chobisa
e593a8d4bd chore: Edited Setup Script to take TipTap Auth Token and Generate .npmrc (#1897) 2023-08-18 11:47:58 +05:30
guru_sainath
abb8782c44 fix: handled default view on plane deploy (#1893)
* fix: handled default view on plane deploy

* fix: handled default view on refresh
2023-08-17 14:24:33 +05:30
guru_sainath
0afd72db95 fix: updated theming in workspace preferences (#1890) 2023-08-16 20:35:17 +05:30
guru_sainath
65295f6c6f chore: updating the theme using MobX from command k (#1879)
* chore: updating the theme using mobx from command k

* feat: Showing the project published status in the app header

* dev: updated validation and redirection the project publish modal and added redirection on the app header
2023-08-16 18:26:36 +05:30
Aaryan Khandelwal
5b6b43fb83 fix: quick action buttons: (#1884) 2023-08-16 18:25:11 +05:30
Dakshesh Jain
f8497125db style: fixed display name coming twice on profile page (#1889) 2023-08-16 18:18:57 +05:30
Bavisetti Narayan
b24622e5ef fix: validation for issue activity description (#1887) 2023-08-16 17:12:09 +05:30
guru_sainath
10dface85d chore: updated error pages 404 and project-not-found in plane deploy (#1885)
* dev: custom error messages.

* dev: updated next version in yarn.lock

* dev: updated project-not-published icon
2023-08-16 17:05:40 +05:30
Aditi Patel
2b6debaa3e Updated setup document to include tiptap pro install (#1871) 2023-08-16 14:42:37 +05:30
Nikhil
1750ba344b fix: my issue duplication (#1882)
Co-authored-by: Plane Team <planeteam@srirams-Mac-mini.local>
2023-08-16 14:40:10 +05:30
Nikhil
550473bb02 Merge pull request #1876 from makeplane/stage/merge-fixes
Promote: Develop to Stage Release
2023-08-16 13:18:26 +05:30
sriramveeraghanta
fde978861c Merge branch 'develop' of github.com:makeplane/plane into stage/merge-fixes 2023-08-16 13:17:21 +05:30
guru_sainath
f44d142f2c chore: tip-tap editor update in workspace user activity (#1877) 2023-08-16 13:16:20 +05:30
guru_sainath
1ded8f486f chore: updated meta tags for project issues (#1875)
* dev: updated meta tags for project issues

* dev: updated project description in meta tags in plane deploy.
2023-08-16 13:15:57 +05:30
Bavisetti Narayan
2c43a15515 chore: added new filed in serializer (#1874)
Co-authored-by: NarayanBavisetti <narayan311@gmail.com>
2023-08-16 13:10:03 +05:30
Dakshesh Jain
0979acc1a4 fix: notification card not redirecting to archive issue detail for archived issue (#1861) 2023-08-16 13:09:56 +05:30
sriramveeraghanta
9003c58d89 merge conflicts resolved 2023-08-16 13:00:58 +05:30
Nikhil
55e2f00ffe fix: members list filtering for workspace and projects (#1872) 2023-08-16 12:21:56 +05:30
Nikhil
08382f88b4 chore: updated migration files for 0.11 (#1851) 2023-08-16 10:37:22 +05:30
Bavisetti Narayan
72419447ec fix: added slug in filename for export issues (#1870)
* chore: file name changed for exported issues

* fix: added slug in filename for export issues

---------

Co-authored-by: NarayanBavisetti <narayan311@gmail.com>
2023-08-16 09:39:17 +05:30
Nikhil
b554087b1f chore: deploy board status for project (#1866) 2023-08-16 01:00:22 +05:30
Bavisetti Narayan
07717e9a93 chore: file name changed for exported issues (#1865)
Co-authored-by: NarayanBavisetti <narayan311@gmail.com>
2023-08-15 19:49:17 +05:30
Nikhil
df46a45afc fix: analytics export (#1862)
* fix: analytics export

* dev: export analytics assignee indexing

* dev: total counts
2023-08-15 15:48:22 +05:30
sriram veeraghanta
e1ae0d3b56 feat : Tiptap integration (#1832)
* remirror instances commented out to avoid prosemirror conflicts

* styles migrated for remirror to tiptap transition

* added bubblemenu support with extensions

* fixed css for task lists and code with syntax highlighting

* added support for slash command

* fixed bubble menu to match styles and added better seperation in UI

* saving with debounce logic added and it's stored in backend

* added migration support by updating to html

* Image uploads done

* improved file structure and delete image function implemented

* Integrated tiptap with Issue Modal

* added additional props and Tiptap Integration with Comments

* added tiptap integration with user activity feeds

* added ref control support and bubble menu support for readonly editor

* added tiptap support for plane pages

* added tiptap support to gpt assistant modal (yet to be tested)

* removed remirror instances and cleaned up code

* improved code structure for extracting props in Tiptap

* fixing ts errors for next build

* fixing node ts error for Horizontal Rule

* added ts fix for node types

* temp fix

* temp fix

* added min height for issue description in modal

* added resolutions to prosemirror-model version

* trying pnpm overrides

* explicitly added prosemirror deps

* bugfixes

* removed extra gap at the top and moved saved indicator to the bottom

* fix: slash command scroll position

* chore: update custom css variables

* matched theme colours

* fixed gpt-assistant modal

* updated yarn lock

* added debounced updates for the title and removed saved state after timeout

* added css animations for saved state

* build fixes and remove remirror instances

* minor commenting fixes

---------

Co-authored-by: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-08-15 15:04:46 +05:30
guru_sainath
daa8f7d79b feat / public deploy settings workflow (#1863)
* Feat: Implemented project publish settings

* dev: updated the env dependancy in turbo and enabling the publish access to admin
2023-08-14 19:18:38 +05:30
Nikhil
d2cdaaccb9 fix: slack queryset (#1860) 2023-08-14 18:53:09 +05:30
Anmol Singh Bhatia
6774eddb66 style: sidebar select date width (#1859) 2023-08-14 18:10:21 +05:30
Dakshesh Jain
8ccc1b3fcc fix: gray background on png image (#1856) 2023-08-14 16:23:10 +05:30
Anmol Singh Bhatia
5e76e03a55 style: profile activity loader (#1858) 2023-08-14 16:20:53 +05:30
srinivas pendem
77fb50faa4 fix: route fix in imports and exports (#1857) 2023-08-14 16:19:13 +05:30
Bavisetti Narayan
5ddfee12bc fix: changed the display of date format (#1855)
Co-authored-by: NarayanBavisetti <narayan311@gmail.com>
2023-08-14 16:10:57 +05:30
Aaryan Khandelwal
f7a596c113 fix: gantt chart block left drag flicker (#1854)
* fix: left drag flicker

* fix: opposite side manual scroll
2023-08-14 14:27:02 +05:30
Dakshesh Jain
f73239be92 refactor: using webp image format instead of svg (#1852) 2023-08-14 13:26:16 +05:30
Anmol Singh Bhatia
dc2438b2d3 style: image upload modal aspect ratio (#1853) 2023-08-14 13:06:00 +05:30
srinivas pendem
ddd3301d17 feat: csv, json and, xlsx exporter (#1840)
* feat : csv, jason and, xlxs exporter

* handeling the export fail

* adding expired state to exports

* typo update

* header change

* improvement: added validation for the expired date

---------

Co-authored-by: srinivaspendem <you@example.comsrinivaspendem2612@gmail.com>
2023-08-14 11:44:17 +05:30
Vamsi Kurama
816f00d956 Merge pull request #1848 from ryota-murakami/fix/license 2023-08-12 17:12:14 +05:30
ryota-murakami
70e2509d52 package.json; fix license 2023-08-12 20:30:01 +09:00
Bavisetti Narayan
1a9faa025a fix: export issues in CSV, JSON and XLSX (#1794)
* fix: file name change

* feat: added xml json and csv export

* chore: added openpyxl package

* fix: added initiated_by field

* fix: added initiated by details

* dev: refactoring

* fix: rendering assignee name and labels in sheet

* fix: handeled exception in label

* feat: implemented link expiration scheduler(8 days)

* fix: removed the expired field

---------

Co-authored-by: NarayanBavisetti <narayan311@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2023-08-11 20:09:52 +05:30
Nikhil
feba1cc4d0 feat: project public boards (#1772)
* feat: project public boards

* dev: public issue and comment reactions

* dev: public issue comments

* dev: public comments

* dev: inbox for public boards

* dev: inbox issues for public board

* dev: public inbox issue

* dev: migrations

* dev: update api endpoints

* dev: project boards and views

* dev: state and label details

* dev: public issue voting

* dev: issue voting

* dev: workspace details

* dev: project icon and emoji
2023-08-11 19:27:44 +05:30
Anmol Singh Bhatia
079a5b28d8 style: custom theming color picker position (#1846) 2023-08-11 19:17:59 +05:30
Aaryan Khandelwal
c6eea9c7a9 fix: empty groups not appearing in the kanban view (#1843) 2023-08-11 19:17:02 +05:30
Anmol Singh Bhatia
5f5790ebf9 chore: start date option added in spreadsheet view (#1824) 2023-08-11 19:14:54 +05:30
Anmol Singh Bhatia
a3d99100ee fix: sub issue progress indicator fix (#1847) 2023-08-11 19:05:13 +05:30
Anmol Singh Bhatia
ac6d2b0139 chore: updated user permission for project and workspace settings (#1807)
* fix: updated user permission for project and workspace settings

* chore: workspace delete modal fix
2023-08-11 18:29:24 +05:30
Dakshesh Jain
7becec4ee9 feat: randomize color on label create (#1839)
fix: create label state being persisted after edit label
2023-08-11 17:42:47 +05:30
guru_sainath
cd5e5b96da feat: Mobx integration, List and Kanban boards implementation in plane space (#1844)
* feat: init mobx and issue filter

* feat: Implemented list and kanban views in plane space and integrated mobx.

* feat: updated store type check
2023-08-11 17:18:33 +05:30
Dakshesh Jain
ad4cdcc512 fix: cmdk modal not closing when choosing an option (#1833) 2023-08-11 17:16:37 +05:30
Nikhil
6617049983 fix: sub issue endpoint for state distribution (#1845) 2023-08-11 16:38:03 +05:30
Dakshesh Jain
abec46a725 fix: cmdk not changing theme if active theme is custom-theme (#1842) 2023-08-11 16:16:20 +05:30
Nikhil
88e987b902 feat: cycle and module sort order (#1841)
* dev: cycle and module ordering

* dev: sort order for smallest
2023-08-11 16:03:15 +05:30
Aaryan Khandelwal
785a6e8871 chore: gantt chart resizable blocks, y-axis drag and drop (#1810)
* chore: gantt chart resizable blocks

* chore: right scroll added

* chore: left scroll added

* fix: build errors

* chore: remove unnecessary console logs

* chore: add block type and remove info toggle

* feat: gantt chart blocks y-axis drag and drop

* chore: disable drag flag

* fix: y-axis drag mutation

* fix: scroll container undefined error

* fix: negative scroll

* fix: negative scroll

* style: blocks tooltip consistency
2023-08-11 15:59:13 +05:30
Anmol Singh Bhatia
762ef422ca chore: project search added in project list page (#1837) 2023-08-11 15:57:11 +05:30
Anmol Singh Bhatia
e2b5657c3e chore: profile cover photo (#1836) 2023-08-11 15:56:26 +05:30
Anmol Singh Bhatia
dbb53a663e style: sidebar ui improvement (#1816)
* style: sidebar ui improvement

* style: sidebar menu spacing

* style: sidebar consistent spacing

* style: notification improvement

* style: remove from favorite filled icon added

* chore: settings option added in sidebar context menu

* chore: update delete project option visibility for sidebar

* style: sidebar project list display border top on scroll
2023-08-11 15:53:10 +05:30
Anmol Singh Bhatia
5c964d144a style: ui improvement (#1806)
* style: kanban board theming

* style: assignee ui revamp

* style: kanban board header, label , priority , state and avatar ui revamp

* style: kanban card state dropdown

* style: sidebar profile dropdown

* style: sidebar dropdown icon

* style: sidebar workspace dropdown

* style: assignee select component

* fix: state select

* style: consistent app header button
2023-08-11 15:50:05 +05:30
Anmol Singh Bhatia
289e81d6eb chore: issue activity user redirection added (#1805)
* feat: issue activity user redirection added

* feat: analytics page user redirection
2023-08-11 15:48:52 +05:30
Nikhil
def10af1e2 fix: issue date filtering (#1834) 2023-08-11 12:48:30 +05:30
Nikhil
edaeae1b69 chore: sort order for cycle and modules (#1835) 2023-08-11 12:48:02 +05:30
Nikhil
e06ee25800 fix: project states create (#1830) 2023-08-11 12:46:50 +05:30
Nikhil
be86a7d38e feat: project member role (#1828) 2023-08-11 12:46:29 +05:30
Nikhil
0a1483c482 chore: issue list date filters and properties (#1820)
* dev: start date and target date validation and filter for null dated issues

* dev: remove print logs

* dev: issue property dates
2023-08-11 12:45:51 +05:30
Nikhil
11abd3cadf fix: user id for default analytics (#1808) 2023-08-11 12:45:04 +05:30
Nikhil
085cd1960e fix: project members endpoint email (#1804)
* fix: project members endpoint email

* dev: cycle and module assignee display name
2023-08-11 12:44:20 +05:30
Nikhil
2769a73898 remove: auto start date configuration (#1799) 2023-08-11 12:43:43 +05:30
Nikhil
8373f20944 fix: issues n plus 1 (#1785) 2023-08-11 12:43:00 +05:30
Dakshesh Jain
f562fcd466 refactor: both delete or backspace can be used to open modal (#1829)
* refactor: both delete or backspace can be used to open modal

* fix: 'Bulk Issue Delete' modal will open on single click
2023-08-10 16:02:10 +05:30
Dakshesh Jain
8c8668a3e6 refactor: not making calls to member's endpoint to get membership status (#1831)
* refactor: not making call to members endpoint to get membership status

* refactor: type for IProject
2023-08-10 15:39:32 +05:30
Dakshesh Jain
9ce85cdf21 refactor: if/else conditions (#1822)
* refactor: shortcuts if/else

* fix: merge conflict
2023-08-10 13:12:17 +05:30
Dakshesh Jain
1c6cdb8328 refactor: added validation for display_name (#1823) 2023-08-10 13:05:03 +05:30
guru_sainath
005b42cb8d dev: Updating themening worfkflow (#1827) 2023-08-10 13:03:42 +05:30
Dakshesh Jain
be062ccd34 fix: import user using endpoint with email (#1819) 2023-08-09 17:49:25 +05:30
Dakshesh Jain
c9d0c5353d style: displaying email in members page depending on user role (#1817)
* style: displaying email in members page depending on user role

* refactor: added null safety
2023-08-09 17:23:57 +05:30
Dakshesh Jain
2a6eb5fe23 style: option to edit display name in profile page (#1818) 2023-08-09 16:44:35 +05:30
Aaryan Khandelwal
d9ccce41bc chore: profile and my issues page start date option (#1815)
* chore: profile and my issues page start date option

* fix: properties order in my profile view options
2023-08-09 15:46:47 +05:30
Anmol Singh Bhatia
3db69a3a71 style: profile empty state (#1811)
* style: profile empty state

* style: priority empty state padding
2023-08-09 15:45:20 +05:30
Dakshesh Jain
faa50b0bbb fix: analytics showing user id instead of display name (#1812)
* fix: replacing first, last name and email with display name

* fix: different endpoint for workspace & project member

* fix: falling back to email if display_name doesn't exist

* fix: analytics showing user id instead of display name
2023-08-09 15:20:29 +05:30
Dakshesh Jain
1991e09035 refactor: removed escape keydown listener (#1814) 2023-08-09 15:18:26 +05:30
Aaryan Khandelwal
4fcd081d27 chore: select start date option for issue (#1813) 2023-08-09 15:17:32 +05:30
Aaryan Khandelwal
5f1209f1db chore: empty state for multi-level dropdown (#1802)
* fix :label filter should show something if there is no label #1779 (#1795)

* style: children empty state

---------

Co-authored-by: Pankaj Chotaliya <34762752+pankajvc@users.noreply.github.com>
2023-08-08 14:13:26 +05:30
Aaryan Khandelwal
88e5a05253 chore: subscribed by me tab on my issues page (#1800)
* chore: add subscribed by me tab in my issues

* chore: update tab titles

* fix: build error
2023-08-08 13:15:25 +05:30
Dakshesh Jain
981acc81c1 fix: replaced first name, last name or email to display name (#1796)
* fix: replacing first, last name and email with display name

* fix: different endpoint for workspace & project member

* fix: falling back to email if display_name doesn't exist
2023-08-08 13:01:43 +05:30
Nikhil
cf306ee605 feat: user display name (#1179)
* feat: user display name for the entire system

* feat: update issue activity to remove emails

* dev: update to display name wherever assignees__email and member__email

* dev: update display names on issue activity and the user script

* dev: update display_name function to generate display_name from email

* dev: add email for test purpose

* dev: set default display name for the user

* dev: add migration script and default value

* dev: annotate with assignees_id

* dev: return assignees id

* dev: display name for the profile

* dev: project members endpoint

* dev: url update

* dev: trailing /

* dev: update workspace member serializer

* fix: activity for assignees
2023-08-08 12:59:04 +05:30
guru_sainath
9df0ba6e3a feat: initiated plane space (#1801) 2023-08-08 12:55:42 +05:30
guru_sainath
b6744dcd29 Chore: mobx setup and app sidebar and theme management (#1798)
* dev: Mobx integration for app sidebar and custom theme

* dev: Handled edge case and conditional rendering for mobx store
2023-08-08 12:50:27 +05:30
DevMiner
a164dfd532 chore(frontend): add sharp (#1451) 2023-08-07 15:52:08 +05:30
Bavisetti Narayan
2b46e5f977 feat: issue export csv (#1781)
* feat: created issue export csv

* fix: optimized the queries

---------

Co-authored-by: NarayanBavisetti <narayan311@gmail.com>
2023-08-07 11:59:04 +05:30
Vamsi Kurama
9ff8994c0e Merge pull request #1784 from makeplane/stage-release
promote: stage-release to master v0.10.1-patch
2023-08-03 18:55:24 +05:30
Nikhil
9b4aebc385 promote: develop to stage-release v0.10-patch (#1783)
* chore: show message if dragging unjoined project (#1763)

* fix: invalid project selection in create issue modal (#1766)

* style: sidebar project list improvement (#1767)

* fix: comment reaction mutation (#1768)

* fix: user profiles n plus 1 (#1765)

* fix: bulk issue import (#1773)

* style: profile activity (#1771)

* style: profile activity comment log styling

* chore: profile feed activity refactor

* style: sidebar project list

* chore: add non existing states for project entities (#1770)

* fix: notification read status being toggled when click on link (#1769)

* fix: custom theme persisting after signing out (#1780)

* fix: custom theme persistence

* chore: remove console logs

* fix: build error

* fix: change theme from command k

---------

Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
2023-08-03 15:28:22 +05:30
Aaryan Khandelwal
97c3fb40e7 fix: custom theme persisting after signing out (#1780)
* fix: custom theme persistence

* chore: remove console logs

* fix: build error

* fix: change theme from command k
2023-08-03 15:01:31 +05:30
Dakshesh Jain
5aad6c71da fix: notification read status being toggled when click on link (#1769) 2023-08-02 17:23:55 +05:30
Aaryan Khandelwal
a1ae338c37 chore: add non existing states for project entities (#1770) 2023-08-02 16:47:36 +05:30
Anmol Singh Bhatia
c16b0daa22 style: profile activity (#1771)
* style: profile activity comment log styling

* chore: profile feed activity refactor

* style: sidebar project list
2023-08-02 16:45:34 +05:30
Nikhil
9a29896291 fix: bulk issue import (#1773) 2023-08-02 16:42:47 +05:30
Nikhil
a66dcb9419 fix: user profiles n plus 1 (#1765) 2023-08-02 16:42:24 +05:30
Dakshesh Jain
87a920174e fix: comment reaction mutation (#1768) 2023-08-02 14:21:48 +05:30
Anmol Singh Bhatia
584192faba style: sidebar project list improvement (#1767) 2023-08-02 14:21:26 +05:30
Dakshesh Jain
b61adbed4b fix: invalid project selection in create issue modal (#1766) 2023-08-02 13:38:45 +05:30
Aaryan Khandelwal
7434800999 chore: show message if dragging unjoined project (#1763) 2023-08-02 12:09:53 +05:30
Vamsi Kurama
3488001197 Merge pull request #1762 from makeplane/stage-release
promote: stage-release to master
2023-08-01 22:38:20 +05:30
Nikhil
9828d2332a Merge pull request #1761 from makeplane/develop
promote: develop to stage-release
2023-08-01 22:07:03 +05:30
Nikhil
78095e3823 Merge pull request #1760 from makeplane/fix/project_member_invite
fix: project invite
2023-08-01 22:05:48 +05:30
pablohashescobar
f41086fd26 fix: typeerror 2023-08-01 22:00:56 +05:30
pablohashescobar
0866dc3494 fix: project invite 2023-08-01 21:42:48 +05:30
Vamsi Kurama
2ced7e4911 Merge pull request #1758 from makeplane/stage-release
promote: stage-release to master v0.10
2023-08-01 20:04:40 +05:30
Nikhil
9f69fe6060 Merge pull request #1750 from makeplane/develop
promote: develop to stage-release
2023-08-01 19:35:54 +05:30
Nikhil
6ea15ced02 fix: project identifier length (#1757) 2023-08-01 19:25:04 +05:30
Nikhil
11525f26d0 fix: project identifier migration (#1755) 2023-08-01 19:11:32 +05:30
Anmol Singh Bhatia
f3bd1691ce style: sidebar project list styling (#1756) 2023-08-01 19:11:09 +05:30
Anmol Singh Bhatia
d83a76a3aa style: my issue and profile page view dropdown (#1754) 2023-08-01 19:04:53 +05:30
Aaryan Khandelwal
2cd431b4a4 fix: my issues mutation (#1753)
* fix: my issues mutation

* fix: activity message and icon return value
2023-08-01 18:40:04 +05:30
Aaryan Khandelwal
d22e4b8212 fix: profile activity workspace slug (#1752) 2023-08-01 18:38:33 +05:30
Anmol Singh Bhatia
0e0e09c4fd style: profile dropdown updated (#1751) 2023-08-01 18:25:13 +05:30
Aaryan Khandelwal
a8816ef473 refactor: issue activity component (#1749) 2023-08-01 17:07:11 +05:30
Anmol Singh Bhatia
d315a24c1c style: primary color variable added in global (#1748) 2023-08-01 17:04:23 +05:30
Nikhil
e73a4bef4e chore: issue and project details in activity (#1747)
* chore: issue and project details in activity

* dev: update capture log
2023-08-01 17:03:19 +05:30
Aaryan Khandelwal
d9339b8f8e Merge pull request #1729 from makeplane/develop
promote: develop to stage-release
2023-08-01 15:46:56 +05:30
Dakshesh Jain
a66a0680df fix: showing alert on error while deleting workspace member or invited member (#1746)
style: showing 'Leave' for current user
2023-08-01 15:32:42 +05:30
Anmol Singh Bhatia
98c7453741 style: view dropdown (#1742) 2023-08-01 14:16:43 +05:30
Nikhil
1a5faca77c chore: show created by empty for viewers and guests (#1740)
* chore: show created by empty for viewers and guests

* dev: return empty queryset
2023-08-01 14:16:21 +05:30
Nikhil
6e7fa1a39c chore: project create to return sort order (#1738)
* chore: project create retun sort order

* chore: project create return sort order
2023-08-01 14:15:40 +05:30
Nikhil
7a6e742362 dev: fix migrations (#1735)
* dev: fix migrations

* dev: migrations for issue comment reactions and preference and cover image fields
2023-08-01 14:15:09 +05:30
Anmol Singh Bhatia
8a9ff31009 style: sidebar project disclosure list open by default (#1744) 2023-08-01 14:13:42 +05:30
Dakshesh Jain
d310b8f86f style: style if user doesn't have profile pic (#1745) 2023-08-01 14:12:57 +05:30
Nikhil
4e297d92f3 chore: update empty states, fix: delete issue modal (#1743)
* chore: update empty states

* fix: delete issue modal

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-08-01 13:58:58 +05:30
Anmol Singh Bhatia
e48147f87e style: create project modal (#1741) 2023-08-01 13:34:54 +05:30
Aaryan Khandelwal
85a7a7df2b chore: profile dropdown in the sidebar (#1737)
* chore: profile dropdown in the sidebar

* style: update spacing and font sizes
2023-08-01 13:31:16 +05:30
Dakshesh Jain
92b22dc99e style: showing 'Created by me' tab to all user (#1739)
* style: showing 'Created by me' tab to all user

* refactor: removed unnecessary imports
2023-08-01 13:30:51 +05:30
Aaryan Khandelwal
cb4d294608 style: sidebar projects design (#1736)
* chore: disclosure menu for sidebar projects

* fix: projects list spacing

* style: new design
2023-08-01 12:24:34 +05:30
Aaryan Khandelwal
df8504e6f7 fix: issue redirection (#1733) 2023-08-01 11:22:47 +05:30
Dakshesh Jain
7287c27b73 refactor: changed per_page to 30 (#1734) 2023-08-01 11:19:06 +05:30
Nikhil
cc2e6182b6 feat: user project sorting (#1719)
* feat: user project sorting

* dev: migration typo fix and query member fix

* feat: project member sort order update

* fix: project sorting per members
2023-07-31 18:12:02 +05:30
Nikhil
40fd7790eb fix: my issues duplication (#1726) 2023-07-31 18:11:46 +05:30
Aaryan Khandelwal
d733fb92cd fix: show project drag handle only when uncollapsed (#1727)
* fix: show project drag handle only when uncollapsed

* chore: fetch profile issues auth

* chore: update theme colors

* chore: update profile page redirection
2023-07-31 18:11:25 +05:30
Nikhil
1ae78e55c9 chore: profile page permission (#1728)
* chore: profile page permission

* dev: change the default type
2023-07-31 18:04:01 +05:30
Nikhil
ff3f1897bc feat: user cycle stats (#1723)
* feat: user cycle stats

* dev: revert capture exception
2023-07-31 17:49:07 +05:30
Sai Phanindra
f42f2465a9 Changed alt text for badges in Readme (#1686) 2023-07-31 17:25:37 +05:30
Aaryan Khandelwal
7ad0466d65 refactor: new onboarding workflow (#1724)
* refactor: new onboarding workflow

* refactor: new onboarding workflow
2023-07-31 17:23:49 +05:30
Anmol Singh Bhatia
e8f748a67d style: responsive title (#1683)
* style: responsive issue title added

* style: responsive breadcrumbs and app-header layout

* style: breadcrumbs styling

* fix: app header dropdown issue and limit app header title to 32 characters
2023-07-31 17:22:48 +05:30
Dakshesh Jain
81b1405448 refactor: moved mutate to 'finally' block (#1722)
* refactor: moved mutate to 'finally' block

fix: content for success

* fix: invited -> added
2023-07-31 17:21:37 +05:30
Anmol Singh Bhatia
98d9763f8e feat: sidebar project ordering functionality added (#1725) 2023-07-31 17:10:23 +05:30
Dakshesh Jain
c9498fa54d fix: workspace member invitation mutate (#1721)
* fix: workspace member invitation mutate

* fix: mutate on finally
2023-07-31 16:58:45 +05:30
Aaryan Khandelwal
0586d30a33 style: profile page responsiveness added (#1710)
* refactor: folder structure

* style: mobile responsiveness added

* chore: add user profile redirection

* chore: profile page authorization
2023-07-31 16:57:28 +05:30
Dakshesh Jain
406b323e8e fix: image upload accepting non-image format (#1720)
* fix: image upload accepting non-image format

* style: showing all the valid for image upload
2023-07-31 14:17:51 +05:30
Anmol Singh Bhatia
47838a506a fix: workspace name validation added (#1702) 2023-07-31 12:03:16 +05:30
Ankur Singh
d9ce042dff handle email invitation urls in outlook clients properly (#1671)
Co-authored-by: Ankur Singh <ankur.singh@epfl.ch>
2023-07-31 11:48:29 +05:30
Dakshesh Jain
4fb11cb388 fix: project cover image upload (#1704)
* fix: popover close on image upload

* fix: removed comments
2023-07-31 11:47:45 +05:30
Anmol Singh Bhatia
6769d1139e feat: project user preference for pages (#1673)
* feat: project user preference for pages

* feat: page block description improvement

* fix: create block input box
2023-07-31 11:47:22 +05:30
Anmol Singh Bhatia
89e7975821 style: ui improvements (#1699)
* style: sibling issues ui

* style: view dropdown
2023-07-31 11:45:10 +05:30
Nikhil
89bf24bd64 Merge pull request #1718 from makeplane/stage-release
dev: equate stage-release and develop branch
2023-07-31 11:42:18 +05:30
Nikhil
922735e5f2 feat: issue and comments reaction (#1674)
* dev: initialize issue reactions

* dev: issue reactions

* dev: comment reactions and update in urls

* dev: reactions in issue and comment list

* dev: reaction filtering

* dev: comment reaction lite serializer

* fix: reaction delete endpoint query
2023-07-31 10:42:17 +05:30
Nikhil
ed75163ec4 chore: project preferences (#1669) 2023-07-31 10:42:00 +05:30
Nikhil
8e0124be91 feat: project ordering (#1701)
* dev: project ordering

* dev: add ordering for projects list
2023-07-31 10:41:25 +05:30
Anmol Singh Bhatia
c98edd4a91 style: reactions ui improvement (#1705) 2023-07-30 02:08:52 +05:30
Dakshesh Jain
35bb71303e refactor: fetching notification only when popover is open (#1706) 2023-07-30 02:05:30 +05:30
Aaryan Khandelwal
e5a3bec28c Merge pull request #1709 from makeplane/stage-release
promote: stage-release to master
2023-07-28 19:47:04 +05:30
Aaryan Khandelwal
30054f71a8 Merge pull request #1708 from makeplane/fix/google_authentication
fix: google not accepting width as string
2023-07-28 19:35:10 +05:30
Dakshesh Jain
f40eb1add1 fix: google not accepting width as string 2023-07-28 19:21:55 +05:30
Nikhil
e0affa21c4 feat: profile page endpoints (#1682)
* dev: profile page endpoints

* dev: workspace projects endpoint

* dev: user profile page endpoints

* dev: profile page endpoints

* dev: project filters

* dev: fix priority distribution

* dev: issue subscriptions

* dev: issue priority distribution and issue activity api optimization

* dev: user data in profile endpoints

* dev: profile page data

* dev: project list endpoint

* dev: project emojis

* dev: capture exception

* dev: update workspace user profile urls

* dev: user profile endpoints rename and activity filter

* dev: fix subscriber issues filtering
2023-07-28 14:35:45 +05:30
Nikhil
b14c70df71 fix: workspace member only admin delete (#1700) 2023-07-28 14:29:40 +05:30
Nikhil
4c54ca5494 dev: revert issue filters query parameters (#1703) 2023-07-28 14:29:05 +05:30
Aaryan Khandelwal
10f145f85c feat: user profile analytics, views and filters (#1698)
* feat: user profile overview

* chore: profile sidebar designed

* feat: user issues filters and view options

* refactor: filters

* refactor: mutation logic

* fix: percentage calculation logic and sidebar shadow
2023-07-28 13:39:42 +05:30
Dakshesh Jain
8930840a76 style: text color & position (#1692)
* feat: developed reaction selector component

* feat add reaction on issue & issue comment

refactor: reaction selector component, made hooks to abstracted reaction logic & state by making custom hook

* fix: emoji.helper.tsx function

* refactor: reaction not working on inbox issue

* fix: user not been passed to create/delete function

* style: text position & color
2023-07-28 10:46:35 +05:30
Vamsi Kurama
e930f8cc7b Merge pull request #1697 from makeplane/stage-release
promote: stage-release to master
2023-07-28 00:55:32 +05:30
Vihar Kurama
865698bcb4 Merge pull request #1696 from makeplane/remove-events
chore: remove events
2023-07-28 00:33:12 +05:30
Aaryan Khandelwal
a3678b490a chore: update .env.example 2023-07-28 00:32:34 +05:30
Aaryan Khandelwal
5117859142 chore: update .env.example 2023-07-28 00:29:47 +05:30
Aaryan Khandelwal
05c923a97f chore: remove events 2023-07-28 00:26:35 +05:30
Aaryan Khandelwal
bedc3ab5a1 fix: create view form (#1691) 2023-07-27 21:38:16 +05:30
Dakshesh Jain
0cc4468091 feat: issue & comment reaction (#1690)
* feat: developed reaction selector component

* feat add reaction on issue & issue comment

refactor: reaction selector component, made hooks to abstracted reaction logic & state by making custom hook

* fix: emoji.helper.tsx function

* refactor: reaction not working on inbox issue
2023-07-27 18:55:03 +05:30
Nikhil
5cfea3948f fix: issue filters (#1688) 2023-07-27 17:30:39 +05:30
Nikhil
c947a6dd64 fix: cycles n+1 (#1689) 2023-07-27 17:30:00 +05:30
Aaryan Khandelwal
c54b8b9a15 refactor: filters list component (#1687)
* refactor: filters list component

* fix: build error
2023-07-27 00:57:12 +05:30
Dakshesh Jain
0b86080166 fix: displaying API error for AI response (#1677) 2023-07-26 23:59:34 +05:30
Dakshesh Jain
0e352b7bcb style: padding bottom no load more (#1678) 2023-07-26 23:59:05 +05:30
Dakshesh Jain
bc8be73d6c fix: invalid isOpen flag (#1676) 2023-07-26 23:58:40 +05:30
Aaryan Khandelwal
d6f3c2515a fix: fetch states only when the dropdown is opened (#1684) 2023-07-26 23:20:44 +05:30
Nikhil
fd9dcfa2ec feat: my issues filtering (#1666)
* feat: my issues filtering

* dev: migrations

* dev: remove state list endpoint

* dev: state group filtering
2023-07-26 17:52:35 +05:30
Dakshesh Jain
39274fd5fa fix: show-sub issue filter is true now by default (#1679) 2023-07-26 17:52:03 +05:30
Aaryan Khandelwal
3d7fe40035 feat: my issues view layouts and filters, refactor: issue views (#1681)
* refactor: issue views and my issues

* chore: update view dropdown options

* refactor: render emoji function

* refactor: api calss

* fix: build errors

* fix: fetch states only when dropdown is opened

* chore: my issues dnd

* fix: build errors

* refactor: folder structure
2023-07-26 17:51:26 +05:30
Aaryan Khandelwal
ec62308195 refactor: cmdk (#1680)
* chore: add project identifier to each result item

* refactor: cmdk code structure

* refactor: folder structure
2023-07-26 15:12:00 +05:30
Dakshesh Jain
9c28011ea5 refactor: notification pagination & made context for handling functions related to notification (#1654)
* refactor: add pagination and notification context

* refactor: moved header & snooze option to their own files

added check before toUpperCase function
2023-07-26 12:02:14 +05:30
Dakshesh Jain
10059b2150 feat: upload cover image for project (#1668) 2023-07-26 12:01:33 +05:30
Anmol Singh Bhatia
6fe99c7f3e fix: custom search select query fix (#1610) 2023-07-25 16:08:11 +05:30
Anmol Singh Bhatia
2229d8d828 fix: link validation fix (#1645)
* fix: link validation fix

* fix: build fix and code refactor

* fix: build fix

* chore: code refactor

* fix: link url input fix

* chore: link type updated

* fix: build fix
2023-07-25 15:43:47 +05:30
Anmol Singh Bhatia
ad410d134f fix: project identifier validation (#1643)
* fix: project identifier validation

* feat: alphanumric identifier validation

* chore: code refactor

* refactor: project identifier change function

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-07-25 15:43:28 +05:30
Anmol Singh Bhatia
9b531aca47 feat: workspace member bulk invite (#1530)
* feat: workspace member bulk invite

* style: invite dropdown styling
2023-07-25 15:42:52 +05:30
Nikhil
2bb842367f fix: pages n plus 1 (#1651) 2023-07-25 14:23:58 +05:30
Nikhil
916fca53ac chore: project identifier for all the search items and take project id as query params (#1663) 2023-07-25 14:23:41 +05:30
Nikhil
7763cca9a2 fix: email magic sign in integrity error (#1662) 2023-07-25 14:23:26 +05:30
Nikhil
3ad3cc77f9 fix: handle model save error in issue activity (#1661) 2023-07-25 14:23:10 +05:30
Nikhil
998fab80b5 feat: project preferences (#1652) 2023-07-25 14:22:54 +05:30
Nikhil
679c97bbe3 fix: make title as optional for issue links (#1641) 2023-07-25 14:22:38 +05:30
Aaryan Khandelwal
c87d70195d refactor: command k and enable workspace level search (#1664)
* refactor: command k and enable workspace level search

* fix: global level search
2023-07-25 13:52:21 +05:30
Dakshesh Jain
c2327fa538 feat: show sub-issue on list-view (#1665) 2023-07-25 13:09:38 +05:30
Anmol Singh Bhatia
bc076e69f7 style: issue label ui updated (#1653)
* style: issue label ui updated

* chore: code refactor
2023-07-25 12:07:16 +05:30
Rhea Jain
1db9030f20 Update README.md (#1659) 2023-07-24 21:19:31 +05:30
Nikhil
737ac33d5d chore: project issue link activity (#1639)
* chore: project issue link activity

* dev: fix delete activity
2023-07-24 17:41:04 +05:30
Nikhil
fd17c249fd chore: ability to comment for guests and viewers (#1650) 2023-07-24 17:40:26 +05:30
Nikhil
afce027bf3 chore: global search endpoint for workspace (#1649)
* chore: global search endpoint

* chore: global search endpoitnt for workspace search
2023-07-24 17:39:29 +05:30
Aaryan Khandelwal
6db1db55e9 fix: create issue modal restting (#1647) 2023-07-24 14:39:47 +05:30
Nikhil
08a025f67c fix: notification select related fields (#1646) 2023-07-24 14:39:25 +05:30
Aaryan Khandelwal
8a2cc6f919 fix: remove issue link activity (#1644) 2023-07-24 13:57:23 +05:30
Aaryan Khandelwal
29b04bb3ef chore: increase project identifier max length (#1638) 2023-07-24 12:57:05 +05:30
Aaryan Khandelwal
f3b09a13b8 chore: set all issue properties as true by default (#1640) 2023-07-24 12:56:27 +05:30
Nikhil
e83ef7332d fix: issue create update n+1 and issue activity get n+1 (#1606)
* fix: issue create update n+1 and issue activity get n+1

* dev: notifications n+1
2023-07-24 12:23:34 +05:30
Nikhil
8ff834c328 chore: return total members, cycle and modules (#1637) 2023-07-24 12:23:04 +05:30
Nikhil
4ee161bae2 chore: project identifiers (#1636) 2023-07-24 12:19:11 +05:30
Nikhil
27402b52b6 fix: issue activity for attachments (#1626)
* fix: issue activity for attachments

* fix: issue activity assignees
2023-07-24 12:17:41 +05:30
Nikhil
479dfc17f5 feat: notification pagination (#1580) 2023-07-24 12:10:21 +05:30
Nikhil
8e70a036b7 chore: add project lead as project member (#1627)
* chore: add project lead as project member

* fix: project member lead create
2023-07-24 12:09:32 +05:30
Nikhil
73b38f4db9 feat: cross project issue linking (#1609)
* dev: sub issue listing

* feat: cross project issue linking

* dev: project search

* dev: workspace search logic

* dev: return state and project details for parent issues

* dev: issue state flat serializer

* dev: id for lite serializer

* dev: project name in for the response issues

* dev: issue cross project

* dev: issue project identifiers

* dev: blocked and blocked by activity
2023-07-24 12:08:47 +05:30
Ikko Eltociear Ashimine
e357283789 chore: fix typo in replace-env-vars.sh (#1632)
peform -> perform
2023-07-24 12:08:29 +05:30
Aaryan Khandelwal
2ce7914b7a style: new cycles list page design with empty states (#1633) 2023-07-24 11:32:59 +05:30
Aaryan Khandelwal
fe60771943 fix: create cycle modal (#1631)
* fix: cycle date select in the modal

* chore: update remove assignee issue activity
2023-07-23 22:54:17 +05:30
Aaryan Khandelwal
464c13fcd0 fix: issue parent activity (#1629) 2023-07-23 22:14:41 +05:30
Aaryan Khandelwal
a7b5ad55ab style: create project modal (#1628)
* style: create project modal

* fix: build error

* fix: modal width
2023-07-23 22:14:26 +05:30
Aaryan Khandelwal
ccbcfecc6d fix: form not submitting on enter (#1613) 2023-07-23 22:13:09 +05:30
Aaryan Khandelwal
7669ee8755 fix: project select not working on the create issue modal (#1608) 2023-07-23 22:12:13 +05:30
Aaryan Khandelwal
fdb7da4d45 chore: show proper error messages on profile form submit (#1611) 2023-07-23 22:10:40 +05:30
Aaryan Khandelwal
ff6690afd2 chore: workspace level toggle (#1625) 2023-07-23 15:11:28 +05:30
Aaryan Khandelwal
f9c3f02d15 refactor: issue activity message logic (#1614) 2023-07-23 14:38:07 +05:30
Aaryan Khandelwal
6c2600efa7 feat: cross-project issue linking (#1612)
* feat: cross project issue linking

* fix: remove parent issue mutation

* fix: build error
2023-07-22 14:53:48 +05:30
Aaryan Khandelwal
0e5c0fe31e refactor: issue search (#1607) 2023-07-21 14:29:06 +05:30
Anmol Singh Bhatia
4424d67073 style: ui improvements (#1605)
* style: automation setting border

* style: sidebar ui improvement
2023-07-21 12:37:48 +05:30
guru_sainath
26eb3b59ce Merge pull request #1604 from makeplane/stage-release
promote: stage-release to master
2023-07-20 22:45:17 +05:30
guru_sainath
4d909fbef3 Merge pull request #1603 from makeplane/develop
promote: develop to stage-release
2023-07-20 22:42:28 +05:30
guru_sainath
89210accae Merge pull request #1602 from makeplane/dev/monitoring_settings
dev: add server monitoring configuration
2023-07-20 22:40:08 +05:30
pablohashescobar
7c5c02bba6 dev: add server monitoring configuration 2023-07-20 22:34:47 +05:30
Vamsi Kurama
11faf3f810 Merge pull request #1600 from makeplane/stage-release
promote: stage-release to master
2023-07-20 19:36:43 +05:30
Aaryan Khandelwal
30ea1adf61 Merge pull request #1597 from makeplane/develop
promote: develop to stage-release
2023-07-20 19:32:04 +05:30
Dakshesh Jain
546aa40aa3 fix: un-read count not mutating (#1598)
* refactor: height of popover & api fetch call

* fix: notification subscribe endpoint

* fix: un-read count not mutating
2023-07-20 19:15:13 +05:30
Nikhil
78669363b1 fix: restrict notifications for created by when the actor is same (#1596) 2023-07-20 18:53:02 +05:30
guru_sainath
bca749986a Merge pull request #1595 from makeplane/develop
promote: develop to stage-release
2023-07-20 18:11:18 +05:30
gurusainath
229938114d Merge branch 'develop' of gurusainath:makeplane/plane into develop 2023-07-20 17:25:31 +05:30
gurusainath
c5e418ab47 Merge branch 'stage-release' of gurusainath:makeplane/plane into develop 2023-07-20 17:25:00 +05:30
Aaryan Khandelwal
ecdd1f1d03 promote: develop to stage-release (#1594)
* fix: onboarding invitations overflow (#1575)

* fix: onboarding invitations overflow

* fix: user avatar in the notification card

* style: update graph grid color

* fix: no 'Create by me' label coming up (#1573)

* feat: added new issue subscriber table

* dev: notification model

* feat: added CRUD operation for issue subscriber

* Revert "feat: added CRUD operation for issue subscriber"

This reverts commit b22e062576.

* feat: added CRUD operation for issue subscriber

* dev: notification models and operations

* dev: remove delete endpoint response data

* dev: notification endpoints and fix bg worker for saving notifications

* feat: added list and unsubscribe function in issue subscriber

* dev: filter by snoozed and response update for list and permissions

* dev: update issue notifications

* dev: notification  segregation

* dev: update notifications

* dev: notification filtering

* dev: add issue name in notifications

* dev: notification new endpoints

* fix: pushing local settings

* feat: notification workflow setup and made basic UI

* style: improved UX with toast alerts and other interactions

refactor: changed classnames according to new theme structure, changed all icons to material icons

* feat: showing un-read notification count

* feat: not showing 'subscribe' button on issue created by user & assigned to user

not showing 'Create by you' for view & guest of the workspace

* fix: 'read' -> 'unread' heading, my issue wrong filter

* feat: made snooze dropdown & modal

feat: switched to calendar

* fix: minor ui fixes

* feat: snooze modal date/time select

* fix: params for read/un-read notification

* style: snooze notification modal

* fix: no label for 'Create by me'

* fix: no label for 'Create by me'

* fix: removed console log

* fix: tooltip going behind popover

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>

* style: tooltip on notification header actions (#1577)

* style: tooltip on notification header

* chore: update tooltip content

---------

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

* fix: user migrations for back population (#1578)

* fix: total notifications count (#1579)

* fix: notification card (#1583)

* feat: add new icons package (#1586)

* feat: add material icons package

* chore: replace issue view icons

* chore: notification ordering (#1584)

* fix: uuid error when cycle and module updates (#1585)

* refactor: height of popover & api fetch call (#1587)

* fix: snooze dropdown overflow (#1588)

* fix: notification subscribe endpoint (#1593)

* refactor: height of popover & api fetch call

* fix: notification subscribe endpoint

* chore: notification empty state overflow (#1592)

* chore: notification empty state overflow

* fix: white logo

* fix: custom theme default values

* fix: custom theme default values

* fix: issues count to remove archived issues (#1591)

* dev: background migration for user custom themes (#1590)

---------

Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
2023-07-20 17:24:17 +05:30
Nikhil
e687cd6f6a dev: background migration for user custom themes (#1590) 2023-07-20 16:59:09 +05:30
Nikhil
9b6721790f fix: issues count to remove archived issues (#1591) 2023-07-20 16:58:34 +05:30
gurusainath
05df65577a Merge branch 'stage-release' of gurusainath:makeplane/plane into develop 2023-07-20 16:54:40 +05:30
Aaryan Khandelwal
52d21b9dda chore: notification empty state overflow (#1592)
* chore: notification empty state overflow

* fix: white logo

* fix: custom theme default values

* fix: custom theme default values
2023-07-20 16:51:00 +05:30
Dakshesh Jain
51f10d5f36 fix: notification subscribe endpoint (#1593)
* refactor: height of popover & api fetch call

* fix: notification subscribe endpoint
2023-07-20 16:35:18 +05:30
Aaryan Khandelwal
9275e6f373 promote: develop to stage-release (#1589)
* fix: onboarding invitations overflow (#1575)

* fix: onboarding invitations overflow

* fix: user avatar in the notification card

* style: update graph grid color

* fix: no 'Create by me' label coming up (#1573)

* feat: added new issue subscriber table

* dev: notification model

* feat: added CRUD operation for issue subscriber

* Revert "feat: added CRUD operation for issue subscriber"

This reverts commit b22e062576.

* feat: added CRUD operation for issue subscriber

* dev: notification models and operations

* dev: remove delete endpoint response data

* dev: notification endpoints and fix bg worker for saving notifications

* feat: added list and unsubscribe function in issue subscriber

* dev: filter by snoozed and response update for list and permissions

* dev: update issue notifications

* dev: notification  segregation

* dev: update notifications

* dev: notification filtering

* dev: add issue name in notifications

* dev: notification new endpoints

* fix: pushing local settings

* feat: notification workflow setup and made basic UI

* style: improved UX with toast alerts and other interactions

refactor: changed classnames according to new theme structure, changed all icons to material icons

* feat: showing un-read notification count

* feat: not showing 'subscribe' button on issue created by user & assigned to user

not showing 'Create by you' for view & guest of the workspace

* fix: 'read' -> 'unread' heading, my issue wrong filter

* feat: made snooze dropdown & modal

feat: switched to calendar

* fix: minor ui fixes

* feat: snooze modal date/time select

* fix: params for read/un-read notification

* style: snooze notification modal

* fix: no label for 'Create by me'

* fix: no label for 'Create by me'

* fix: removed console log

* fix: tooltip going behind popover

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>

* style: tooltip on notification header actions (#1577)

* style: tooltip on notification header

* chore: update tooltip content

---------

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

* fix: user migrations for back population (#1578)

* fix: total notifications count (#1579)

* fix: notification card (#1583)

* feat: add new icons package (#1586)

* feat: add material icons package

* chore: replace issue view icons

* chore: notification ordering (#1584)

* fix: uuid error when cycle and module updates (#1585)

* refactor: height of popover & api fetch call (#1587)

* fix: snooze dropdown overflow (#1588)

---------

Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
2023-07-20 15:14:57 +05:30
Aaryan Khandelwal
4aef8c2242 fix: snooze dropdown overflow (#1588) 2023-07-20 14:49:30 +05:30
Dakshesh Jain
780573dadd refactor: height of popover & api fetch call (#1587) 2023-07-20 14:33:24 +05:30
Nikhil
5e625ab132 fix: uuid error when cycle and module updates (#1585) 2023-07-20 14:18:28 +05:30
Nikhil
34123681cf chore: notification ordering (#1584) 2023-07-20 14:18:06 +05:30
Aaryan Khandelwal
c72ff782ac feat: add new icons package (#1586)
* feat: add material icons package

* chore: replace issue view icons
2023-07-20 14:17:21 +05:30
Aaryan Khandelwal
6eb72507a5 fix: notification card (#1583) 2023-07-20 10:52:52 +05:30
Aaryan Khandelwal
26b18b431b fix: total notifications count (#1579) 2023-07-19 20:37:40 +05:30
Nikhil
1bae9289f5 fix: user migrations for back population (#1578) 2023-07-19 20:06:12 +05:30
Dakshesh Jain
5c5bcb33e3 style: tooltip on notification header actions (#1577)
* style: tooltip on notification header

* chore: update tooltip content

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-07-19 18:42:32 +05:30
Dakshesh Jain
bed5f76082 fix: no 'Create by me' label coming up (#1573)
* feat: added new issue subscriber table

* dev: notification model

* feat: added CRUD operation for issue subscriber

* Revert "feat: added CRUD operation for issue subscriber"

This reverts commit b22e062576.

* feat: added CRUD operation for issue subscriber

* dev: notification models and operations

* dev: remove delete endpoint response data

* dev: notification endpoints and fix bg worker for saving notifications

* feat: added list and unsubscribe function in issue subscriber

* dev: filter by snoozed and response update for list and permissions

* dev: update issue notifications

* dev: notification  segregation

* dev: update notifications

* dev: notification filtering

* dev: add issue name in notifications

* dev: notification new endpoints

* fix: pushing local settings

* feat: notification workflow setup and made basic UI

* style: improved UX with toast alerts and other interactions

refactor: changed classnames according to new theme structure, changed all icons to material icons

* feat: showing un-read notification count

* feat: not showing 'subscribe' button on issue created by user & assigned to user

not showing 'Create by you' for view & guest of the workspace

* fix: 'read' -> 'unread' heading, my issue wrong filter

* feat: made snooze dropdown & modal

feat: switched to calendar

* fix: minor ui fixes

* feat: snooze modal date/time select

* fix: params for read/un-read notification

* style: snooze notification modal

* fix: no label for 'Create by me'

* fix: no label for 'Create by me'

* fix: removed console log

* fix: tooltip going behind popover

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-07-19 17:40:40 +05:30
Aaryan Khandelwal
124c2f772e fix: onboarding invitations overflow (#1575)
* fix: onboarding invitations overflow

* fix: user avatar in the notification card

* style: update graph grid color
2023-07-19 17:09:53 +05:30
Vihar Kurama
b38898753f Merge pull request #1570 from makeplane/develop
promote: develop to stage-release
2023-07-19 16:07:43 +05:30
guru_sainath
86a120f11e Merge branch 'stage-release' into develop 2023-07-19 16:05:13 +05:30
Rhea Jain
da603dc3f8 Update README.md (#1543) 2023-07-19 15:28:01 +05:30
Nikhil
2f3970f641 feat: beat worker for configuration (#1571) 2023-07-19 15:25:33 +05:30
Nikhil
d759438ebd fix: issue automation (#1569) 2023-07-19 15:08:41 +05:30
Nikhil
0102f1d693 fix: psycopg errors (#1568) 2023-07-19 15:07:54 +05:30
Dakshesh Jain
53e443d816 feat: notifications (#1566)
* feat: added new issue subscriber table

* dev: notification model

* feat: added CRUD operation for issue subscriber

* Revert "feat: added CRUD operation for issue subscriber"

This reverts commit b22e062576.

* feat: added CRUD operation for issue subscriber

* dev: notification models and operations

* dev: remove delete endpoint response data

* dev: notification endpoints and fix bg worker for saving notifications

* feat: added list and unsubscribe function in issue subscriber

* dev: filter by snoozed and response update for list and permissions

* dev: update issue notifications

* dev: notification  segregation

* dev: update notifications

* dev: notification filtering

* dev: add issue name in notifications

* dev: notification new endpoints

* fix: pushing local settings

* feat: notification workflow setup and made basic UI

* style: improved UX with toast alerts and other interactions

refactor: changed classnames according to new theme structure, changed all icons to material icons

* feat: showing un-read notification count

* feat: not showing 'subscribe' button on issue created by user & assigned to user

not showing 'Create by you' for view & guest of the workspace

* fix: 'read' -> 'unread' heading, my issue wrong filter

* feat: made snooze dropdown & modal

feat: switched to calendar

* fix: minor ui fixes

* feat: snooze modal date/time select

* fix: params for read/un-read notification

* style: snooze notification modal

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-07-19 14:44:04 +05:30
Nikhil
98b9957753 fix: issue created notification (#1553)
* fix: issue created notification

* chore: my issues assigned notifications

* dev: fix read at notification
2023-07-19 14:31:45 +05:30
Nikhil
509af4662d dev: migrations (#1561) 2023-07-19 14:31:07 +05:30
Aaryan Khandelwal
d1f2a819f5 fix: update border colors on theme switch (#1565) 2023-07-19 13:53:22 +05:30
Aaryan Khandelwal
a42bff675b fix: archived issue details page overflow, restore button loading (#1564) 2023-07-19 13:29:08 +05:30
Aaryan Khandelwal
c71a2137e6 fix: scope and demand line graph y axis values (#1563) 2023-07-19 13:13:23 +05:30
Rhea Jain
5e1f0a2604 fixes as per consistency (#1562) 2023-07-19 13:00:11 +05:30
Aaryan Khandelwal
ccab382d7d chore: add dashboard navbar (#1560) 2023-07-19 12:16:39 +05:30
Aaryan Khandelwal
a7aa78a349 chore: high contrast theming (#1559)
* fix: archived issues empty state

* chore: update high contrast theme colors
2023-07-19 11:47:41 +05:30
Aaryan Khandelwal
5ae963c451 fix: tour sidebar icons, auth pages scroll (#1555)
* fix: tour sidebar icons, menu button word wrap

* chore: change theme on sign out

* fix: auth pages scroll y-padding
2023-07-18 19:02:33 +05:30
Dakshesh Jain
07c097c9ad style: different style for archive & project issues (#1552)
* fix: same empty state coming for all issue list related UI

* style: different style for archive & project  issues
2023-07-18 18:58:36 +05:30
Aaryan Khandelwal
fc92d7d1a0 chore: hide issue properties if there are none (#1554) 2023-07-18 18:47:28 +05:30
Nikhil
9ba8f5c21f fix: cycle module notifications (#1536)
* chore: add triggered by details for notifications

* dev: update issue activity json to include extra fields

* dev: improve issue fetch
2023-07-18 15:59:58 +05:30
Aaryan Khandelwal
059b8c793a refactor: parent issue select (#1546)
* refactor: parent issue select

* fix: sibling issues list
2023-07-18 15:36:03 +05:30
Dakshesh Jain
93da220c4a fix: same empty state coming for all issue list related UI (#1547) 2023-07-18 15:28:12 +05:30
Aaryan Khandelwal
0feab162ff style: onboarding screens (#1539)
* fix: onboarding screen styling

* chore: minor styling fixes

* chore: disable buttons if form is invalid
2023-07-18 15:20:05 +05:30
Nikhil
55a1291b1d fix: inbox issue archival (#1538)
* chore: add triggered by details for notifications

* dev: update issue activity json to include extra fields

* dev: fix inboc issue archival

* dev: update the filter for closing issues
2023-07-18 15:10:20 +05:30
Nikhil
b12a00cf4a chore: default project state colors (#1540)
* chore: add triggered by details for notifications

* dev: update issue activity json to include extra fields

* chore: project create default state colors
2023-07-18 15:10:01 +05:30
Nikhil
52ee8c5615 chore: remove logger from gpt assistant (#1542)
* chore: add triggered by details for notifications

* dev: update issue activity json to include extra fields

* chore: remove logger from gpt assistant
2023-07-18 15:09:44 +05:30
Nikhil
68108c9fe9 fix: favorite permissions (#1549)
* chore: add triggered by details for notifications

* dev: update issue activity json to include extra fields

* dev: fix permissions for cycle and views
2023-07-18 15:09:18 +05:30
Aaryan Khandelwal
88fbe85087 fix: button and input heights (#1548) 2023-07-18 15:00:06 +05:30
Dakshesh Jain
9b423cea4b fix: create workspace valid (#1535)
show alert on-change rather then on-submit
2023-07-18 12:08:22 +05:30
Dakshesh Jain
9d891ecce1 fix: selecting label once create using modal (#1537) 2023-07-18 12:08:09 +05:30
Dakshesh Jain
16a7bd3bda feat: user issue notifications (#1523)
* feat: added new issue subscriber table

* dev: notification model

* feat: added CRUD operation for issue subscriber

* Revert "feat: added CRUD operation for issue subscriber"

This reverts commit b22e062576.

* feat: added CRUD operation for issue subscriber

* dev: notification models and operations

* dev: remove delete endpoint response data

* dev: notification endpoints and fix bg worker for saving notifications

* feat: added list and unsubscribe function in issue subscriber

* dev: filter by snoozed and response update for list and permissions

* dev: update issue notifications

* dev: notification  segregation

* dev: update notifications

* dev: notification filtering

* dev: add issue name in notifications

* dev: notification new endpoints

* fix: pushing local settings

* feat: notification workflow setup and made basic UI

* style: improved UX with toast alerts and other interactions

refactor: changed classnames according to new theme structure, changed all icons to material icons

* feat: showing un-read notification count

* feat: not showing 'subscribe' button on issue created by user & assigned to user

not showing 'Create by you' for view & guest of the workspace

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2023-07-18 12:07:55 +05:30
Dakshesh Jain
6e9f3971a5 style: empty state for archive issue (#1541) 2023-07-18 12:07:35 +05:30
Aaryan Khandelwal
dddfeb17b7 refactor: dropdowns (#1532) 2023-07-17 17:35:47 +05:30
Aaryan Khandelwal
538d67dbd9 fix: theming colors (#1533)
* chore: update border colors

* chore: loading screens bg color, custom theming default values

* chore: remove unnecessary images

* chore: update static colors

* chore: update old variable names

* chore: update issue activity icon colors

* chore: update user activity icon colors
2023-07-17 16:28:23 +05:30
Nikhil
090870b03e fix: created_by notifications (#1534)
* chore: add triggered by details for notifications

* dev: update issue activity json to include extra fields

* dev: remove unused imports and improve the filtering

* dev: fix unread filter

* dev: fix created_by none when updating the field
2023-07-17 16:09:30 +05:30
Aaryan Khandelwal
0a56a30ab2 fix: issue sidebar create label form (#1527)
* fix: issue sidebar create label form

* fix: issue details page overflow
2023-07-17 15:37:50 +05:30
Aaryan Khandelwal
8df1648329 fix: dashboard pie chart legends overflow (#1528) 2023-07-17 14:48:43 +05:30
Nikhil
b69c4b6b30 chore: notifications (#1515)
* chore: add triggered by details for notifications

* dev: update issue activity json to include extra fields

* dev: triggered_by details

* dev: add bot filtering

* dev: unread notification count endpoint

* dev: update endpoint to send count for all notification types
2023-07-17 13:17:48 +05:30
Nikhil
e0181342c0 fix: n+1s (#1514)
* dev: fix workspace n+1

* dev: trim down label details for issue state serializer
2023-07-17 13:17:34 +05:30
Nikhil
f9f8b5c3d9 chore: update bridge id to cycle and module id (#1513)
* chore: update bridge id to cycle and module id

* fix: typo
2023-07-17 13:17:11 +05:30
Aaryan Khandelwal
5fadf53580 style: auth screens (#1531)
* chore: invitations empty state

* style: new auth screens

* chore: update typography

* chore: update border colors

* chore: resend code text
2023-07-17 13:00:44 +05:30
Aaryan Khandelwal
da6ecd439c refactor: favorite projects fetch function, chore: update tooltip design (#1526)
* chore: update tooltip design

* fix: due date popup overflow

* fix: build error

* fix: build error

* chore: add key to map return value

* refactor: favorite projects sidebar list
2023-07-14 15:08:07 +05:30
pablohashescobar
7914bcf486 refactor: serializers to avoid getting child items (#1504)
* refactor: serializers to avoid getting child items

* dev: update issue state serializer to remove n+1 items
2023-07-14 12:01:38 +05:30
Aaryan Khandelwal
c9a5893c3f chore: update favorite projects endpoint (#1522)
* chore: upate favorite projects list endpoint

* chore: add project button on the sidebar

* refactor: sidebar favorite projects workflow
2023-07-13 19:44:53 +05:30
Anmol Singh Bhatia
7361657660 fix: issue delete redirection, chore: code refactor (#1521) 2023-07-13 19:00:43 +05:30
Anmol Singh Bhatia
60e96bcb72 style: app sidebar revamp (#1120)
* style: app sidebar, sidebar workspace dropdown and help section styling

* style: consistent  padding and spacing

* feat: material icon global component

* style: icons updated and tooltip added

* style: project list spacing and project name truncate

* style: sidebar padding and theming

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-07-13 18:35:43 +05:30
Anmol Singh Bhatia
3f3fb373cc fix: issue archive improvement, chore: code refactor (#1520)
* style: select month modal

* chore: automation setting dropdown updated ,style: month dropdown styling

* chore: restore issue alert message updated

* chore: archive issue fetching updated and code refactor

* fix: build fix
2023-07-13 17:04:24 +05:30
Bavisetti Narayan
a829e6fc40 chore: added is_favorite filter (#1518)
* fix: notification filtering

* dev: reverse logic for archive filtering

* dev: fix watching notification

* dev: read filter

* dev: update automatic issue archival and close to send notifications

* dev: update archival structure for auto close issues

* chore: added is_favorite filter

* fix: removed the unwanted filter

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2023-07-13 16:51:42 +05:30
Aaryan Khandelwal
864e592bc5 fix: onboarding screen design issues (#1517)
* fix: projects empty state flicker

* fix: tour images padding

* chore: add greeting icon on the dashboard

* chore: update email id font weight

* fix: placeholder color
2023-07-13 16:51:08 +05:30
pablohashescobar
411a661abd fix: magic code casing (#1519) 2023-07-13 16:49:37 +05:30
pablohashescobar
61ad6b9e0e chore: upgrade psycopg to 3 (#1507) 2023-07-13 13:51:02 +05:30
pablohashescobar
2ff49c93bd fix: notifications (#1498)
* fix: notification filtering

* dev: reverse logic for archive filtering

* dev: fix watching notification

* dev: read filter

* dev: update automatic issue archival and close to send notifications

* dev: update archival structure for auto close issues

* Closing of dialog when we click around the dialog (#1364)

* style: new empty states (#1497)

* fix: custom colors opacity

* chore: update text colors for dark mode

* fix: dropdown text colors, datepicker bg color

* chore: update text colors

* chore: updated primary bg color

* style: new empty states added

* refactor: empty state for issues

* style: empty state for estimates

* chore: update labels, estimates and integrations empty states

* fix: custom analytics sidebar

* fix: archival spelling mistake

* fix: updated the default state logic

* dev: fix key

---------

Co-authored-by: Khrystyna Derenivska <56432889+kblueberry@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2023-07-13 13:47:24 +05:30
Aaryan Khandelwal
120d06983d style: inbox (#1508) 2023-07-13 11:38:45 +05:30
Anmol Singh Bhatia
c9cbca5ec8 feat: auto-archive and auto-close (#1502)
* chore: issue archive services and types added

* chore: project type and constant updated

* feat: auto-close and auto-archive feature added

* feat: implement rendering of archived issues

* feat: implemented rendering of only list view for archived issues , chore: update types and services

* feat: implemented archive issue detail page and unarchive issue functionality , chore: refactor code

* feat: activity for issue archive and issue restore added

* fix: redirection and delete fix

* fix: merge conflict

* fix: restore issue redirection fix

* fix: disable modification of issue properties for archived issues, style: disable properties styling

* fix: hide empty group, switch to list view on redirct to archived issues

* fix: remove unnecessary header buttons for archived issue

* fix: auto-close dropdown fix
2023-07-13 11:34:37 +05:30
pablohashescobar
275942a246 feat: flag for onboarding tour completion (#1499)
* feat: flag for onboarding tour completion

* dev: boolean field

* dev: user tour completed endpoint

* dev: onboarding step json
2023-07-12 22:10:07 +05:30
Aaryan Khandelwal
a1b09fcbc6 style: onboarding screens (#1412)
* style: new onboarding screens

* chore: onboarding tour screens

* fix: build error

* fix: build errors

* style: default layout background

* chor: update user auth hook logic, style: new onboarding screens

* fix: component structure

* chore: tab responsiveness added

* fix: redirection logic

* style: welcome screens responsiveness

* chore: update workspace url input field

* style: mobile responsiveness added

* chore: complete onboarding workflow

* style: create workspace page design update

* style: workspace invitations page design update

* chore: update steps logic

* fix: step change logic

* style: tour steps
2023-07-12 19:55:08 +05:30
Aaryan Khandelwal
26f0e9da00 fix: add missing argument (#1506) 2023-07-12 17:55:58 +05:30
Aaryan Khandelwal
4a2057c0b3 style: new empty states (#1497)
* fix: custom colors opacity

* chore: update text colors for dark mode

* fix: dropdown text colors, datepicker bg color

* chore: update text colors

* chore: updated primary bg color

* style: new empty states added

* refactor: empty state for issues

* style: empty state for estimates

* chore: update labels, estimates and integrations empty states

* fix: custom analytics sidebar
2023-07-12 11:45:45 +05:30
Khrystyna Derenivska
82ff786666 Closing of dialog when we click around the dialog (#1364) 2023-07-12 11:39:40 +05:30
Bavisetti Narayan
5773ff2afd chore: updated old and new value in issue archival (#1500) 2023-07-11 19:15:39 +05:30
Ankur Singh
1403a536c1 feat: openai host (#1447)
* support custom openai api endpoints (for azure and local deployments)

* update openai python package and use new api format

* fix: project member list endpoint n+1 (#1458)

* chore: workspace char name and slug maximum length (#1453)

* fix: user invitation workflow for self hosted version (#1441)

* chore: due date filter (#1460)

* refactor: standardized date format throughout the platform (#1461)

* chore: due date filter (#965)

* chore: due date filter

* fix: deployment error

* chore: optimized code

* chore: created constants for due date

* chore: create seperated css file for react datepicker styling

* fix: due date filter

* chore: highlight selected option

* fix: merge conflicts

* fix: build error

* chore: date range selector validation

* fix: issue views overflow

* refactor: due date filter modal code

* refactor: multi level dropdown

* chore: due date filter select default value

---------

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

* fix: layout of tabs on Pages is not adaptable to mobile screens #1380 (#1400)

* fix: layout of tabs on Pages is not adaptable to mobile screens #1380

* fix: scrolling experience on page

* chore: update project members type (#1459)

* fix: state icon color on group titles (#1435)

* fix: workspace invitation delete for self hosted (#1475)

* chore: upgrade backend dependencies (#1479)

* chore: upgrade backend dependencies

* dev: update storage settings for self hosted version

* chore: project members endpoint to support bulk operations (#1464)

* chore: rename workspace company size to organization size (#1463)

* chore: rename workspace company size to organization size

* chore: make workspace organization size as required

* fix: static and media files storages (#1482)

* fix: emoji render function (#1484)

* fix: emoji render function

* fix: emoji render function

* feat: bulk invite for project (#1466)

* feat: bulk invite for project

* feat: members dropdown updated

* fix: error message added ,style: ui improvement

* feat: added add members button for scenarios with multiple members

* chore: updated watch to fields

* feat: created on and updated on column added in spreadsheet view (#1454)

* feat: created on and updated on column added in spreadsheet view

* fix: build fix

* refactor: simplify logic

---------

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

* fix: resolved overflow issue with longer state names (#1444)

* chore: update theming structure (#1422)

* chore: store various shades of accent color

* refactor: custom theme selector

* refactor: custom theme selector

* chore: update custom theme input labels

* fix: color generator function logic

* fix: accent color preloaded data

* chore: new theming structure

* chore: update shades calculation logic

* refactor: variable names

* chore: update color scheming

* chore: new color scheming

* refactor: themes folder structure

* chore: update classnames according to new variables

* Revert "chore: update classnames according to new variables"

This reverts commit 60a87453b21768167e37889e709c12287ca07b08.

* chore: remove temp file

* chore: update classnames according to the new theming structure (#1494)

* chore: store various shades of accent color

* refactor: custom theme selector

* refactor: custom theme selector

* chore: update custom theme input labels

* fix: color generator function logic

* fix: accent color preloaded data

* chore: new theming structure

* chore: update shades calculation logic

* refactor: variable names

* chore: update color scheming

* chore: new color scheming

* refactor: themes folder structure

* chore: update classnames to the new ones

* chore: update static colors

* chore: sidebar link colors

* chore: placeholder color

* chore: update border classnames

* chore:  environment variables for worker and api (#1492)

* feat: notifications (#1363)

* feat: added new issue subscriber table

* dev: notification model

* feat: added CRUD operation for issue subscriber

* Revert "feat: added CRUD operation for issue subscriber"

This reverts commit b22e062576.

* feat: added CRUD operation for issue subscriber

* dev: notification models and operations

* dev: remove delete endpoint response data

* dev: notification endpoints and fix bg worker for saving notifications

* feat: added list and unsubscribe function in issue subscriber

* dev: filter by snoozed and response update for list and permissions

* dev: update issue notifications

* dev: notification  segregation

* dev: update notifications

* dev: notification filtering

* dev: add issue name in notifications

* dev: notification new endpoints

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>

* fix: docker inconsistencies (#1493)

Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>

* feat: issue archival and close (#1474)

* chore: added issue archive using celery beat

* chore: changed the file name

* fix: created API and updated logic for achived-issues

* chore: added issue activity message

* chore: added the beat scheduler command

* feat: added unarchive issue functionality

* feat: auto issue close

* dev: refactor endpoints and issue archive activity

* dev: update manager for global filtering

* fix: added id in issue unarchive url

* dev: update auto close to include default close state

* fix: updated the list and retrive function

* fix: added the prefetch fields

* dev: update unarchive

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>

* fix: updated text and background colors (#1496)

* fix: custom colors opacity

* chore: update text colors for dark mode

* fix: dropdown text colors, datepicker bg color

* chore: update text colors

* chore: updated primary bg color

* feat: web waitlist modal integration (#1487)

* dev : Updating the limit of the issues in the sidebar and a weight list modal

* dev: integrated supabase and implemented web waitlist api endpoint

* dev : updated web pro weightlist request

* dev: rename typo

* dev: web waitlist endpoint update

* update: ui fixes

* fix: removed supabase from env.example

* chore: replaced supabase npm package to cdn

* chore: updated supabase req

* fix: Handled error status and error message.

---------

Co-authored-by: srinivaspendem <you@example.comsrinivaspendem2612@gmail.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>

* add openai host env in all places

---------

Co-authored-by: Ankur Singh <ankur.singh@epfl.ch>
Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: Kunal Vishwakarma <116634168+kunalv17@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: Chandan Jal <97095857+ChandanJal@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
Co-authored-by: Quadrubo <71718414+Quadrubo@users.noreply.github.com>
Co-authored-by: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: srinivas pendem <65014795+srinivaspendem@users.noreply.github.com>
Co-authored-by: srinivaspendem <you@example.comsrinivaspendem2612@gmail.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
2023-07-11 18:51:25 +05:30
srinivas pendem
eba2f3820a feat: web waitlist modal integration (#1487)
* dev : Updating the limit of the issues in the sidebar and a weight list modal

* dev: integrated supabase and implemented web waitlist api endpoint

* dev : updated web pro weightlist request

* dev: rename typo

* dev: web waitlist endpoint update

* update: ui fixes

* fix: removed supabase from env.example

* chore: replaced supabase npm package to cdn

* chore: updated supabase req

* fix: Handled error status and error message.

---------

Co-authored-by: srinivaspendem <you@example.comsrinivaspendem2612@gmail.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
2023-07-11 16:27:29 +05:30
Aaryan Khandelwal
253edebb93 fix: updated text and background colors (#1496)
* fix: custom colors opacity

* chore: update text colors for dark mode

* fix: dropdown text colors, datepicker bg color

* chore: update text colors

* chore: updated primary bg color
2023-07-11 15:18:47 +05:30
Bavisetti Narayan
7554988164 feat: issue archival and close (#1474)
* chore: added issue archive using celery beat

* chore: changed the file name

* fix: created API and updated logic for achived-issues

* chore: added issue activity message

* chore: added the beat scheduler command

* feat: added unarchive issue functionality

* feat: auto issue close

* dev: refactor endpoints and issue archive activity

* dev: update manager for global filtering

* fix: added id in issue unarchive url

* dev: update auto close to include default close state

* fix: updated the list and retrive function

* fix: added the prefetch fields

* dev: update unarchive

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2023-07-11 14:35:20 +05:30
Quadrubo
7087b1b5f2 fix: docker inconsistencies (#1493)
Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
2023-07-11 14:10:57 +05:30
pablohashescobar
abdb4a4778 feat: notifications (#1363)
* feat: added new issue subscriber table

* dev: notification model

* feat: added CRUD operation for issue subscriber

* Revert "feat: added CRUD operation for issue subscriber"

This reverts commit b22e062576.

* feat: added CRUD operation for issue subscriber

* dev: notification models and operations

* dev: remove delete endpoint response data

* dev: notification endpoints and fix bg worker for saving notifications

* feat: added list and unsubscribe function in issue subscriber

* dev: filter by snoozed and response update for list and permissions

* dev: update issue notifications

* dev: notification  segregation

* dev: update notifications

* dev: notification filtering

* dev: add issue name in notifications

* dev: notification new endpoints

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
2023-07-11 13:36:31 +05:30
pablohashescobar
ad1a074292 chore: environment variables for worker and api (#1492) 2023-07-11 13:30:55 +05:30
Aaryan Khandelwal
4c2cb2368a chore: update classnames according to the new theming structure (#1494)
* chore: store various shades of accent color

* refactor: custom theme selector

* refactor: custom theme selector

* chore: update custom theme input labels

* fix: color generator function logic

* fix: accent color preloaded data

* chore: new theming structure

* chore: update shades calculation logic

* refactor: variable names

* chore: update color scheming

* chore: new color scheming

* refactor: themes folder structure

* chore: update classnames to the new ones

* chore: update static colors

* chore: sidebar link colors

* chore: placeholder color

* chore: update border classnames
2023-07-10 12:47:00 +05:30
Aaryan Khandelwal
a14f8c281b chore: update theming structure (#1422)
* chore: store various shades of accent color

* refactor: custom theme selector

* refactor: custom theme selector

* chore: update custom theme input labels

* fix: color generator function logic

* fix: accent color preloaded data

* chore: new theming structure

* chore: update shades calculation logic

* refactor: variable names

* chore: update color scheming

* chore: new color scheming

* refactor: themes folder structure

* chore: update classnames according to new variables

* Revert "chore: update classnames according to new variables"

This reverts commit 60a87453b21768167e37889e709c12287ca07b08.

* chore: remove temp file
2023-07-10 12:25:32 +05:30
Anmol Singh Bhatia
d564ea8898 fix: resolved overflow issue with longer state names (#1444) 2023-07-07 14:11:33 +05:30
Anmol Singh Bhatia
7868bfa2b1 feat: created on and updated on column added in spreadsheet view (#1454)
* feat: created on and updated on column added in spreadsheet view

* fix: build fix

* refactor: simplify logic

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-07-07 14:11:07 +05:30
Anmol Singh Bhatia
353c85120f feat: bulk invite for project (#1466)
* feat: bulk invite for project

* feat: members dropdown updated

* fix: error message added ,style: ui improvement

* feat: added add members button for scenarios with multiple members

* chore: updated watch to fields
2023-07-07 14:10:36 +05:30
Aaryan Khandelwal
49f37e0346 fix: emoji render function (#1484)
* fix: emoji render function

* fix: emoji render function
2023-07-06 16:08:49 +05:30
pablohashescobar
3a2f4d55d7 fix: static and media files storages (#1482) 2023-07-06 15:30:34 +05:30
pablohashescobar
8443dfc9dd chore: rename workspace company size to organization size (#1463)
* chore: rename workspace company size to organization size

* chore: make workspace organization size as required
2023-07-06 11:58:47 +05:30
pablohashescobar
2f8a1dbe20 chore: project members endpoint to support bulk operations (#1464) 2023-07-06 11:58:35 +05:30
pablohashescobar
6bfeb6af34 chore: upgrade backend dependencies (#1479)
* chore: upgrade backend dependencies

* dev: update storage settings for self hosted version
2023-07-06 11:58:24 +05:30
pablohashescobar
fd3f6ab7a4 Merge pull request #1478 from makeplane/stage-release
promote: stage-release to master
2023-07-05 21:24:39 +05:30
pablohashescobar
d05d814efe chore: workspace invitation for self-hosted versions (#1477) 2023-07-05 21:21:31 +05:30
pablohashescobar
cc0701a823 fix: workspace invitation delete for self hosted (#1475) 2023-07-05 21:00:30 +05:30
Aaryan Khandelwal
3906503c1b fix: state icon color on group titles (#1435) 2023-07-05 00:56:39 +05:30
Aaryan Khandelwal
c3fe221e7a chore: update project members type (#1459) 2023-07-05 00:56:15 +05:30
Chandan Jal
e530533f9e fix: layout of tabs on Pages is not adaptable to mobile screens #1380 (#1400)
* fix: layout of tabs on Pages is not adaptable to mobile screens #1380

* fix: scrolling experience on page
2023-07-04 23:13:31 +05:30
Kunal Vishwakarma
4c3e2c252a chore: due date filter (#965)
* chore: due date filter

* fix: deployment error

* chore: optimized code

* chore: created constants for due date

* chore: create seperated css file for react datepicker styling

* fix: due date filter

* chore: highlight selected option

* fix: merge conflicts

* fix: build error

* chore: date range selector validation

* fix: issue views overflow

* refactor: due date filter modal code

* refactor: multi level dropdown

* chore: due date filter select default value

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-07-04 23:13:07 +05:30
Anmol Singh Bhatia
4ede04d72f refactor: standardized date format throughout the platform (#1461) 2023-07-04 18:19:19 +05:30
pablohashescobar
5a6fd0efdb chore: due date filter (#1460) 2023-07-04 16:48:59 +05:30
pablohashescobar
1a72a0dff4 fix: user invitation workflow for self hosted version (#1441) 2023-07-04 13:56:51 +05:30
pablohashescobar
e4ee6a5bfb chore: workspace char name and slug maximum length (#1453) 2023-07-04 13:54:48 +05:30
pablohashescobar
e23e9ccdbb fix: project member list endpoint n+1 (#1458) 2023-07-04 13:54:37 +05:30
guru_sainath
54a536e268 Merge pull request #1436 from makeplane/fix/bug_fix_and_ui_improvement 2023-07-03 13:57:15 +05:30
pablohashescobar
110eb39a51 dev: update packages to latest version (#1431) 2023-06-30 19:37:26 +05:30
anmolsinghbhatia
fc15da826b style: label dropdown empty state 2023-06-30 18:28:12 +05:30
Mark Percival
7e2caf65bb chore: Dry up docker compose environment variables (#1438)
* chore: Use docker compose extensions to dry up duplicate environment
variables between worker and api services.
See: https://docs.docker.com/compose/compose-file/11-extension/
2023-06-30 10:00:45 +05:30
tajkirkpatrick
d62dc25aa0 Add network timeout option to yarn install (#1382)
Inside of the Dockerfile.web, the yarn install command is susceptible to encountering a ECONNECT timeout error on aarch64 and ARM devices (such as a raspberry pi). This explicit overwrite of the default network timeout extends the window for low power CPU devices.
2023-06-30 09:53:44 +05:30
anmolsinghbhatia
32bf2ed56a fix: display properties fix 2023-06-29 18:37:19 +05:30
anmolsinghbhatia
ebf877b7fa fix: display properties fix 2023-06-29 18:33:44 +05:30
anmolsinghbhatia
d8eeb9e17a fix: cycle list item fix 2023-06-29 18:20:22 +05:30
anmolsinghbhatia
f2a4e026a5 fix: cycle and module sidebar overflow fix 2023-06-29 18:19:38 +05:30
anmolsinghbhatia
8229b12c9c style: recent page overflow fix 2023-06-29 18:17:52 +05:30
anmolsinghbhatia
3c07da433a fix: overflow fix 2023-06-29 18:16:01 +05:30
pablohashescobar
1ed7935bf0 docs: update readme.md for self hosting setup and remove pnpm from contribution guidelines (#1423) 2023-06-29 11:52:44 +05:30
Vamsi Kurama
6394f517a2 Merge pull request #1413 from makeplane/stage-release
promote: stage-release to master
2023-06-28 19:19:59 +05:30
pablohashescobar
379d258375 fix: charts design and mutation (#1426) (#1427)
* fix: pie chart overlap issue

* fix: burndown chart mutation

* fix: burndown chart mutation

Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
2023-06-28 19:09:44 +05:30
Aaryan Khandelwal
c743d43ce2 fix: charts design and mutation (#1426)
* fix: pie chart overlap issue

* fix: burndown chart mutation

* fix: burndown chart mutation
2023-06-28 19:08:33 +05:30
pablohashescobar
6a27827c16 Merge pull request #1425 from makeplane/develop
promote: develop to stage-release
2023-06-28 17:48:53 +05:30
Anmol Singh Bhatia
01f465fdfa style: adjust tooltip position and spacing in workspace id and title in spreadsheet (#1420) 2023-06-28 17:27:43 +05:30
Anmol Singh Bhatia
1a668c19a5 style: issue detail page layout (#1424) 2023-06-28 17:27:19 +05:30
pablohashescobar
206ca98307 Merge pull request #1418 from makeplane/develop
promote: develop to stage-release
2023-06-28 11:14:41 +05:30
pablohashescobar
ed0106200e dev: migrations for removal of timelineissues and shortcut (#1417) 2023-06-28 11:06:52 +05:30
pablohashescobar
473c32d3d4 fix: github importer issue (#1414) (#1415) 2023-06-27 22:56:06 +05:30
pablohashescobar
0bdd26ce12 fix: github importer issue (#1414) 2023-06-27 22:54:52 +05:30
guru_sainath
124d1c30aa Merge pull request #1410 from makeplane/develop
promote: develop to stage-release
2023-06-27 19:01:26 +05:30
Rhea Jain
df0b7d78e6 Update README.md (#1411)
Edited the security email.
2023-06-27 18:57:28 +05:30
Aaryan Khandelwal
7fbf0e6358 fix: progress chart x-axis values (#1409)
* fix: x-axis dates value in the progress chart

* chore: loader for active cycle
2023-06-27 18:08:37 +05:30
Aaryan Khandelwal
7f1def2041 fix: priority none filter (#1407) 2023-06-27 18:01:57 +05:30
Aaryan Khandelwal
b0cdcfd91e fixL inbox status colors (#1408) 2023-06-27 18:01:42 +05:30
Anmol Singh Bhatia
f3be2faa8f fix: resolve z-index issue with quick action menu and disable it for completed cycles (#1405) 2023-06-27 17:12:21 +05:30
guru_sainath
fd7274ba1c Merge pull request #1406 from makeplane/develop
promote: develop to stage-release
2023-06-27 16:48:34 +05:30
Anmol Singh Bhatia
b01afdf300 fix: spreadsheet quick action menu fix (#1404) 2023-06-27 15:49:19 +05:30
M. Palanikannan
5914240290 fix: cannot change the state if it's the only state in group (#1358)
* fixed loohole with groups and added tooltip

* muted text when dropdown disabled
2023-06-26 18:28:12 +05:30
Anmol Singh Bhatia
3f22ccc528 fix: filter none updated (#1399) 2023-06-26 18:08:49 +05:30
Anmol Singh Bhatia
ad3411284b feat: add existing issue option added in spreadsheet view (#1397) 2023-06-26 18:01:28 +05:30
pablohashescobar
ae051b28af fix: priority filtering (#1398) 2023-06-26 17:59:17 +05:30
Aaryan Khandelwal
c89592d587 chore: add tooltip to line graphs (#1392)
* chore: workspace dashboard line graph tooltip

* chore: burndown chart and analytics line graph tooltip added
2023-06-26 14:26:38 +05:30
Aaryan Khandelwal
c70fe91886 fix: create issue modal not working on workspace level (#1393) 2023-06-26 14:25:19 +05:30
Anmol Singh Bhatia
1a48fdd142 fix: bug fixes (#1394)
* fix: multi level dropdown fix

* style: spreadsheet view add issue button

* fix: spreadsheet view sub-issue label mutation
2023-06-26 14:24:52 +05:30
Aaryan Khandelwal
06ce89a03a fix: sidebar toggle button on workspace dashboard (#1389) 2023-06-24 18:12:11 +05:30
Anmol Singh Bhatia
fd30ea9a20 feat: editable label option added in all view , fix: view page list and kanban view mutation fix, chore: code refactor (#1390)
* feat: editable label select component added in spreadsheet view

* feat: editable label select option added in all view, chore: code refactor

* fix: view page list and kanban view mutation fix and sub issue mutation, chore: refactor partial update issue function

* fix: build fix
2023-06-24 18:09:06 +05:30
pablohashescobar
7acd4ef1af fix: issue duplication when ordering by labels and assignee (#1388) 2023-06-24 17:52:12 +05:30
pablohashescobar
46d93525be Merge pull request #1386 from makeplane/develop
promote: develop to stage-release
2023-06-24 01:34:34 +05:30
Anmol Singh Bhatia
56a35e74bb fix: spreadsheet bug fixes (#1385)
* fix: sub issue accordion fix

* chore: assignees sort order updated
2023-06-24 01:25:18 +05:30
Anmol Singh Bhatia
5ada1e5397 fix: spreadsheet view bug fixes (#1383)
* fix: due date sorting fix

* fix: update and delete sub-issue fix
2023-06-24 00:35:43 +05:30
Aaryan Khandelwal
ddaa8df1c5 fix: progress chart to show ideal line only when data is present (#1384) 2023-06-24 00:35:00 +05:30
pablohashescobar
ccbe773ce1 fix: state and priority ordering (#1378) 2023-06-23 22:18:03 +05:30
Anmol Singh Bhatia
160cc014a7 feat: spreadsheet view improvements (#1379)
* feat: quick menu for spreadsheet view added ,style: spreadsheet view column updated ,fix: z-index issue

* feat: sorting indicator, style: spreadsheet column
2023-06-23 21:33:24 +05:30
Aaryan Khandelwal
ca7d3309d3 chore: accept issue confirmation modal (#1377)
* chore: accept issue confirmation modal

* chore: add inbox option to the command menu

* fix: status colors not loading

* chore: show state name on the inbox issue sidebar
2023-06-23 19:30:53 +05:30
Aaryan Khandelwal
b87e2fff4c chore: show error messages from request (#1375) 2023-06-23 19:30:32 +05:30
Aaryan Khandelwal
428d0dbac9 fix: words breaking abruptly (#1371) 2023-06-23 19:30:11 +05:30
Aaryan Khandelwal
ca799a2b02 fix: update task for ai requests (#1368) 2023-06-23 19:29:36 +05:30
Aaryan Khandelwal
ff87137e40 fix: onboarding tracker (#1360) 2023-06-23 19:29:17 +05:30
pablohashescobar
df41daf71b fix: auth error messages (#1376) 2023-06-23 17:28:21 +05:30
pablohashescobar
fef83d3153 fix: inbox issue update (#1373) 2023-06-23 17:28:13 +05:30
pablohashescobar
8e094aa895 chore: triage state filtering (#1372) 2023-06-23 17:28:06 +05:30
Anmol Singh Bhatia
e08fc59114 feat: spreadsheet view (#1369)
* feat: spreadsheet view

* fix: fix scroll and overflow issues, feat: updated issue properties component, style: ui improvements

* feat: sub-issue toggle and sub-issue hook added, chore: code refactor

* fix: only render parent issue

* feat: sub issue fetching hook updated and nested sub issue added, chore: code refactor

* style: title sticky to left on scroll and column styling

* fix: tooltip , filter and view z-index fix

* feat: spreadsheet view column sorting, fix: sticky scroll issue fix

* feat: updated issue view filter for spreadsheet view

* style: spreadsheet view column

* feat: double click to edit title

* fix: estimate sorting fix

* style: spreadsheet view columns

* fix: spreadsheet view mutation, feat: edit , copy and delete option added

* fix: edit sub issue fix
2023-06-23 17:20:05 +05:30
pablohashescobar
0cb856b92f chore: inbox issue ordering (#1367) 2023-06-23 13:33:01 +05:30
pablohashescobar
37303e6cb8 refactor: inbox issues (#1370)
* refactor: inbox issue endpoints

* dev: update inbox issues endpooint
2023-06-23 13:30:52 +05:30
Aaryan Khandelwal
71b2884b57 chore: route to issue after creating it (#1359)
* chore: navigate to newly created inbox issue

* refactor: inbox

* fix: hide ai modal after issue creation

* chore: hide action buttons after acting upon them

* chore: add icon to inbox status

* chore: update inbox status colors
2023-06-23 13:19:26 +05:30
Aaryan Khandelwal
41b7544cfc feat: search endpoint (#1317)
* feat: search endpoint for parent issue selection

* feat: blocker and blocked by search endpoint

* refactor: blocker and blocked by components and types

* refactor: blocker and blocked by components, feeat: cycle and module new search endpoints

* chore: sub-issues param change

* style: show selected issues list
2023-06-23 13:18:38 +05:30
Aaryan Khandelwal
62392be5a3 chore: info icon for activity graph (#1353) 2023-06-23 11:10:19 +05:30
Aaryan Khandelwal
c2caed8c42 fix: bulk delete issues mutation (#1351) 2023-06-23 11:10:09 +05:30
Aaryan Khandelwal
048a01dbf3 fix: description not loading while editing an issue (#1349) 2023-06-23 11:09:57 +05:30
Aaryan Khandelwal
8982452500 fix: issue title breaking in issue card (#1339) 2023-06-23 11:09:47 +05:30
Aaryan Khandelwal
d3c56c1765 fix: cycle stats empty state (#1338)
* chore: active cycle percentage fix

* fix: progress chart x-axis values
2023-06-23 11:09:34 +05:30
Aaryan Khandelwal
9c85704be3 style: profile settings, activity, preference page padding (#1335) 2023-06-23 11:09:03 +05:30
Aaryan Khandelwal
f839150741 fix: create new issue when grouped by label (#1308) 2023-06-23 11:08:53 +05:30
pablohashescobar
e7bb580289 chore: set sentry dsn from environment variable (#1366)
* chore: set sentry dsn from env variable for backend and worker

* dev: sentry dsn for docker compose hub file
2023-06-22 19:48:40 +05:30
pablohashescobar
d1e834eb6f chore: updated user onboarded response (#1365) 2023-06-22 19:48:28 +05:30
pablohashescobar
33cfbbf153 chore: enable print logs for background workers when in DEBUG mode (#1357) 2023-06-22 19:48:17 +05:30
pablohashescobar
bfac39f1bc chore: inbox issue permissions (#1341)
* chore: inbox issue permissions

* dev: update delete endpoint
2023-06-22 19:48:04 +05:30
pablohashescobar
537cd2f5dd chore: link and attachment count in sub issues (#1352) 2023-06-22 19:47:56 +05:30
Aaryan Khandelwal
352c84b026 fix: clear inbox status filter button (#1355) 2023-06-22 16:23:39 +05:30
Aaryan Khandelwal
2cef6e67d4 chore: decline issue mutation (#1354) 2023-06-21 17:56:08 +05:30
Aaryan Khandelwal
a0ae569a68 chore: show inbox applied filters list (#1334) 2023-06-21 17:32:56 +05:30
Aaryan Khandelwal
7d29a89eed fix: inbox mutation fixes (#1324)
* chore: inbox status update mutation

* fix: inbox issue activity mutation

* refactor: code structure

* chore: snoozed status message

* chore: disable older dates for snoozing

* chore: extend snooze time

* chore: hide copy link from inbox
2023-06-21 17:10:52 +05:30
Aaryan Khandelwal
cf8c902473 chore: update cycle and module stats logic (#1323)
* refactor: cycles stats

* chore: show assignee avatar in stats

* chore: cycles and modules sidebar stats refactor

* fix: build errors
2023-06-20 16:32:02 +05:30
pablohashescobar
d7097330ef chore: update issue search for cycle and modules (#1314)
* chore: update issue search for cycle and modules

* dev: return state name, group and color in search

* dev: sub issue search
2023-06-20 10:27:45 +05:30
pablohashescobar
7a991720a8 chore: add assignee, label and burndown plot in module details (#1313)
* chore: add assignee, label and burndown plot in module details

* dev: fix typo and key error

* dev: add avatar in module retrieve
2023-06-20 10:27:34 +05:30
pablohashescobar
ac6fae44e8 chore: toggle sub issue view and sub issue count in sub issues (#1312) 2023-06-20 10:27:21 +05:30
pablohashescobar
8496422d20 fix: inbox issue activity (#1310) 2023-06-20 10:27:01 +05:30
pablohashescobar
d1d8722525 remove: shortcut module (#1315) 2023-06-20 10:26:44 +05:30
pablohashescobar
f797bb20f9 remove: time line issues (#1316) 2023-06-20 10:26:31 +05:30
pablohashescobar
464c0f2308 chore: add assignee avatar and minor refactor on cycles list and retrieve endpoint (#1320) 2023-06-20 10:25:47 +05:30
pablohashescobar
c9ebc20a8e fix: importer delete when imported_data is None (#1328) 2023-06-20 10:24:38 +05:30
Bavisetti Narayan
0c3635cf25 chore: added DEBUG value for docker setup (#1327)
* chore: add DEBUG value for docker setup

* refactor: removed the extra DEFAULT value
2023-06-20 09:36:08 +05:30
Aaryan Khandelwal
f2ebac1bb4 fix: issue details page auth (#1331) 2023-06-19 23:39:47 +05:30
vamsi
a3f6d61347 LICENSE change for Plane 2023-06-19 18:47:39 +05:30
Aaryan Khandelwal
1da86b80b2 chore: change charts library (#1305)
* fix: dashboard charts

* fix: cycles new charts

* chore: sidebar burn down chart and calendar graph

* chore: update dashboard line and pie graph

* chore: update axes width of burndown chart

---------

Co-authored-by: Dakshesh Jain <dakshesh.jain14@gmail.com>
2023-06-19 12:59:57 +05:30
Sai Tharun
59c0de9b57 🔨 updated missing migration file (#1321)
Co-authored-by: saitharunsai <sai.tharun@livehealth.in>
2023-06-19 08:23:44 +05:30
Vamsi Kurama
dbbce439ff Merge pull request #1311 from makeplane/stage-release
promote: staging to master
2023-06-16 21:34:03 +05:30
pablohashescobar
4c0857233e fix: workspace member invite to avoid lower permission user to invite higher permission member (#1309) 2023-06-16 19:52:24 +05:30
Aaryan Khandelwal
0dfa06e55b fix: lower role user cannot invite higher role user (#1302) 2023-06-16 19:06:34 +05:30
Aaryan Khandelwal
81f6562168 feat: sign up page added (#1306) 2023-06-16 19:00:04 +05:30
pablohashescobar
56a4e18a3c chore: link and attachment count for cycles and modules (#1307) 2023-06-16 18:59:13 +05:30
pablohashescobar
bfe581d3bd dev: workspace issue count (#1298) 2023-06-16 18:58:56 +05:30
pablohashescobar
78f9028b2f fix: member invite (#1303)
* fix: member invite

* dev: fix integer errors
2023-06-16 18:58:29 +05:30
pablohashescobar
885f5deebe chore: update docker setup to mount env file (#1270) 2023-06-16 18:58:08 +05:30
pablohashescobar
6b1d20449b chore: add labels data in cycles (#1223)
* dev: add labels data for all cycles

* dev: add assignees and labels percentage

* dev: initial peice on cycle burn down chart

* dev: cycles burn down chat
2023-06-16 18:57:49 +05:30
pablohashescobar
e9a0eb87cc feat: inbox (#1023)
* dev: initialize inbox

* dev: inbox and inbox issues models, views and serializers

* dev: issue object filter for inbox

* dev: filter for search issues

* dev: inbox snooze and duplicates

* dev: set duplicate to null by default

* feat: inbox ui and services

* feat: project detail in inbox

* style: layout, popover, icons, sidebar

* dev: default inbox for project and pending issues count

* dev: fix exception when creating default inbox

* fix: empty state for inbox

* dev: auto issue state updation when rejected or marked duplicate

* fix: inbox update status

* fix: hydrating chose with old values

filters workflow

* feat: inbox issue filtering

* fix: issue inbox filtering

* feat: filter inbox issues

* refactor: analytics, border colors

* dev: filters and views for inbox

* dev: source for inboxissue and update list inbox issue

* dev: update list endpoint to house filters and additional data

* dev: bridge id for list

* dev: remove print logs

* dev: update inbox issue workflow

* dev: add description_html in issue details

* fix: inbox track event auth, chore: inbox issue action authorization

* fix: removed unnecessary api calls

* style: viewed issues

* fix: priority validation

* dev: remove print logs

* dev: update issue inbox update workflow

* chore: added inbox view context

* fix: type errors

* fix: build errors and warnings

* dev: update issue inbox workflow and log all the changes

* fix: filters logic, sidebar fields to show

* dev: update issue filtering status

* chore: update create inbox issue modal, fix: mutation issues

* dev: update issue accept workflow

* chore: add comment to inbox issues

* chore: remove inboxIssueId from url after deleting

* dev: update the issue triage workflow

* fix: mutation after issue status change

* chore: issue details sidebar divider

* fix: issue activity for inbox issues

* dev: update inbox perrmissions

* dev: create new permission layer

* chore: auth layer for inbox

* chore: show accepting status

* chore: show issue status at the top of issue details

---------

Co-authored-by: Dakshesh Jain <dakshesh.jain14@gmail.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-06-16 18:57:17 +05:30
pablohashescobar
963ccd808d fix: email ssl setting for docker environment (#1299) 2023-06-16 18:54:01 +05:30
pablohashescobar
1e2c1cac9c chore: project list endpoint to show is_member status (#1166) 2023-06-16 18:52:58 +05:30
pablohashescobar
592fe94cb4 chore: enable/disable signup in self hosted environments (#1271)
* dev: new onboarding workflow for self hosted instance

* dev: additional flag on user creation

* dev: segregate sign up and sign in endpoint

* dev: update sign in endpoint for not existing users
2023-06-16 18:23:39 +05:30
guru_sainath
02111d779b promote: staging to production 2023-06-14 17:47:23 +05:30
guru_sainath
c3aa1cb06d chore: auth workflow in magic-link
chore: auth workflow in magic-link
2023-06-14 17:42:48 +05:30
guru_sainath
e73bd96dbc chore: auth workflow in magic-link (#1292) 2023-06-14 16:56:17 +05:30
guru_sainath
8c9f4b9665 promote: develop to stage release
promote: develop to stage release
2023-06-14 14:57:30 +05:30
guru_sainath
be7706e62e chore: updating last_workspace_id under user (#1289)
* chore: onboarding steps workflow verification

* chore: onboarding onboarding variable update

* chore: role check in onboarding

* chore: updated last_workspace_id under user
2023-06-14 14:04:25 +05:30
guru_sainath
4083f623a0 refactor: onboarding user role validation (#1287) 2023-06-14 13:39:49 +05:30
guru_sainath
6f7b563712 refactor: onboarding workflow (#1286)
* chore: onboarding steps workflow verification

* chore: onboarding variable update
2023-06-14 13:17:35 +05:30
guru_sainath
4b25b7244b promote: develop to staging 2023-06-13 15:40:12 +05:30
guru_sainath
f774603b7f chore: onboarding workflow in authentication (#1281) 2023-06-13 14:37:25 +05:30
pablohashescobar
15b5db0cae dev: upgrade python runtime (#1256) 2023-06-12 10:02:16 +05:30
guru_sainath
66807bef0d fix: social auth authentication workflow (#1264)
* fix: github login mutation

* dev: updated social auth workflow and handled multiple loads on user

* dev: mutaing user and updated analytics logout issue resolved

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-06-10 01:26:38 +05:30
Vamsi Kurama
49f19c2c44 Merge pull request #1257 from makeplane/stage-release
promote: stage release to production
2023-06-09 16:27:25 +05:30
guru_sainath
9529ddb393 Merge pull request #1262 from makeplane/develop
promote: develop to stage-relaease
2023-06-09 16:23:23 +05:30
Aaryan Khandelwal
e7af3da115 chore: update remove file function logic (#1259)
* chore: update remove file function logic

* fix: workspace file delete endpoint
2023-06-09 10:24:57 +05:30
guru_sainath
d09f410f21 Merge pull request #1252 from makeplane/develop
promote: develop to stage release
2023-06-08 00:19:08 +05:30
pablohashescobar
98e6a1366c chore: update workspace invitation email redirection url (#1236)
* chore: update workspace invitation email redirection url

* dev: update workspace invitation mail
2023-06-08 00:14:53 +05:30
pablohashescobar
754142afa2 fix: workspace and project member user deletion (#1241)
* fix: workspace and project member user deletion

* fix: workspace member deletion

* dev: add comments
2023-06-08 00:14:41 +05:30
Aaryan Khandelwal
42fceb4dcd fix: user profile data mutation (#1243) 2023-06-07 19:03:49 +05:30
Aaryan Khandelwal
e949c4e130 chore: fetch only high priority issues for the active cycle (#1228) 2023-06-07 19:03:02 +05:30
Anmol Singh Bhatia
78c1a64690 fix: assignee dropdown, sign in button, and onboarding flicker fix (#1242) 2023-06-07 17:45:57 +05:30
guru_sainath
3d5fcbd4ce dev: route validation on non authenticated pages (#1238) 2023-06-07 13:47:56 +05:30
Anmol Singh Bhatia
f9cd1b1352 fix: last workspace id (#1237) 2023-06-07 13:18:45 +05:30
Peter Dave Hello
18f66805cb Improve apk usages in Dockerfile (#1198) 2023-06-07 12:30:42 +05:30
pablohashescobar
382a1343ea fix: file asset uploads in workspace (#1234) 2023-06-07 12:21:09 +05:30
pablohashescobar
c05eb9e240 fix: forgot password email subject and update template (#1233) 2023-06-07 09:09:59 +05:30
Anmol Singh Bhatia
40d2990565 fix: onboarding ui fix (#1225) 2023-06-07 01:56:58 +05:30
Aaryan Khandelwal
684df96969 chore: replace nextjs Image element (#1227) 2023-06-07 01:56:21 +05:30
Aaryan Khandelwal
1f3fdd5d0a feat: reset password page for self-hosted added (#1221)
* feat: reset password page for self-hosted added

* chore: change reset password workflow

* dev: update email template for reset password

* chore: updated restricted workspace slugs list

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2023-06-06 21:36:13 +05:30
Anmol Singh Bhatia
6f2a38ad66 fix: bug and auth fixes (#1224)
* fix: sign in and invitation page fixes

* fix: project and workspace services track event fix

* fix: user onboarding complete track event fix

* fix: issue track event fix

* fix: partial property , issue comment and mark as done issue track event fix

* fix: bulk delete , move to cycle or module and issue label track event fix

* fix: state , cycle and module track event fix

* fix: pages and block track event fix

* fix: integration , estimate , importer , analytics and gpt track event fix

* fix: view track event fix

* fix: build fix

* fix: build fix
2023-06-06 21:36:00 +05:30
pablohashescobar
c127353281 chore: workspace invite created detail (#1209)
* chore: workspace invite created detail

* dev: select related workspace member invite list
2023-06-06 19:15:56 +05:30
pablohashescobar
705371eaf3 fix: file upload size limit (#1218) 2023-06-06 19:15:42 +05:30
pablohashescobar
fae9d8cdc1 chore: reset password url (#1220)
* chore: reset password url

* dev: update password reset endpoint

* dev: update reset password url
2023-06-06 19:15:20 +05:30
pablohashescobar
b6c0ddac50 chore: move minio endpoint url to environment configuration (#1210) 2023-06-06 08:21:57 +05:30
pablohashescobar
557e96c68e fix: email tls when selfhosting (#1206) 2023-06-05 21:26:04 +05:30
guru_sainath
7eae6b4c9e fix: user public authentication workflow updates (#1207)
* auth integration fixes

* auth integration fixes

* auth integration fixes

* auth integration fixes

* dev: update user api to return fallback workspace and improve the structure of the response

* dev: fix the issue keyerror and move onboarding logic to serializer method field

* dev: use-user-auth hook imlemented for route access validation and build issues resolved effected by user payload

* fix: global theme color fix

* style: new onboarding ui , fix: use-user-auth hook implemented

* fix: command palette, project invite modal and issue detail page mutation type fix

* fix: onboarding redirection fix

* dev: build isuue resolved

* fix: use user auth hook fix

* fix: sign in toast alert fix, sign out redirection fix and user theme error fix

* fix: user response fix

* fix: unAuthorizedStatus logic updated

* dev: Implemented SEO in app.tsx

* dev: User public auth workflow updates.

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: anmolsinghbhatia <anmolsinghbhatia@caravel.tech>
2023-06-05 17:48:29 +05:30
pablohashescobar
77e05a3599 fix: project member role update (#1205) 2023-06-05 17:45:10 +05:30
pablohashescobar
2511a284eb feat: plane proxy setup (#1181)
* feat: plane proxy setup

* dev: remove port mapping from web, api and minio containers
2023-06-05 12:53:04 +05:30
pablohashescobar
e3da80755c fix: minio settings (#1172) 2023-06-05 12:52:25 +05:30
pablohashescobar
58d1d8f132 fix: issue search for blocking and blocked_by condition (#1182)
* fix: issue search for blocking and blocked_by condition

* fix: issue search endpoint blockers

* fix: rectify the filter parameters
2023-06-05 12:51:30 +05:30
pablohashescobar
50060a0bf9 chore: update docker uploads (#1202) 2023-06-05 12:51:12 +05:30
pablohashescobar
bffc6a60e7 fix: workspace member role update (#1203) 2023-06-05 12:50:44 +05:30
pablohashescobar
799cf230b7 Revert "Update README.md (#1189)" (#1193)
This reverts commit 37442f482b.
2023-06-04 15:51:06 +05:30
tarunratan
37442f482b Update README.md (#1189)
change in readme of docker-compose
2023-06-04 09:49:13 +05:30
Nathanael Demacon
c234f2a087 docs: fix docker compose quick start (#1173)
* docs: add missing .env.example fetch in docker compose quick start

* docs: clone the repository instead of fetching particular files
2023-06-02 12:27:15 +05:30
Anmol Singh Bhatia
857879f5ed fix : theme provider fix (#1164) 2023-06-01 14:40:27 +05:30
sriram veeraghanta
44f8ba407d Authentication Workflow fixes. Redirection fixes (#832)
* auth integration fixes

* auth integration fixes

* auth integration fixes

* auth integration fixes

* dev: update user api to return fallback workspace and improve the structure of the response

* dev: fix the issue keyerror and move onboarding logic to serializer method field

* dev: use-user-auth hook imlemented for route access validation and build issues resolved effected by user payload

* fix: global theme color fix

* style: new onboarding ui , fix: use-user-auth hook implemented

* fix: command palette, project invite modal and issue detail page mutation type fix

* fix: onboarding redirection fix

* dev: build isuue resolved

* fix: use user auth hook fix

* fix: sign in toast alert fix, sign out redirection fix and user theme error fix

* fix: user response fix

* fix: unAuthorizedStatus logic updated

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
Co-authored-by: anmolsinghbhatia <anmolsinghbhatia@caravel.tech>
2023-05-30 19:14:35 +05:30
Anmol Singh Bhatia
33db616767 fix: default status set for module form (#1160) 2023-05-29 22:16:32 +05:30
Anmol Singh Bhatia
c949c4d244 fix: empty module mutation and issue view flicker fix (#1158) 2023-05-29 18:35:43 +05:30
Anmol Singh Bhatia
c8caa925b1 chore: page and cycle refactor (#1159)
* fix: release note modal fix

* chore: cycle and page endpoint refactor
2023-05-29 18:35:16 +05:30
Aaryan Khandelwal
26ba4d71c3 fix: order by last updated, cycles empty state alignment (#1151)
* fix: order by last updated

* fix: cycles empty space alignment, chore: new meta tags

* chore: update meta tags
2023-05-29 15:38:35 +05:30
Aaryan Khandelwal
022960d7e3 fix: pages layout and alignment issues (#1152) 2023-05-29 15:16:49 +05:30
guru_sainath
dce3c3f008 Merge pull request #1153 from makeplane/fix/cycles_layout
refactor: cycles list code and folder structure
2023-05-29 15:16:10 +05:30
pablohashescobar
ffc6077e9b chore: improve docker setup (#1150) 2023-05-29 12:11:16 +05:30
guru_sainath
23d08a2ad1 Merge pull request #1156 from makeplane/hot-fix
promote: hot-fix to develop
2023-05-29 10:46:45 +05:30
Aaryan Khandelwal
1c98f2dca9 chore: update cycle fetch keys names 2023-05-29 02:38:16 +05:30
Aaryan Khandelwal
053ebc031d fix: cycles layout 2023-05-29 02:14:40 +05:30
pablohashescobar
c9dee593eb chore: total members in user workspace invites (#1143) 2023-05-28 18:11:59 +05:30
pablohashescobar
bc8430220b chore: email settings for docker setup (#1148) 2023-05-28 18:11:36 +05:30
Marks
030558c026 Update text during the onboarding process (#1149)
* Update text during the onboarding process

A few of the phrases were worded in ways that took a bit longer to process. These changes should make onboarding more comfortable.

* Update text
2023-05-28 17:42:01 +05:30
pablohashescobar
d8c367c51e docs: update self hosting setup script (#1145) 2023-05-28 14:47:25 +05:30
Eli
1afb3ba4d2 chore: speedup replace-env-vars.sh (#1146) 2023-05-28 10:04:54 +05:30
pablohashescobar
8252b1ccde chore: configuration for nginx port (#1144) 2023-05-28 09:56:15 +05:30
Anmol Singh Bhatia
394f0bf555 chore: cycles endpoint updated and code refactor (#1135)
* chore: cycles endpoint updated and code refactor

* chore: incomplete cycle endpoint updated

* chore: code refactor
2023-05-26 15:38:56 +05:30
Anmol Singh Bhatia
4ce0ac6ea1 chore: pages endpoint updated (#1137) 2023-05-26 15:38:44 +05:30
pablohashescobar
cd821a934d chore: update single click deployments (#1141)
* chore: update single click deployments

* dev: update environment variables
2023-05-26 14:04:15 +05:30
pablohashescobar
f80b3f1eb1 fix: issue ordering for priority and updated_by parameters (#1142) 2023-05-26 13:51:09 +05:30
pablohashescobar
b6321438ce chore: docker setup (#1136)
* chore: update docker environment variables and compose file for better readability

* dev: update single dockerfile

* dev: update WEB_URL configuration

* dev: move database settings to environment variable

* chore: remove port configuration from default compose file

* dev: update example env to add EMAIL_FROM and default values for AWS
2023-05-26 11:09:59 +05:30
pablohashescobar
16604dd31b refactor: page views endpoint (#1130) 2023-05-25 14:13:54 +05:30
Aaryan Khandelwal
11b28048bf chore: analytics tracker events (#1119)
* chore: added export analytics event tracker

* chore: add analytics view events

* chore: workspace analytics view track event added
2023-05-25 12:38:53 +05:30
Dakshesh Jain
7e5b26ea82 fix: project ordering messing up in projects page (#1122) 2023-05-25 12:38:15 +05:30
pablohashescobar
5beb50fa76 fix: role updation (#1110) 2023-05-25 12:27:04 +05:30
pablohashescobar
af2d7d6f75 fix: project member delete when deleting user from workspace (#1123)
* fix: project member delete when deleting user from workspace

* fix: workspace and project member delete
2023-05-25 12:25:15 +05:30
pablohashescobar
e608b58e70 refactor: cycle views endpoint (#1128) 2023-05-25 12:24:39 +05:30
pablohashescobar
a16514ed11 fix: auto generated secret key to only generate hexadecimal characters (#1133) 2023-05-25 12:24:03 +05:30
Anmol Singh Bhatia
74329a49cc fix: send code button behavior on enter key press (#1121) 2023-05-25 12:19:48 +05:30
Anmol Singh Bhatia
def391cb76 feat: storing my issue view display properties (#1124) 2023-05-25 12:19:37 +05:30
Robin
e526a01295 Clean up docker compose file for selfhosting (#1022)
* Clean up docker compose file

Removed nginx container (might want to put it back?)
Changed spacing to tabs for better readability
Changed the order, first the important stuff (plane) and later the database/redis
All containers should be in the same format (first container_name, then image, then restart, etc.).
Removed links because deprecated since compose version 2, all containers are in one docker network
Removed build from plane-api
Removed ports from redis and postgresql
Removed PGDATA directory because that's the default one
Renamed redis and db to plane-redis and plane-db

* Fixed spacing (again)

* Fix spacing (attempt 3)

* Pasting error - should be good now

* New compose download instructions

---------

Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
2023-05-25 10:49:37 +05:30
pablohashescobar
0fb4a87454 fix: docker image uploads (#1108)
* dev: basic initial setup for images

* Update docker-compose.yml

* dev: minio setup

* dev: docker minio setup

* dev: update the asset view

* dev: setup minio with default configuration

* dev: update minio setup for creating buckets

* dev: update the permission sets

* dev: get variables from shell for create bucket

* dev: update image uploading setup for docker

* dev: environment variables update

* dev: web url for images

* dev: update image configuration

* dev: env update for email port

---------

Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>
2023-05-25 10:24:20 +05:30
Vihar Kurama
0bd6e53b44 docs: updated Readme with new features and screenshots (#1132)
* update readme images with new features

* remove line-break on readme

* update plane analytics image
2023-05-24 21:42:40 +05:30
gurusainath
f095594be9 update: Handled empty state in adding members to project. 2023-05-22 22:38:22 +05:30
guru_sainath
2e638b28b6 dev: added tooltip to title and added info for issues (#1112)
* update: tooltip in the blocks

* dev: added tooltip to title and added info for issues
2023-05-22 22:09:52 +05:30
guru_sainath
aaffe37fbe fix: Showing status for accounts not created in the workspace members (#1111) 2023-05-22 22:09:38 +05:30
Vamsi Kurama
5c632921f8 Merge pull request #1102 from makeplane/stage-release
promote: stage-release to master
2023-05-22 00:20:23 +05:30
guru_sainath
7c9035182b Merge pull request #1105 from makeplane/hot-fix
promote: hot-fix to stage-release
2023-05-21 19:42:15 +05:30
gurusainath
b5325f14aa fix: gantt build issue resolved 2023-05-21 19:38:33 +05:30
gurusainath
4238f89cec dev: gantt ui changes 2023-05-21 19:27:08 +05:30
guru_sainath
a44cddb0fc dev: dropdown overflow issue resolved in kanban (#1106) 2023-05-21 19:08:28 +05:30
guru_sainath
83a0c8163f dev: redirection implementation on gantt blocks (#1104) 2023-05-21 18:37:26 +05:30
gurusainath
c8c195eab4 Merge branch 'stage-release' of gurusainath:makeplane/plane into stage-release 2023-05-20 23:32:07 +05:30
guru_sainath
0acee1fe66 Merge pull request #1103 from makeplane/develop
fix: updated discord link on readme (#1101)
2023-05-20 23:31:32 +05:30
Vihar Kurama
e5f6be54e0 fix: updated discord link on readme (#1101) 2023-05-20 23:30:05 +05:30
guru_sainath
15a846ce06 Merge pull request #1100 from makeplane/hot-fix
promote: hotfix to stage-release
2023-05-20 23:28:29 +05:30
guru_sainath
a01e241523 styles: UI changes in the gantt blocks (#1099) 2023-05-20 23:17:44 +05:30
pablohashescobar
cba62f07c0 chore: analytic export mail (#1098) 2023-05-20 23:16:19 +05:30
gurusainath
c1f8766571 styles: UI changes in the gantt blocks 2023-05-20 23:10:04 +05:30
guru_sainath
af13a1b00a Merge pull request #1097 from makeplane/fix/cycle_view
fix: cycle view & create label modal
2023-05-20 22:43:55 +05:30
anmolsinghbhatia
4439740768 fix: create label modal error message updated 2023-05-20 22:30:44 +05:30
anmolsinghbhatia
98a223e5e1 fix: cycle view board view fix , feat: on gantt view set all cycle as default tab 2023-05-20 22:24:05 +05:30
guru_sainath
e081395857 Merge pull request #1095 from makeplane/develop
promote: develop to stage-release
2023-05-20 20:24:27 +05:30
gurusainath
8b527f27d0 dev: migrations for the analytics fields 2023-05-20 20:18:22 +05:30
guru_sainath
ae67dc6074 update: changed icons for gantt chat in issues, modules and cycles (#1096) 2023-05-20 20:08:17 +05:30
guru_sainath
e1e9a5ed96 feat: Gantt chart (#1062)
* dev: Helpers

* dev: views

* dev: Chart views Month, Year and Day

* dev: Chart Workflow updates

* update: scroll functionality implementation

* update: data vaidation

* update: date renders and issue filter in the month view

* update: new date render month view

* update: scroll enabled left in chart

* update: Item render from the date it created.

* update: width implementation in chat view

* dev: chart render functionality in the gantt chart

* update: month view fix

* dev: chart render issues resolved

* update: fixed allchat views

* update: updated week view default values

* update: integrated chart view in issues

* update: grabble and sidebar logic impleemntation and integrated gantt in issues

* update: Preview gantt chart in month view

* fix: mutation in gantt chart after creating a new issue

* chore: cycles and modules list gantt chart

* update: Ui changes on gantt view

* fix: gantt chart height, chore: remove link from issue

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-05-20 17:30:15 +05:30
Aaryan Khandelwal
9ccc35d181 fix: make custom search select handle undefined options (#1094)
* fix: make search select handle undefined options

* fix: kanban y-scroll
2023-05-20 16:00:41 +05:30
pablohashescobar
012486df11 chore: assignee names in analytics export (#1086)
* chore: assignee names in analytics export

* chore: update key as assignee name
2023-05-20 16:00:02 +05:30
Anmol Singh Bhatia
1fed5f7846 style: active cycle stats tab sticky (#1092) 2023-05-20 03:08:23 +05:30
Aaryan Khandelwal
8cbe6c4b36 fix: show only filtered states when state filter is selected (#1093) 2023-05-20 03:07:00 +05:30
Dakshesh Jain
d9642eee82 fix: ai response not coming when using 'AI' button (#1091)
* fix: ai response not comming for page

* fix: ai response not coming when using 'AI' button
2023-05-19 20:33:35 +05:30
Anmol Singh Bhatia
ab273f6be3 fix: sidebar dropdown fix, feat: assignee name updated (#1089)
* fix: issue sidebar cycle and module dropdown width fix

* feat: issue sidebar, issue card and issue modal assignee full name added
2023-05-19 20:00:09 +05:30
Dakshesh Jain
b1f26f322f style: added theme in color picker (#1088) 2023-05-19 19:46:09 +05:30
Dakshesh Jain
2e4f936dfa fix: ai response not comming for page (#1087) 2023-05-19 19:12:34 +05:30
Dakshesh Jain
ddeafc0695 fix: inconsistency for create label, select label getting closed on select (#1085) 2023-05-19 19:12:24 +05:30
Anmol Singh Bhatia
406f02737f feat: kanban board issue menu context (#1084) 2023-05-19 19:12:15 +05:30
Dakshesh Jain
8e9afd459a fix: create issue state not clearing on create more (#1082) 2023-05-19 19:11:56 +05:30
Anmol Singh Bhatia
186b5b5500 feat: cycle gantt view option added (#1083) 2023-05-19 18:08:47 +05:30
Aaryan Khandelwal
f2c8bdba34 fix: assignee name in analytics tooltip (#1081) 2023-05-19 17:08:32 +05:30
pablohashescobar
e162c88f03 dev: project emoji and icons (#1076) 2023-05-19 16:46:56 +05:30
Aaryan Khandelwal
7f5fdb9589 fix: icon picker not working (#1080)
* fix: icon picker not working

* fix: project icon in analytics sidebar
2023-05-19 16:35:51 +05:30
Anmol Singh Bhatia
e3a114cd69 fix: module and cycle create issue in calendar view mutation fix (#1079) 2023-05-19 16:15:06 +05:30
Anmol Singh Bhatia
ae1eb9527a style: ui improvement (#1077)
* style: assignee, sub-issue and due date display properties styling

* style: cycle view  indicator added
2023-05-19 15:22:09 +05:30
Dakshesh Jain
6da4247400 fix: Application Error on issues list page (#1064)
* fix: Application Error on issues list page

* fix: can't read property of undefined at renderTick
2023-05-19 15:13:55 +05:30
Dakshesh Jain
4ce5a450d9 fix: pages 'I'm feeling lucky' not working (#1058) 2023-05-19 15:13:33 +05:30
pablohashescobar
06618006c2 fix: cycle date check endpoint (#1074) 2023-05-19 13:00:38 +05:30
pablohashescobar
bb79c9de96 chore: start date for issues (#1075) 2023-05-19 12:36:12 +05:30
Aaryan Khandelwal
09cffd5498 fix: analytics colors when segmented by cycle, module, dates, and assignees (#1072)
* fix: show unique colors when segmented

* chore: modify random color generator function

* chore: modify random color generator function
2023-05-18 19:07:24 +05:30
Anmol Singh Bhatia
5916d6e749 fix: bug and ui fix (#1073)
* fix: cycle and module sidebar scroll

* style: date picker theming

* style: workspace slug spacing

* fix: app sidebar z-index

* fix: favorite cycle mutation

* fix: cycle modal on error close

* feat: cycle view context

* style: active cycle stats scroll

* fix: active cycle favorite mutation

* feat: import export banner

* feat: cycle sidebar date picker logic updated

* fix: NaN in progress percentage fix

* fix: tooltip fix

* style: empty state for active cycle

* style: cycle badge width fix , all cycle empty state fix and cycle icon size fix
2023-05-18 19:07:01 +05:30
pablohashescobar
c3d520aefd fix: analytics segmented export (#1068)
* fix: analytics segmented export

* dev: fix none type

* fix: analytic export y axis count
2023-05-17 18:32:10 +05:30
Aaryan Khandelwal
d41250c1ce chore: delete label confirmation modal (#1069)
* fix: negative days displayed on upcoming issues on dashboard

* chore: show completed and cancelled states by default

* chore: delete label confirmation modal
2023-05-17 16:04:56 +05:30
pablohashescobar
27626fb16f fix: default analytic estimate points and sorting for custom analytics (#1066) 2023-05-17 14:58:45 +05:30
Aaryan Khandelwal
ab695a309f fix: layout padding, tabs size and page heading font sizes (#1067) 2023-05-17 14:57:58 +05:30
Aaryan Khandelwal
3427652c22 chore: update analytics sidebar and header content, fix: trash box positioning (#1065)
* fix: labels dropdown on issue details page theming

* style: trash box styling and positioning

* chore: empty state for scope and demand analytics, show assignee name in scope graph tooltip

* chore: empty state for analytics

* chore: modify analytics sidebar and header
2023-05-17 13:25:58 +05:30
Anmol Singh Bhatia
559b0cc9c8 style: cycle new ui (#1052)
* style: cycles new ui

* chore: added progress bar for the high priority issues

* fix: build fix

* style: active cycle details, theming , padding and layout

* style: cycle list and card styling

* style: cycle card

* fix: tooltip text overflow

* fix: cycle mutation fix

* style: cycle list and card view improvement, chore: code refactor

* feat: view cycle button

* style: cycle list and board view improvement

* style: responsiveness added

* feat: active cycle stats component, chore: code refactor

* fix: active cycle divider fix, style: stats font color

* fix: tooltip fix

---------

Co-authored-by: kunal_17 <kunalvish17360@gmail.com>
2023-05-17 12:58:01 +05:30
pablohashescobar
c49b0d6151 fix: issue assignee multiple values (#1056)
* fix: issue assignee multiple values

* chore: return first name and last name

* dev: keys update and also send data when segmented
2023-05-17 00:46:41 +05:30
pablohashescobar
d99f85ce05 chore: analytics assignee email for default analytics (#1057) 2023-05-17 00:46:20 +05:30
pablohashescobar
e696a3741c chore: analytics data ordering (#1059) 2023-05-17 00:45:59 +05:30
Aaryan Khandelwal
d575e8ec6b chore: x-axis tick values for assignees (#1060)
* style: new custom analytics ui

* fix: x-axis assignee tick values

* chore: assignee names in the custom analytics table
2023-05-16 15:11:40 +05:30
pablohashescobar
c060f7db30 chore: user first name and last name for default analytics (#1054) 2023-05-16 10:50:26 +05:30
pablohashescobar
84a0f6f77e chore: rename effort to estimate (#1053) 2023-05-16 10:50:14 +05:30
Aaryan Khandelwal
c6d78b5e6a style: new custom analytics ui (#1055) 2023-05-16 10:41:37 +05:30
Aaryan Khandelwal
8c707cc544 fix: lower role user cannot update higher role user (#1048)
* fix: user role update

* chore: update project member update service type
2023-05-15 23:58:41 +05:30
pablohashescobar
abe021071c fix: workspace and project member update (#1046) 2023-05-15 19:38:37 +05:30
pablohashescobar
8d6082183e chore: return assignee avatars when x axis in assignee_email (#1049) 2023-05-15 19:38:08 +05:30
pablohashescobar
7b52fb885d remove: onboarding emails (#1050)
* remove: user onboarding mail

* remove: welcome emails
2023-05-15 19:37:40 +05:30
pablohashescobar
d28bc41fbd chore: project members, cycles and modules count (#1051) 2023-05-15 19:37:17 +05:30
pablohashescobar
63075a6a0d fix: analytics export and send month and year when dimension in date (#1039)
* fix: send month and year when dimension in date

* fix: export csv email

* fix: export for segment and fix segment for date values
2023-05-15 11:37:07 +05:30
Aaryan Khandelwal
9fdc56db0f chore: user cannot update their own role (#1041) 2023-05-15 11:35:19 +05:30
Aaryan Khandelwal
290318603d fix: calendar view mutation (#1042) 2023-05-15 11:35:07 +05:30
Anmol Singh Bhatia
dbbd9add99 fix: ui and bug fix (#1043)
* style: calendar border added

* fix: calendar issue ellipsis position fix

* fix: help section overflow fix

* fix: module card date overflow fix

* style: page detail padding and position fix

* fix: cycle and module sidebar fix
2023-05-15 11:32:50 +05:30
Aaryan Khandelwal
37bb183bf0 chore: update analytics x-axis, tooltip and table heading values (#1040)
* chore: global bar graph component

* chore: global pie graph component

* chore: global line graph component

* chore: removed unnecessary file

* chore: refactored global chart components to accept all props

* chore: function to convert response to chart data

* chore: global calendar graph component added

* chore: global scatter plot graph component

* feat: analytics boilerplate created

* chore: null value for segment and project

* chore: clean up file

* chore: change project query param key

* chore: export, refresh buttons, analytics table

* fix: analytics fetch key error

* chore: show only integer values in the y-axis

* chore: custom x-axis tick values and bar colors

* refactor: divide analytics page into granular components

* chore: convert analytics page to modal, save analytics modal

* fix: build error

* fix: modal overflow issues, analytics loading screen

* chore: custom tooltip, refactor: graphs folder structure

* refactor: folder structure, chore: x-axis tick values for larger data

* chore: code cleanup

* chore: remove unnecessary files

* fix: refresh analytics button on error

* feat: scope and demand analytics

* refactor: scope and demand and custom analytics folder structure

* fix: dynamic import type

* chore: minor updates

* feat: project, cycle and module level analytics

* style: project analytics modal

* fix: merge conflicts

* style: new scope and demand ui, user avatars in bar graph

* fix: default analytics types

* chore: new values when dimensioned by date

* chore: update table and tooltip content when dimensioned or segmented by dates
2023-05-15 11:22:06 +05:30
vamsi
512b8c104d dev: analytics migrations 2023-05-12 17:02:34 +05:30
Aaryan Khandelwal
bf865f399f fix: kanban board horizontal scroll (#1038)
* fix: kanban board horizontal scroll

* chore: droppable placeholder position
2023-05-12 12:41:31 +05:30
pablohashescobar
6a78948113 fix: analytics (#1037)
* fix: most issue created by user keys

* fix: cycle and module filters for GET method
2023-05-12 12:22:42 +05:30
pablohashescobar
6e9235e5fe fix: analytic query params (#1035)
* fix: query params for analytics

* fix: default analytics filters
2023-05-11 20:53:54 +05:30
dependabot[bot]
f2a68874f1 chore(deps): bump django in /apiserver/requirements (#1036)
Bumps [django](https://github.com/django/django) from 3.2.18 to 3.2.19.
- [Commits](https://github.com/django/django/compare/3.2.18...3.2.19)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-11 20:25:08 +05:30
Anmol Singh Bhatia
9cb3794dde fix: page block padding fix (#1034) 2023-05-11 18:41:13 +05:30
Anmol Singh Bhatia
1329145173 feat: custom theming (#1028)
* chore: custom theme types and constants

* feat: custom theming

* feat: preferences tab added in profile settings

* feat: remove unneccessary file

* feat:theme apply on page load

* fix: theme switch dropdown fix

* feat: color picker input, theme icon added, chore: code refactor

* style: color picker icon added

* fix: mutation fix

* fix: palette sequence fix

* chore: default custom theme palette updated

* style: join project and not authorized page theming

* fix: merge conflict

* fix: build fix and preferences tab layout fix
2023-05-11 18:40:17 +05:30
Anmol Singh Bhatia
44d49b5500 style: page detail (#1030)
* style: page detail header styling

* style: page detail ui

* style: page block, create block styling
2023-05-11 18:03:37 +05:30
Aaryan Khandelwal
1a534a3c19 feat: plane analytics (#1029)
* chore: global bar graph component

* chore: global pie graph component

* chore: global line graph component

* chore: removed unnecessary file

* chore: refactored global chart components to accept all props

* chore: function to convert response to chart data

* chore: global calendar graph component added

* chore: global scatter plot graph component

* feat: analytics boilerplate created

* chore: null value for segment and project

* chore: clean up file

* chore: change project query param key

* chore: export, refresh buttons, analytics table

* fix: analytics fetch key error

* chore: show only integer values in the y-axis

* chore: custom x-axis tick values and bar colors

* refactor: divide analytics page into granular components

* chore: convert analytics page to modal, save analytics modal

* fix: build error

* fix: modal overflow issues, analytics loading screen

* chore: custom tooltip, refactor: graphs folder structure

* refactor: folder structure, chore: x-axis tick values for larger data

* chore: code cleanup

* chore: remove unnecessary files

* fix: refresh analytics button on error

* feat: scope and demand analytics

* refactor: scope and demand and custom analytics folder structure

* fix: dynamic import type

* chore: minor updates

* feat: project, cycle and module level analytics

* style: project analytics modal

* fix: merge conflicts
2023-05-11 17:38:46 +05:30
Aaryan Khandelwal
d7928f853d chore: global graph components (#1014)
* chore: global bar graph component

* chore: global pie graph component

* chore: global line graph component

* chore: removed unnecessary file

* chore: refactored global chart components to accept all props

* chore: global calendar graph component added

* chore: global scatter plot graph component
2023-05-11 17:11:04 +05:30
Dakshesh Jain
a0553722c9 fix: settings editor state according to ai response (#1032)
* fix: placeholder and ai response not getting appended in textarea

* fix: settings editor state according to ai response
2023-05-11 17:02:20 +05:30
Anmol Singh Bhatia
34f4580b94 style: issue due date selector width fix (#1033) 2023-05-11 17:01:58 +05:30
pablohashescobar
a1d7a4ea55 fix: created by null for bulk operations (#1026) 2023-05-11 16:58:35 +05:30
pablohashescobar
abaa65b4b7 feat: analytics (#1018)
* dev: initialize plane analytics

* dev: plane analytics endpoint

* dev: update endpoint to give data with segments as well

* dev: analytics with count and effort paramters

* feat: analytics endpoints

* feat: saved analytics

* dev: remove print logs

* dev: rename x_axis to dimension in response

* dev: remove color queries

* dev: update query for None values

* feat: analytics export

* dev: update code structure send color when state or label and fix none count

* dev: uncomment try catch block

* dev: fix segment keyerror

* dev: default analytics endpoint

* dev: fix segmented results

* dev: default analytics endpoint and colors for segment

* dev: total issues and open issues by state

* dev: segment colors

* dev: fix total issue annotate

* dev: effort segmentation

* dev: total estimates and open estimates

* fix: effort when not segmented

* dev: send avatar for default analytics
2023-05-11 16:57:03 +05:30
pablohashescobar
fb165d080e feat: estimate points data in cycles list endpoint (#1015)
* feat: estimate points data in cycles list endpoint

* dev: prefetch for assignees

* dev: update sum for estimate points
2023-05-11 16:56:48 +05:30
Dakshesh Jain
083562b24c fix: placeholder and ai response not getting appended in textarea (#1031) 2023-05-11 13:41:16 +05:30
Anmol Singh Bhatia
88d3fa549a style: page block hover effect (#1017) 2023-05-11 02:27:27 +05:30
Anmol Singh Bhatia
c7deb00f2a feat: calendar view display properties (#1024)
* fix: calendar mutation fix, chore: calendar type added

* feat: calendar view display property added

* feat: calendar header, single date and single issue component added, chore: code refactor

* chore: partialupdateissue function updated

* fix: dropdown overflow fix, style: issue card styling

* fix: calendar weekly view row height fix

* feat: calendar issue card ellipsis added, fix: edit and delete mutation fix

* style: plus icon , add issue button padding and onhover effect fix

* style: calendar issue card

* style: weekly view height
2023-05-11 02:27:14 +05:30
Dakshesh Jain
4f2b106852 fix: rich text editor (#1008)
* fix: undo/redo, placeholder overlapping with text, horizontal cursor

refractor: removed a lot of state-management that was not required

* fix: forwarding ref to remirror for getting extra helper functions

* fix: icon type error

* fix: value type not supported error on page block

* style: spacing, and UX for add link

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-05-11 02:15:49 +05:30
Aaryan Khandelwal
df96d40cfa fix: views issues mutation, sidebar link highlight (#1025)
* fix: views issues mutation, sidebar link highlight

* fix: show only specific states when type filter is set

* fix: delete comment mutation

* style: bulk delete issues modal

* fix: project settings features mutation
2023-05-11 02:15:39 +05:30
vamsi
4884ecd668 dev: migrations for estimate point values 2023-05-05 19:48:38 +05:30
vamsi
c16c5b1cb2 Merge branch 'develop' of https://github.com/makeplane/plane into develop 2023-05-05 19:46:45 +05:30
guru_sainath
a69593a9e8 fix: handled token expiry validation (#1016) 2023-05-05 18:01:58 +05:30
Aaryan Khandelwal
a1de3f581f fix: layout height and overflow (#1004)
* fix: kanban height issue

* dev: Layout fixes

* dev: layout changes

* fix: layout overflow settings and fixed header

* style: filters padding fixed

* fix: hide filters if none are applied

---------

Co-authored-by: gurusainath <gurusainath007@gmail.com>
2023-05-05 17:07:29 +05:30
Rhea Jain
443878994a fix: breadcrumbs and tab updated (#1007) 2023-05-05 15:46:05 +05:30
Anmol Singh Bhatia
86cb23777e fix: bug fixes (#1000)
* fix: issue sidebar cycle and module dropdown fix

* style: my issue page

* style: date picker theming

* fix: cycle modal

* style: date picker

* fix: info icon fix

* feat: integration banner

* feat: project integration banner

* fix: module card progress bar fix

* style: integration banner

* style: workspace sidebar

* fix: cycle date checker

* fix: calendar page view dropdown
2023-05-05 15:45:53 +05:30
Aaryan Khandelwal
93c105c495 chore: track events for estimates and importers (#1012) 2023-05-05 15:45:38 +05:30
Aaryan Khandelwal
b34cf0c471 fix: ai button not working on creating a page block (#1013)
* fix: ai button not working on creating page block

* fix: build error
2023-05-05 15:45:10 +05:30
pablohashescobar
fd96c54b43 fix: cycle date check endpoint for updation (#1006)
* fix: cycle date check endpoint for updation

* dev: update the cycle date check endpoint to exclude current cycle when updating
2023-05-05 15:13:22 +05:30
pablohashescobar
993cf3faba chore: add assignee avatar in cycle endpoint (#996)
* chore: add assignee avatar in cycle endpoint

* dev: update the structure to return avatar and firstname

* dev: return distinct users

* dev: update the structure to return id

* dev: update the prefetch queryset to distinct by id

* dev: remove id from distinct

* dev: add unique condition
2023-05-05 15:13:03 +05:30
pablohashescobar
1bf1b63fff fix: estimate points update (#1003)
* fix: estimate points hub

* fix: estimate points update

* fix: estimate points bulk_update
2023-05-05 15:12:38 +05:30
pablohashescobar
336220bd98 feat: return workspace and project details in estimate endpoints (#1009) 2023-05-05 15:12:22 +05:30
pablohashescobar
5b0dc43bae docs: update readme (#1010)
docs: update readme
2023-05-05 15:12:01 +05:30
pablohashescobar
e0bec31586 feat: workspace detail for imports (#1011) 2023-05-05 15:11:45 +05:30
pablohashescobar
a2825208b8 docs: update self hosting section in readme (#1002)
docs: update self hosting section in readme
2023-05-03 23:53:53 +05:30
pablohashescobar
c3387ba974 fix: environment variables for the services (#1001) 2023-05-03 21:31:06 +05:30
pablohashescobar
baa9c30449 fix: single docker file (#999) 2023-05-03 16:48:04 +05:30
pablohashescobar
849e2d658a dev:: update docker file for frontend (#998) 2023-05-03 16:39:13 +05:30
pablohashescobar
c7f1090914 fix: docker setup (#987)
* removing dependencies from .env

* dev: Passing the arguments from docker compose to DockerWeb in nextjs to define base environment variables

* dev: removed env from docker-compose and taking the env from shell

* dev: Updated docker file and used console in signin to test the env from docker

* dev: Docker setting env variables via shell

* removed env variables and args

* Update Dockerfile.web

* Update Dockerfile.web

* Update signin.tsx

* .

* .

* dev: Added BASE_URL from docker

* dev: Updated docker config

* dev: scripts for replacing variable during runtime

* dev: entrypoint script

* dev: update replace env script and update docker entrypoint command for frontend

* dev: update replace env script to not update process.env

* dev: update docker file to add missing variables as well

* fix: updated docker compose yml and web

* dev: create start script to run docker and update script for replacing variables

* dev: update setup script and env example script to create variables in the root of the project

* .

* dev: update docker compose hub

* dev: update docker compose hub command

* dev: update docker compose yml and env example

* dev: update docker compose hub

* dev: single docker

---------

Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
2023-05-03 13:36:55 +05:30
Vamsi Kurama
563bb12b9b Merge pull request #993 from makeplane/stage-release
promote: stage-release to prod
2023-05-03 01:03:31 +05:30
vamsi
e3d43298df Merge branch 'stage-release' of https://github.com/makeplane/plane into stage-release 2023-05-03 00:57:04 +05:30
pablohashescobar
b36565298f Merge pull request #992 from makeplane/develop
promote: develop to stage-release
2023-05-03 00:55:14 +05:30
guru_sainath
b26e8bd956 update: UI for google auth button and loadin toggle in signin screen (#991) 2023-05-03 00:48:24 +05:30
pablohashescobar
e5703dbe70 Merge pull request #990 from makeplane/develop
promote: develop to stage-release
2023-05-02 23:37:25 +05:30
Anmol Singh Bhatia
498d6d2b02 style: onboarding logo and style (#989) 2023-05-02 23:31:36 +05:30
pablohashescobar
1d22817ede fix: import user invite emails (#986) 2023-05-02 20:09:54 +05:30
Anmol Singh Bhatia
483c49d0ff fix: ui and bug fixes (#980)
* style: sub issue theming

* style: shortcut modal theming

* style: blocking and blocked by modal theming

* fix: filter labels dropdown width fix

* style: display properties

* chore: workspace invite

* style: invite co workers theming

* style: create workspace theming

* style: attachment theming

* style: workspace sidebar theming

* style: issue property theming

* style: create module modal lead icon

* style: label list modal theming

* delete attachment and member modal theming

* style: transfer issue modal

* style: delete estimate modal theming

* style: module form status

* style: delete state modal theming

* style: shortcut modal

* style: onboarding logo

* style: onboarding command menu
2023-05-02 20:00:33 +05:30
guru_sainath
0fa9451633 fix: workspace integration github repos issue resolved (#988) 2023-05-02 18:15:24 +05:30
pablohashescobar
46237c5431 Merge pull request #866 from makeplane/develop
promote: develop to stage-release
2023-05-02 01:57:04 +05:30
vamsi
20e400487f dev: migrations SlackProjectSync; new attributes to cycle, importer and module 2023-05-02 01:55:15 +05:30
pablohashescobar
99fb3c9bfe chore: log cycle delete and cycle issue delete activities (#975)
* chore: log cycle delete and cycle issue delete activities

* dev: remove print logs
2023-05-02 01:21:48 +05:30
pablohashescobar
88200a93bf feat: delete imported data as well when the import is deleted (#974) 2023-05-02 00:53:08 +05:30
pablohashescobar
b2ad071608 fix: bulk modules importer (#973) 2023-05-02 00:52:52 +05:30
pablohashescobar
21992f540f chore: importer user invite email (#972) 2023-05-02 00:52:36 +05:30
pablohashescobar
742731cbe6 chore: log module delete and module issue delete activities (#976) 2023-05-02 00:51:04 +05:30
pablohashescobar
c6878b9b0f fix: page access update (#977) 2023-05-02 00:50:41 +05:30
pablohashescobar
887cac5612 feat: filter issues by estimate points (#978) 2023-05-02 00:50:10 +05:30
guru_sainath
982566b5b4 Merge pull request #982 from makeplane/fix/slack-integration
fix: slack with project integration bug fixes
2023-05-02 00:47:36 +05:30
gurusainath
2dc5655886 fix: slack with project integration bug fixes 2023-05-02 00:40:47 +05:30
guru_sainath
160b4a4390 Merge pull request #970 from makeplane/refactor/estimates_modal
refactor: estimates payload generate function
2023-04-29 14:17:29 +05:30
guru_sainath
f187d9512a Merge pull request #969 from makeplane/style/workspace_sidebar
style: workspace sidebar
2023-04-29 14:15:41 +05:30
Aaryan Khandelwal
53d3ea1979 refactor: estimates payload generate function 2023-04-29 03:27:03 +05:30
anmolsinghbhatia
13d76d4325 style: workspace sidebar 2023-04-28 20:51:47 +05:30
guru_sainath
25338cc804 Merge pull request #968 from makeplane/style/onboarding_screens
style: onboarding screens, invitations page
2023-04-28 20:50:40 +05:30
Aaryan Khandelwal
eaa750b025 fix: initial onboarding step 2023-04-28 20:47:29 +05:30
Aaryan Khandelwal
81d9c70026 style: onboarding screens, invitations page 2023-04-28 20:46:07 +05:30
guru_sainath
93fb4fe1e9 Merge pull request #959 from makeplane/feat/product_update_modal
feat: product update modal
2023-04-28 19:38:33 +05:30
guru_sainath
b8e6d072cc Merge pull request #967 from makeplane/style/ui_fixes
style: command k item and cycle icon theming
2023-04-28 19:03:16 +05:30
anmolsinghbhatia
1220cebe50 style: command k item and cycle icon theming 2023-04-28 18:52:53 +05:30
anmolsinghbhatia
9464b5c00e style: product update modal 2023-04-28 18:29:01 +05:30
anmolsinghbhatia
3fae0f39c0 chore: product update interface 2023-04-28 18:28:43 +05:30
Kunal Vishwakarma
73a757e337 fix: added the decoded url for slack integration popup (#958) 2023-04-28 17:55:57 +05:30
Kunal Vishwakarma
bb40b7feb5 chore: removed email span from invite member page (#956) 2023-04-28 17:49:38 +05:30
Aaryan Khandelwal
3175ce9136 style: create project modal (#957) 2023-04-28 17:49:29 +05:30
Anmol Singh Bhatia
0b9b4bb289 fix: cycle & module mutation , feat: cycle & module toast alerts (#962)
* fix: cycle remove issue mutation

* fix: module remove issue mutation

* feat: issue removed toast alert added
2023-04-28 17:49:16 +05:30
Anmol Singh Bhatia
f0f24b6fc4 style: module , cycle & icon styling (#963)
* style: target icon updated

* style: cycle card theming

* style: module card theming

* style: no current cycle message
2023-04-28 17:49:04 +05:30
Anmol Singh Bhatia
429dffb055 fix: cycle & module sidebar default tab fix (#964) 2023-04-28 17:48:40 +05:30
guru_sainath
6e5c85cd6e Merge pull request #961 from makeplane/style/issue_list_responsive
style: responsive design for issue list in 'list' view
2023-04-28 10:49:54 +05:30
Dakshesh Jain
2adcb163fb Merge branch 'develop' of https://github.com/makeplane/plane into style/issue_list_responsive 2023-04-25 19:44:19 +05:30
Dakshesh Jain
028a350cd1 style: issue list dropdown on next line 2023-04-25 19:43:52 +05:30
Anmol Singh Bhatia
d021a5696a fix: sub issues list fix (#960) 2023-04-25 19:00:20 +05:30
Dakshesh Jain
a5c18e37c1 Merge branch 'develop' of https://github.com/makeplane/plane into style/issue_list_responsive 2023-04-25 18:36:24 +05:30
Dakshesh Jain
8e611664a8 style: made issue list view responsive 2023-04-25 18:35:58 +05:30
anmolsinghbhatia
3480b450f2 fix: build fix 2023-04-25 18:10:23 +05:30
anmolsinghbhatia
a7d9591c44 feat: product updates tag and date added 2023-04-25 18:02:13 +05:30
anmolsinghbhatia
1364c842e0 feat: product updates button added 2023-04-25 17:33:53 +05:30
anmolsinghbhatia
eb99b4adc9 feat: markdown to custom component 2023-04-25 16:54:12 +05:30
anmolsinghbhatia
6684dd4ab6 feat: product updates service added 2023-04-25 16:51:50 +05:30
Kunal Vishwakarma
529ed4432c chore: fixed sidebar highlight not working (#952) 2023-04-25 12:10:05 +05:30
Kunal Vishwakarma
8c1ad69f0c chore: changed pages empty state image (#954) 2023-04-25 12:09:29 +05:30
Kunal Vishwakarma
c23de32b03 chore: added create label inside of pages label select (#944)
* chore: added create label inside of pages label select

* chore: used footer instead of props
2023-04-25 12:08:56 +05:30
Rhea Jain
83ac1f4e4c chore: invite text update (#955) 2023-04-25 12:07:02 +05:30
Anmol Singh Bhatia
cee9695a4a feat: sub issues progress (#895) 2023-04-25 11:38:13 +05:30
Aaryan Khandelwal
c9f866e538 style: profile settings, activity theming (#951) 2023-04-24 18:53:30 +05:30
Aaryan Khandelwal
7d96adcb70 chore: empty state for estimates (#950) 2023-04-24 18:53:18 +05:30
Aaryan Khandelwal
c5b034385f chore: added custom toggle switch everywhere (#949) 2023-04-24 18:53:07 +05:30
Aaryan Khandelwal
ff7f31c35b style: calendar view (#948)
* style: calendar view

* chore: add issue button positioning
2023-04-24 18:10:44 +05:30
Aaryan Khandelwal
7234d6f68b style: workspace and project settings (#946) 2023-04-24 13:21:09 +05:30
Aaryan Khandelwal
d8a5b8d848 style: imports theming (#945) 2023-04-24 13:20:41 +05:30
Aaryan Khandelwal
5412e09701 chore: empty input fields text (#943) 2023-04-24 11:28:05 +05:30
Aaryan Khandelwal
7116acc331 style: auth pages theming (#942) 2023-04-24 11:20:14 +05:30
Aaryan Khandelwal
ae26b17cab style: filters list theming (#941) 2023-04-24 11:20:02 +05:30
Aaryan Khandelwal
2ec8fbab34 style: modals theming (#940)
* style: existing issues list modal

* style: parent issues list modal

* style: issue modal

* style: cycle modal

* style: module modal

* style: view modal

* style: page modal

* style: delete modals
2023-04-24 11:19:53 +05:30
Aaryan Khandelwal
213dc3f8e8 style: signin page theming (#938) 2023-04-24 11:19:43 +05:30
Aaryan Khandelwal
4b02886c40 chore: remove outline button component (#937) 2023-04-23 01:43:58 +05:30
Aaryan Khandelwal
8eddc4b304 fix: points not updating while editing estimate (#935) 2023-04-23 00:00:46 +05:30
Aaryan Khandelwal
169a60723b style: project settings theming (#936)
* style: project and workspace members theming

* style: project features theming

* style: project settings states theming

* style: project settings labels theming

* style: project settings integrations theming
2023-04-22 23:46:19 +05:30
Kunal Vishwakarma
c80094581e feat: frontend slack integration (#932)
* feat: slack integration frontend

* feat: slack integration frontend complete

* Co-authored-by: Aaryan Khandelwal <aaryan610@users.noreply.github.com>
2023-04-22 21:54:50 +05:30
pablohashescobar
d99f669b89 dev: add s3 url for staging (#934) 2023-04-22 18:21:22 +05:30
Aaryan Khandelwal
99dd1b9f0c chore: state delete validation (#930) 2023-04-22 18:19:35 +05:30
pablohashescobar
48e77ea81b remove: state delete issue validation endpoint (#929) 2023-04-22 18:18:08 +05:30
pablohashescobar
0be6738715 dev: back migration for integrations (#933) 2023-04-22 18:17:53 +05:30
Anmol Singh Bhatia
d041d8be6b fix: cycle date validation (#922) 2023-04-22 18:17:17 +05:30
pablohashescobar
e53847c59e feat: module view props (#882) 2023-04-22 18:16:16 +05:30
pablohashescobar
16781a71fe feat: cycle view props (#881) 2023-04-22 18:16:05 +05:30
pablohashescobar
fb4535b294 feat: slack integration (#874)
* feat: init slack integration

* dev: create model and update existing view for slack

* dev: update slack sync model and create view to install slack

* dev: workspace integration query

* dev: update the metadata validation for access_token and team_id and save config to database

* dev: update validation for team_id

* dev: update validation

* dev: update validations

* dev: remove bot access token field from sync

* dev: handle integrity exception
2023-04-22 18:15:52 +05:30
pablohashescobar
33a904bc3e chore: added estimate bulk endpoint for retrieving and updating (#919)
* chore: added estimate bulk endpoint for retrieving and updating

* chore: estimate endpoints

* fix: retrieve project estimate

* dev: handle integrity error check
2023-04-22 01:04:20 +05:30
pablohashescobar
0d264838a9 remove: print exception instead use capture to log it (#926) 2023-04-22 01:04:07 +05:30
Aaryan Khandelwal
c638b6aba6 chore: new estimates workflow (#927)
* chore: new services for estimates

* chore: new estimates workflow
2023-04-22 00:59:57 +05:30
Aaryan Khandelwal
cb814dd68b chore: added new restricted workspace slugs (#928) 2023-04-22 00:57:16 +05:30
Aaryan Khandelwal
e17c824119 style: dashboard styling (#924) 2023-04-22 00:56:17 +05:30
Anmol Singh Bhatia
68930c256f style: sidebar theming (#925)
* style: sidebar workspace dropdown theming

* style: progress chart and progress bar theming

* style: module and cycle sidebar theming
2023-04-22 00:15:45 +05:30
Anmol Singh Bhatia
e59137f6f2 style: cycle and module theming (#923)
* style: cycle theming

* style: module theming
2023-04-21 17:40:57 +05:30
Aaryan Khandelwal
7f235739bd style: projects page theming (#921) 2023-04-21 17:40:49 +05:30
Vamsi Kurama
20162050c3 Merge pull request #833 from kylewlacy/self-hosting-tweaks
Add a few more options for self-hosting
2023-04-21 16:47:36 +05:30
Aaryan Khandelwal
06ad0d0f7a style: views theming (#920) 2023-04-21 16:30:16 +05:30
Aaryan Khandelwal
cfd7e1d154 fix: theming fixes (#914) 2023-04-21 15:48:06 +05:30
Anmol Singh Bhatia
fdf7ea1f82 feat: copy page link added (#915) 2023-04-21 15:46:28 +05:30
Anmol Singh Bhatia
8f12d3d01b style: calendar theming (#918) 2023-04-21 15:45:57 +05:30
Aaryan Khandelwal
62dc6c2f3f fix: comment box placeholder (#909) 2023-04-21 12:31:34 +05:30
Aaryan Khandelwal
6f03022f65 chore: changed light mode colors (#913) 2023-04-21 10:46:04 +05:30
Aaryan Khandelwal
f2701a12ea style: pages theming (#912) 2023-04-21 02:15:21 +05:30
Anmol Singh Bhatia
9129a6cde2 feat: calendar filters (#908)
* feat: hiding unnecessary filters for calendar view

* feat: filters for calendar view

* feat: module and cycle calendar view filters
2023-04-21 01:42:09 +05:30
Rhea Jain
2ba4594b29 chore: attachements button text update (#910) 2023-04-21 01:41:47 +05:30
Aaryan Khandelwal
165d16e32b style: issue details page (#911) 2023-04-21 00:34:22 +05:30
Aaryan Khandelwal
73388195ef chore: page block input (#907)
* fix: sidebar workspace dropdown logo

* chore: changed textarea to input for page block
2023-04-20 19:04:10 +05:30
pablohashescobar
4dda4ec610 chore: single endpoint to create estimate and estimate points (#897) 2023-04-20 18:14:38 +05:30
pablohashescobar
e68a5382f9 feat: sub issue state distribution (#885)
* feat: sub issue state distribution

* dev: update the response structure to match consistency

* dev: update the query for sub issue distribution to include 0 issue groups as well
2023-04-20 18:14:24 +05:30
pablohashescobar
5b6caadd6f chore: state delete validations endpoint (#880) 2023-04-20 18:14:05 +05:30
pablohashescobar
73a8bbb31f feat: release information endpoint (#876)
* dev: init release notes

* feat: API endpoint to fetch get last 5 release information
2023-04-20 18:13:49 +05:30
Aaryan Khandelwal
952d35dd79 style: list and kanban view theming (#906)
* fix: sidebar workspace dropdown logo

* style: list and kanban view theming
2023-04-20 18:13:21 +05:30
Anmol Singh Bhatia
170b3d6eec fix: cycle and module sidebar fix (#905) 2023-04-20 18:09:01 +05:30
Anmol Singh Bhatia
d04a422054 feat: calendar add new issue (#901) 2023-04-20 14:11:11 +05:30
Aaryan Khandelwal
affc7655f7 fix: sidebar workspace dropdown logo (#903) 2023-04-20 13:56:09 +05:30
Aaryan Khandelwal
50c78628b3 feat: themes (#902)
* chore: add next theme and initial setup

* chore: add dark mode colors to layouts

* chore: user general setting page theming

* chore: dashboard theming

* chore: project page theming

* chore: workspace setting page theming

* chore: my issue page theming

* chore: cmdk theming

* chore: change hardcode bg and text color to theme

* chore: change color name according to the design

* style: fix card in the dashboard

* style: fix merge conflict design issues

* style: add light high contrast and dark high contrast

* style: fix cmd k menu color and selection

* feat: change theme from cmdk menu

* chore: add multiple theme field to custom theme

* chore: removed custom theming

* fix: build error

---------

Co-authored-by: Saheb Giri <iamsahebgiri@gmail.com>
2023-04-20 13:42:16 +05:30
Aaryan Khandelwal
3c2f5d12ed feat: themes (#902)
* chore: add next theme and initial setup

* chore: add dark mode colors to layouts

* chore: user general setting page theming

* chore: dashboard theming

* chore: project page theming

* chore: workspace setting page theming

* chore: my issue page theming

* chore: cmdk theming

* chore: change hardcode bg and text color to theme

* chore: change color name according to the design

* style: fix card in the dashboard

* style: fix merge conflict design issues

* style: add light high contrast and dark high contrast

* style: fix cmd k menu color and selection

* feat: change theme from cmdk menu

* chore: add multiple theme field to custom theme

* chore: removed custom theming

* fix: build error

---------

Co-authored-by: Saheb Giri <iamsahebgiri@gmail.com>
2023-04-20 13:41:24 +05:30
Rhea Jain
9f04933957 chore: upload button and github banner text update (#899)
* chore: upload button and github banner text update

* chore: attachments button text fix
2023-04-20 12:16:13 +05:30
Anmol Singh Bhatia
8d37a3e58b feat: cycle list tab context (#900) 2023-04-20 12:11:33 +05:30
Aaryan Khandelwal
4f61c5d552 fix: pages access mutation (#896) 2023-04-20 12:09:55 +05:30
Aaryan Khandelwal
7149d20601 chore: change pages icon (#894) 2023-04-20 12:09:48 +05:30
Aaryan Khandelwal
d30a88832a fix: reset estimates modal form after create/update (#893) 2023-04-20 12:09:35 +05:30
Rhea Jain
ebce364104 chore: changed loading text (#898) 2023-04-19 20:52:52 +05:30
Aaryan Khandelwal
c5206a7792 feat: separate filters for cycles and modules (#892) 2023-04-19 17:25:31 +05:30
Anmol Singh Bhatia
390b837561 fix: invite button validation , style: workspace screen (#877)
* fix: invite button validation

* style: workspace screen tab height
2023-04-19 15:41:46 +05:30
Anmol Singh Bhatia
fb1932e309 fix : create issue modal (#875)
* fix: label list bug fix

* fix: assignee and label count removed

* fix: assignee and label fix
2023-04-19 15:41:17 +05:30
Dakshesh Jain
ac125965eb fix: add tlds (#851) 2023-04-19 15:40:47 +05:30
Dakshesh Jain
63a36fb25d feat: jira importer (#879)
* feat: jira importer

* fix: yarn lock

* fix: displaying correct count of users that are been imported

* fix: showing workspace member in import users
2023-04-19 15:40:31 +05:30
pablohashescobar
2b280935a1 chore: update state create endpoint to send error response on integrity error (#869)
* chore: update state create endpoint to send error response on integrity error

* dev: update status code for general exception
2023-04-18 12:25:22 +05:30
Kunal Vishwakarma
be5ef61428 fix: join project button (#873) 2023-04-18 10:55:32 +05:30
Aaryan Khandelwal
1627a587ee refactor: workspace integrations code (#872) 2023-04-18 10:54:45 +05:30
Aaryan Khandelwal
682a1477fb chore: create/update estimate points validation (#871) 2023-04-18 10:54:19 +05:30
Kyle Lacy
ea87823478 Add $NEXT_PUBLIC_EXTRA_IMAGE_DOMAINS to add domains for Next Image plugin 2023-04-17 16:30:36 -07:00
Kyle Lacy
b8c06b3121 Add $AWS_S3_ENDPOINT_URL to .env.example 2023-04-17 14:08:47 -07:00
Kyle Lacy
ca2366aa9b Use env var to set AWS_S3_ENDPOINT_URL setting 2023-04-17 14:07:00 -07:00
Aaryan Khandelwal
acff6396f9 chore: create/update state duplicate name error (#870) 2023-04-18 01:15:39 +05:30
Aaryan Khandelwal
fa5c994ddc chore: remove redundant console logs (#868) 2023-04-18 01:15:26 +05:30
Aaryan Khandelwal
5f20e65ca6 style: list view styling reduced (#867) 2023-04-18 01:15:10 +05:30
Kyle Lacy
792162ae66 Remove redundant $REDIS_BROKER_SSL setting
A fix was already pushed upstream that made this setting unnecessary
2023-04-17 12:37:58 -07:00
Kyle Lacy
e22f552ea0 Merge branch 'develop' into self-hosting-tweaks 2023-04-17 12:30:24 -07:00
pablohashescobar
396fbc4ebb fix: redis url for docker in production settings (#865) 2023-04-17 22:38:52 +05:30
Vamsi Kurama
d2a58bf04a Merge pull request #862 from makeplane/stage-release
promote: staging to production v0.5
2023-04-17 19:08:10 +05:30
Vamsi Kurama
c51407c85e Merge branch 'master' into stage-release 2023-04-17 19:07:33 +05:30
Vamsi Kurama
3ed937378f Merge pull request #861 from makeplane/develop
promote: patches from develop to stage-release
2023-04-17 18:48:21 +05:30
Dakshesh Jain
0fa3a8c3e3 fix: removed useEffect for project detail fetch error (#860) 2023-04-17 18:38:07 +05:30
Aaryan Khandelwal
bd0cfef02f fix: delete import (#859) 2023-04-17 18:34:18 +05:30
Dakshesh Jain
7aa9e0bba1 fix: project authorization api fetch keys (#858) 2023-04-17 18:22:04 +05:30
Vamsi Kurama
718f62a898 Merge pull request #857 from makeplane/develop
promote: develop to stage-release
2023-04-17 17:47:19 +05:30
Kunal Vishwakarma
d26d01ace4 chore: filters spacing (#856) 2023-04-17 17:42:02 +05:30
Vamsi Kurama
60e44fc1a2 Merge pull request #847 from makeplane/chore/my_issues_endpoint
chore: my issues endpoint to return attachment and link count
2023-04-17 17:39:38 +05:30
Anmol Singh Bhatia
45eaa23ed0 style: dashboard content (#855) 2023-04-17 17:36:02 +05:30
Aaryan Khandelwal
600fedd5ba fix: undefined block content (#854) 2023-04-17 17:21:15 +05:30
Aaryan Khandelwal
6de54089cd fix: show proper issues list if no filters are present (#853) 2023-04-17 17:10:36 +05:30
Aaryan Khandelwal
dc53708109 chore: show workspace members (#852) 2023-04-17 16:41:16 +05:30
Aaryan Khandelwal
f5351e4419 fix: remove filters function (#846) 2023-04-17 15:03:56 +05:30
Aaryan Khandelwal
819508d5fc fix: remirror placeholder (#849) 2023-04-17 15:03:44 +05:30
Kunal Vishwakarma
0beb654069 chore: worked on making issue list padding consistent (#850) 2023-04-17 15:01:22 +05:30
Anmol Singh Bhatia
98cef0e1e8 fix: my issue page display property (#848) 2023-04-17 14:45:51 +05:30
Aaryan Khandelwal
8a6036a20a fix: drop to delete box zindex (#843) 2023-04-17 14:13:32 +05:30
pablohashescobar
85b6c78e75 chore: my issues endpoint to return attachment and link count 2023-04-17 14:03:19 +05:30
Anmol Singh Bhatia
3f401b0fc5 feat: page tab context (#845)
* feat: page list tab context added

* fix: build fix
2023-04-17 13:30:39 +05:30
Anmol Singh Bhatia
365c758a25 fix: create update view modal fix (#842) 2023-04-17 12:24:30 +05:30
Aaryan Khandelwal
ac98381f23 chore: remove estimate option from my issues (#839) 2023-04-17 12:00:30 +05:30
Kunal Vishwakarma
3e436179fe chore: added default state for issues (#840) 2023-04-17 11:54:22 +05:30
Aaryan Khandelwal
e23075b7b9 chore: no estimates option, estimates activity (#838) 2023-04-17 11:30:48 +05:30
pablohashescobar
61761fedc5 chore: remove view filter validation while creating or updating view (#836) 2023-04-17 11:15:38 +05:30
Kunal Vishwakarma
5a36a7931f fix: removed extra spaces form estimate points brackets (#837) 2023-04-17 11:15:06 +05:30
Aaryan Khandelwal
363c5c8ec4 fix: join project mutation (#835)
* fix: join project mutation

* chore: remove imports
2023-04-17 10:27:20 +05:30
Kyle Lacy
5e5d1a4699 Update .env.example with newly-added env vars 2023-04-15 12:56:43 -07:00
Kyle Lacy
e2294f9105 Add EMAIL_FROM setting to change sender email for messages 2023-04-15 12:51:23 -07:00
Kyle Lacy
f757d8232b Add setting to disable extra TLS config for Celery broker connection 2023-04-15 12:32:54 -07:00
Kyle Lacy
6af54ebbe7 Fix typo in `.env.example 2023-04-15 12:32:00 -07:00
Kyle Lacy
3913cf571f Make SMTP port and TLS configurable 2023-04-15 12:00:02 -07:00
Aaryan Khandelwal
8638170a98 fix: cycles and modules sidebar mutation (#831) 2023-04-14 19:40:00 +05:30
Vamsi Kurama
ebff5d8c54 Merge pull request #830 from makeplane/develop
promote: dev to stage-release
2023-04-14 17:06:19 +05:30
vamsi
b7ce69c220 dev: migrations estimate points and themes 2023-04-14 17:04:02 +05:30
Vamsi Kurama
e4da207df5 Merge pull request #768 from makeplane/feat/workspace_themes
feat: workspace themes
2023-04-14 16:56:32 +05:30
Vamsi Kurama
3a0c5bab76 Merge pull request #804 from makeplane/fix/magic_sign_in
fix: connection error when signing in with code
2023-04-14 16:56:20 +05:30
Vamsi Kurama
1cd1505c7d Merge pull request #805 from makeplane/chore/celery_production_settings
chore: production settings for celery
2023-04-14 16:56:00 +05:30
Vamsi Kurama
bc7fab96c3 Merge pull request #812 from makeplane/fix/parent_issue_search
fix: parent issue search
2023-04-14 16:55:20 +05:30
Vamsi Kurama
a358260a22 Merge pull request #817 from makeplane/chore/issue_estimate_points
chore: set default value as null for estimate point
2023-04-14 16:54:43 +05:30
Dakshesh Jain
3b103da6a3 chore: added unsplash flag for self-hosted (#829)
* chore: added unsplash flag for self hosted

* fix: removed actual code and only using flag

* refactor: removed extra variable
2023-04-14 16:52:31 +05:30
Aaryan Khandelwal
23b4145565 chore: added session recorder key to env (#827) 2023-04-14 16:51:24 +05:30
Anmol Singh Bhatia
5848c326c7 fix: cycle and module sidebar fix (#828) 2023-04-14 16:44:06 +05:30
Aaryan Khandelwal
ce253b3cc9 refactor: drag function (#826) 2023-04-14 16:41:28 +05:30
Vamsi Kurama
3817511024 Merge pull request #824 from makeplane/feat/session_recorder
feat: session recorder
2023-04-14 16:09:31 +05:30
Kunal Vishwakarma
f50872f2a9 fix: empty issue design (#821)
* fix: empty issue design

* chore: removed unused imports
2023-04-14 16:04:16 +05:30
Anmol Singh Bhatia
a0b8f7188f fix: cycle card (#825) 2023-04-14 16:03:11 +05:30
Aaryan Khandelwal
2950877767 feat: session recorder integrated 2023-04-14 15:27:14 +05:30
Aaryan Khandelwal
c7d930f89b chore: add env flag to enable session recorder conditionally (#822) 2023-04-14 15:17:35 +05:30
pablohashescobar
81da8715d5 chore: update bug report template to include browser environment as well (#820)
* chore: update bug report template to include browser environment as well

* chore: update type to dropdown
2023-04-14 00:45:03 +05:30
pablohashescobar
b4c8323886 chore: set default value as null for estimate point 2023-04-13 19:54:34 +05:30
Anmol Singh Bhatia
c3ffd233a6 style: workspace url (#816) 2023-04-13 19:33:22 +05:30
Aaryan Khandelwal
3fa6185b63 fix: drag and drop function (#815)
* fix: kanban drag and drop

* fix: kanban board issue dnd mutation
2023-04-13 19:09:55 +05:30
Dakshesh Jain
6de94efc7d style: removed static 'app.plane.so' (#813) 2023-04-13 18:28:23 +05:30
pablohashescobar
0cd6d9d570 fix: parent issue search 2023-04-13 17:49:09 +05:30
Aaryan Khandelwal
657241c9c1 feat: clarity script added (#807) 2023-04-13 16:17:21 +05:30
Anmol Singh Bhatia
dc9ce5101c fix: workspace url error message (#809) 2023-04-13 15:46:25 +05:30
Kunal Vishwakarma
3457411c6a style: issue list (#798)
* style: issue list

* chore: changed the empty state images
2023-04-13 15:39:05 +05:30
Aaryan Khandelwal
b7a7508d5d fix: workspace dashboard duplicate keys (#803) 2023-04-13 15:38:43 +05:30
Dakshesh Jain
484a88d881 fix: unusual redirection on onboarding (#808) 2023-04-13 15:38:00 +05:30
pablohashescobar
cd69b06e5e fix: error message for jira importers (#794) 2023-04-13 00:34:53 +05:30
pablohashescobar
c4609b95cd fix: remove length check condition when updating issue property (#791) 2023-04-13 00:34:37 +05:30
pablohashescobar
6eb7ec0697 fix: typo in url for bulk creating labels (#788) 2023-04-13 00:34:23 +05:30
pablohashescobar
e232d39f0e feat: track estimate points in issue activity (#762)
* feat: track estimate points in issue activity

* dev: update comment
2023-04-13 00:34:12 +05:30
pablohashescobar
8a26fd0a97 fix: issue link activity (#761) 2023-04-13 00:34:02 +05:30
pablohashescobar
537a82028e fix: attachment activity (#760) 2023-04-13 00:33:50 +05:30
pablohashescobar
440ed08728 fix: issue attachment delete (#759) 2023-04-13 00:33:37 +05:30
pablohashescobar
c199e76038 chore: production settings for celery 2023-04-13 00:31:06 +05:30
pablohashescobar
b40fd4bbc2 fix: connection error when signing in with code 2023-04-12 19:55:31 +05:30
Anmol Singh Bhatia
5190ea7280 fix: send code btn fix (#802) 2023-04-12 19:03:29 +05:30
Dakshesh Jain
db488338fb fix: weird redirection in index page (#801) 2023-04-12 19:03:08 +05:30
Anmol Singh Bhatia
9196fb4562 style: onboarding screen cards (#800) 2023-04-12 19:01:46 +05:30
Saheb Giri
34ff8fecc5 feat: add create page option in cmdk menu (#799) 2023-04-12 19:01:19 +05:30
Anmol Singh Bhatia
d6dbfdc731 feat: page improvement (#797)
* feat: remove label icon added

* feat: block menu dropdown state added

* feat: page info icon added and  style: overflow title and label fix
2023-04-12 18:07:50 +05:30
Anmol Singh Bhatia
f2e8add29d feat: attachment and link display properties (#796)
* feat: attachment and link count added

* fix: build fix
2023-04-12 15:33:30 +05:30
Saheb Giri
032ef831b2 feat: now user can edit view (#793)
* feat: now user can edit view

* fix: build error
2023-04-12 15:33:21 +05:30
Kunal Vishwakarma
0f9812cf2c chore: added estimate delete modal (#792) 2023-04-12 15:03:04 +05:30
Aaryan Khandelwal
f734aad10d fix: minor pages bugs (#786)
* fix: dashboard workspace activity mutation

* fix/minor_pages_bugs
2023-04-11 23:19:47 +05:30
pablohashescobar
6279a04267 feat: attachment and link count in issues list (#777) 2023-04-11 18:47:36 +05:30
pablohashescobar
ce26bed44a fix: jira importer info endpoint to get query params (#776) 2023-04-11 18:47:18 +05:30
Anmol Singh Bhatia
88d2adddc7 style: create issue modal icon (#784) 2023-04-11 18:46:39 +05:30
Kunal Vishwakarma
e4e66b3ae4 style: pages UI (#769)
* style: pages ui

* chore: added toast alert and tooltip

* fix: fixed issues in pages block

* fix: ai buttons inside pages block
2023-04-11 18:18:49 +05:30
Aaryan Khandelwal
f1f716e8f6 fix: estimates bugs (#785)
* fix: dashboard workspace activity mutation

* fix: minor bugs
2023-04-11 18:17:47 +05:30
Anmol Singh Bhatia
61b9e7a161 feat: issue activity logs (#782)
* feat: attachment, link and estimate activity log added in issue detail page

* feat: attachment, link and estimate activity log added in profile activity section
2023-04-11 18:14:36 +05:30
Kunal Vishwakarma
dfa3a7b78d feat: estimates (#783)
* chore: use estimate points hook created

* chore: user auth layer

* fix: build error

* chore: estimate crud and validation

* fix: build errors

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-04-11 17:54:01 +05:30
Anmol Singh Bhatia
d5c2965946 fix: workspace joining state fix (#780) 2023-04-11 17:13:06 +05:30
Kunal Vishwakarma
cfa283116b chore: added remove workspace image in workspace settings (#781) 2023-04-11 17:12:34 +05:30
Aaryan Khandelwal
725c9375ea fix: onboarding loop (#775)
* fix: dashboard workspace activity mutation

* fix: onboarding loop
2023-04-11 12:25:21 +05:30
Anmol Singh Bhatia
22c1f6f8e2 feat: workspace name validation added (#767) 2023-04-11 12:11:41 +05:30
Anmol Singh Bhatia
748e5e7fb7 fix: project setting identifier (#766)
* fix: project setting identifier validation added

* fix: project setting identifier label fix
2023-04-11 12:11:15 +05:30
Aaryan Khandelwal
7aa0ace555 fix: pages access (#754)
* fix: dashboard workspace activity mutation

* fix: page access operation
2023-04-11 12:10:22 +05:30
Anmol Singh Bhatia
f2c5bb5c03 fix: workspace join button fix (#774) 2023-04-11 10:12:33 +05:30
pablohashescobar
800075b781 fix: worker script (#773) 2023-04-11 09:25:33 +05:30
vamsi
6865cf4b54 chore: ssl config for REDIS connections to celery 2023-04-11 00:04:03 +05:30
pablohashescobar
bc457846fe chore: move theme setting in user level from workspace level 2023-04-10 23:19:01 +05:30
Saheb Giri
d411cd7576 style: redesign view (#770)
* style: add new design to the view item

* feat: add no of filters
2023-04-10 22:46:09 +05:30
pablohashescobar
2dbe1dd401 fix: remove migrate command from worker script (#772) 2023-04-10 22:44:11 +05:30
pablohashescobar
ec3f891b4a chore: update doc redirection url in user welcome email (#771) 2023-04-10 21:29:54 +05:30
pablohashescobar
b6c911f484 feat: workspace themes 2023-04-10 18:14:09 +05:30
Anmol Singh Bhatia
fc48fb97d1 style: attachment upload button (#765) 2023-04-10 18:07:40 +05:30
Vamsi Kurama
3618f79f89 Merge pull request #764 from makeplane/fix/setup
dev: fix setup.sh causing tr Illegal byte sequence
2023-04-10 17:45:20 +05:30
vamsi
ea563d20a3 dev: fix setup.sh causing tr Illegal byte sequence 2023-04-10 17:43:19 +05:30
Vihar Kurama
805b8f47cc Update Readme.md - Removed status section 2023-04-10 15:15:34 +05:30
Vihar Kurama
5f216fbbbc Merge pull request #753 from makeplane/docker-hub-hotfix
Create docker-compose-hub.yml
2023-04-10 14:26:51 +05:30
Kunal Vishwakarma
33ea1cb9d3 chore: added ai generation inside block in pages (#732) 2023-04-10 12:33:12 +05:30
Vihar Kurama
0caadd0f7a Merge pull request #758 from nothingneko/patch-1
Fix: Dead Discord Link on Readme
2023-04-10 11:11:45 +05:30
pablohashescobar
62e736677a fix: cycle date check endpoint (#748) 2023-04-10 10:58:32 +05:30
pablohashescobar
bd9de0c213 feat: activity for issue attachments and links (#746) 2023-04-10 10:58:22 +05:30
pablohashescobar
c80968bb23 feat: bulk update estimate endpoint (#755) 2023-04-10 10:58:09 +05:30
Jaiden Riordan
441203867b Fix dead Discord Link 2023-04-09 18:32:08 -05:00
vamsi
eac4b21ead dev: migrations for estimate Estimate, IssueAttachment 2023-04-09 03:13:46 +05:30
Narayana Vadapalli
6fe35c9fe6 Create docker-compose-hub.yml 2023-04-09 00:21:40 +05:30
Aaryan Khandelwal
08e77cb19e fix: home page redirection logic (#752)
* fix: dashboard workspace activity mutation

* fix: home page redirection logic

* chore: add homePageRedirect function back
2023-04-08 14:32:33 -04:00
Anmol Singh Bhatia
03e74415f2 feat: upload button validation (#747) 2023-04-08 18:20:33 +05:30
Aaryan Khandelwal
c81bc4e5d2 style: loading screens (#750)
* fix: dashboard workspace activity mutation

* style: loading screens
2023-04-08 18:20:00 +05:30
Aaryan Khandelwal
1026ae3eb1 chore: user auth layer (#749)
* chore: use estimate points hook created

* chore: user auth layer

* fix: build error
2023-04-08 18:05:54 +05:30
Aaryan Khandelwal
3fe32606a9 chore: disable jira importer (#745)
* fix: dashboard workspace activity mutation

* chore: remove jira importer from settings
2023-04-08 15:46:19 +05:30
pablohashescobar
d88a95b1e9 fix: celery worker for issue activities (#744)
* dev: update celery configuration to root folder

* dev: update import for celery

* fix: worker to deserialize data
2023-04-08 15:46:05 +05:30
Aaryan Khandelwal
c21fb6e942 fix: issue attachments mutation (#743)
* fix: dashboard workspace activity mutation

* fix: attachment mutation for create and delete
2023-04-08 15:33:20 +05:30
Aaryan Khandelwal
98e6d3de22 fix: dashboard workspace activity mutation (#742) 2023-04-08 15:10:19 +05:30
Kunal Vishwakarma
9b1ae6bcd4 fix: inconsistency in styles (#734) 2023-04-08 13:55:30 +05:30
Aaryan Khandelwal
3947a86fa7 fix: new auth layer (#740)
* chore: made workspace authorization wrapper component

* chore: added todos

* chore: workspace pages new layout

* chore: project authorization wrapper

* chore: new project authorization wrapper

* fix: authorization for member roles

* chore: new auth screens ui

---------

Co-authored-by: Dakshesh Jain <dakshesh.jain14@gmail.com>
2023-04-08 13:46:46 +05:30
Aaryan Khandelwal
beedd57ee1 fix: fetch selected project members (#741)
* fix: fetch selected project members

* chore: remove old imports
2023-04-08 13:46:21 +05:30
Kunal Vishwakarma
0a3d13706e fix: mutation issue in cycles (#739)
* fix: mutation issue in cycles

* fix: removed comments
2023-04-08 01:24:24 +05:30
Anmol Singh Bhatia
c093209338 fix: shortcut combination key bug fix (#733)
* fix: shortcut combination key bug fix

* refactor: code refactor
2023-04-07 17:01:52 +05:30
Kunal Vishwakarma
a68d94c33f fix: added image popover for settings cover (#737)
* fix: added popover for profile cover

* fix:removed comments
2023-04-07 15:33:11 +05:30
Aaryan Khandelwal
35f9876981 refactor: import/export code (#735) 2023-04-07 13:27:57 +05:30
pablohashescobar
c0b732f1f1 chore: rename project name to project key (#731) 2023-04-06 22:58:13 +05:30
pablohashescobar
6be775434d fix: project issue search endpoint (#729) 2023-04-06 22:58:03 +05:30
pablohashescobar
687b05d221 dev: upgrade python version (#728) 2023-04-06 22:57:36 +05:30
pablohashescobar
59a33587a0 feat: delete endpoint for importers (#725)
* feat: delete endpoint for importers

* fix: delete endpoint for importers
2023-04-06 22:57:20 +05:30
pablohashescobar
e46487c130 chore: add project details on importer service endpoint (#714)
* chore: add project details on importer service endpoint

* dev: add select related for imports
2023-04-06 22:57:06 +05:30
pablohashescobar
5b72b1672f chore: add workspace and project details on label endpoints (#713) 2023-04-06 22:56:55 +05:30
pablohashescobar
ec818a5523 refactor: move all background task from rqworker to celery (#668)
* refactor: move all background task from rqworker to celery

* dev: update background job to take input in parameters rather than a single dict

* dev: update procfile for new worker

* dev: docker updates for new celery worker
2023-04-06 22:56:36 +05:30
pablohashescobar
100c431ac3 fix: default assignee for issues (#712)
* fix: default assignee for issues

* fix: check for empty array as well
2023-04-06 22:56:24 +05:30
Anmol Singh Bhatia
ea06ee4529 fix: issue attachment improvement (#730)
* fix: invalid file error state bug fix

* style: icons updated
2023-04-06 19:16:50 +05:30
Aaryan Khandelwal
35455c2bf7 chore: delete import (#727)
* chore: delete import

* chore: changed button text
2023-04-06 16:06:31 +05:30
Dakshesh Jain
c49f614352 feat: update project cover image (#726) 2023-04-06 15:11:01 +05:30
Kunal Vishwakarma
95fe4a3831 feat: added estimates (#721)
* feat: added estimates

* chore: added estimate to issue sidebar
2023-04-06 15:09:24 +05:30
Anmol Singh Bhatia
14dd498d08 feat: issue attachments feature (#717)
* chore: issue attachment services added

* feat: attachment icons added

* chore: fetch-key and icons export

* feat: issue attachment upload section added

* feat: issue attachment list section added

* feat: date helper function added

* style: responsiveness added

* feat: attachment info added

* style: attachment overflow fix

* style: cursor pointer added

* chore: issue attachment interface

* style: uploading state added

* feat: delete issue attachment modal

* style: style improvement and refactor

* style: consistent icon added , chore: refactor the code

* fix: js icon import fix

* fix: build fix

* chore: refactor code
2023-04-06 15:07:11 +05:30
pablohashescobar
86ec46db2c dev: add imports for back migration and add migration for views (#707) 2023-04-06 13:59:43 +05:30
pablohashescobar
6a579f85ad feat: bulk create endpoint for estimate points (#708)
* feat: bulk create endpoint for estimate points

* dev: remove integrity logic and update url
2023-04-06 13:59:17 +05:30
pablohashescobar
105428894f fix: add check if the users need to be imported (#716) 2023-04-06 13:58:56 +05:30
pablohashescobar
f2144c3e89 fix: issue search endpoint for parent issues (#705)
* fix: issue search endpoint for parent issues

* fix: parent search

* fix: search endpoint
2023-04-06 13:58:27 +05:30
Dakshesh Jain
cf662f6e6c chore: new analytic events (#699)
* feat: tracking events for issues marked as DONE, issue property update, issue moved to cycle, issue moved to modules

* fix: changed events names

* chore: sync analytic

* chore: new analytic events
2023-04-06 12:08:52 +05:30
Aaryan Khandelwal
65037b5031 style: disabled state for buttons (#724) 2023-04-06 01:03:42 +05:30
Aaryan Khandelwal
c9d8a8dbd1 feat: github importer (#722)
* chore: github importer first step completed

* refactor: github importer code refactored

* chore: github importer functionality completed

* fix: import data step saved data
2023-04-06 00:51:15 +05:30
pablohashescobar
6b8b981e1d docs: update readme to include default email and password for self hosting setup (#706) 2023-04-05 15:03:40 +05:30
pablohashescobar
1562939287 chore: add workspace details on comment serializer (#697) 2023-04-05 00:20:21 +05:30
pablohashescobar
cc07e2790d feat: issue estimations (#696)
* dev: initialize estimation

* dev: issue estimation field in issues and project settings

* dev: update issue estimation logic
2023-04-05 00:19:53 +05:30
pablohashescobar
97386e9d07 feat: issue attachments (#677) 2023-04-05 00:17:55 +05:30
pablohashescobar
ff5cddeb95 feat: issue search endpoint (#667)
* feat: issue search endpoints

* dev: update issue search for blocker and blocked by
2023-04-05 00:17:16 +05:30
Vamsi Kurama
3d6f2dd3dc Merge pull request #703 from makeplane/stage-release
promote: stage-release to production
2023-04-04 19:38:37 +05:30
vamsi
8cbf75ad6c Merge branch 'stage-release' of https://github.com/makeplane/plane into stage-release 2023-04-04 19:33:32 +05:30
vamsi
9f4f1cac42 Merge branch 'develop' of https://github.com/makeplane/plane into stage-release 2023-04-04 19:31:12 +05:30
Vamsi Kurama
1c752d7019 Merge pull request #691 from makeplane/develop
promote: develop to stage release
2023-04-04 19:29:55 +05:30
Aaryan Khandelwal
3519be9ce8 fix: remirror empty state (#702)
* fix: minor pages ui

* fix: remirror empty state
2023-04-04 19:27:13 +05:30
sphynxux
9ce158fc10 add screenshots, feature, docker compose steps on readme (#701) 2023-04-04 18:50:23 +05:30
Aaryan Khandelwal
0036ac6afb fix: minor pages ui (#700) 2023-04-04 18:31:28 +05:30
pablohashescobar
7f7ceec24c chore: return user role in user onboard endpoint (#682) 2023-04-04 18:07:17 +05:30
pablohashescobar
adf366b325 chore: gpt environment variables in the example file (#698) 2023-04-04 18:07:01 +05:30
Aaryan Khandelwal
2660d646ad chore: minor pages UI (#695)
* chore: fix minor ui bugs in pages

* chore: shortcut to add new block

* chore: keyboard accessibility

* chore: block options position
2023-04-04 16:21:46 +05:30
Aaryan Khandelwal
dad36b404d fix: pages ai modal (#694) 2023-04-04 14:07:17 +05:30
Aaryan Khandelwal
51be70d814 chore: remove github importer tab (#693) 2023-04-04 00:27:08 +05:30
Aaryan Khandelwal
4af5921991 chore: restrict users from creating workspace with reserved slugs (#692) 2023-04-04 00:13:21 +05:30
pablohashescobar
588247f1c1 dev: back migration for project member views (#663) 2023-04-04 00:00:03 +05:30
pablohashescobar
1bb93f1f50 dev: back migration to update label colors (#664) 2023-04-03 23:58:35 +05:30
pablohashescobar
d990f0038b fix: module link create url validation (#678) 2023-04-03 23:58:24 +05:30
Dakshesh Jain
67952bc225 feat: added user role on onboarding event (#684)
* feat: added tracker for views

* feat: added user role on onboarding event
2023-04-03 23:57:19 +05:30
Kunal Vishwakarma
a1f0f43992 feat: icon picker (#689)
* feat: icon picker

* style: icon picker modal

---------

Co-authored-by: Dakshesh Jain <dakshesh.jain14@gmail.com>
2023-04-03 23:54:26 +05:30
Aaryan Khandelwal
007ed0afa4 fix: cmdk hover style (#690) 2023-04-03 23:52:39 +05:30
Kunal Vishwakarma
62cca1c7cd feat: issue redirect (#685)
* feat: open issue in new tab for list and kanban view

* fix: used a tag
2023-04-03 23:51:46 +05:30
Aaryan Khandelwal
5ba7d271b7 style: revamp pages (#688)
* feat: dnd added for blocks

* chore: added access option to pages

* style: ui fixes

* fix: polishing

* fix: build error
2023-04-03 23:30:29 +05:30
Saheb Giri
f6f9caf9e6 fix: now user can navigate using arrow keys (#681) 2023-04-03 19:04:11 +05:30
Aaryan Khandelwal
35e40a7bec chore: added placeholder to remirror (#686)
* chore: added placeholder to remirror

* fix: build error
2023-04-03 18:14:50 +05:30
Aaryan Khandelwal
3e08186d72 fix: kanban empty issues (#687) 2023-04-03 18:04:45 +05:30
Dakshesh Jain
150553d420 fix: tracker not creating user alias (#683) 2023-04-03 16:37:19 +05:30
Aaryan Khandelwal
1b30e4b57f fix: user cannot create duplicate links (#680) 2023-04-03 16:22:37 +05:30
Anmol Singh Bhatia
a63c551e75 feat: completed cycle transfer issue validation added (#676)
* feat: completed cycle transfer issue validation added

* style: transfer issue section

* style: issue transfer button
2023-04-03 15:57:52 +05:30
Dakshesh Jain
cfe7c5e0b7 fix: search button not working on image picker popover (#679) 2023-04-03 15:57:08 +05:30
Aaryan Khandelwal
12ad3892f8 fix: signin page type (#671) 2023-04-03 15:07:39 +05:30
Dakshesh Jain
353197f583 feat: added tracker for views (#675) 2023-04-03 15:04:48 +05:30
Kunal Vishwakarma
0cf498651c feat: shortcuts (#674)
* feat: added shortcut for page and view

* fix: shortcut for view

* fix: onclick method for views and pages
2023-04-03 14:23:50 +05:30
Saheb Giri
a18af1cecf fix: missing deleted icon in user activity (#673) 2023-04-03 11:51:25 +05:30
Aaryan Khandelwal
61875722e4 chore: add auto generate description option to create issue modals (#672) 2023-04-03 11:41:46 +05:30
Vamsi Kurama
7fed2ec6ef Merge pull request #670 from makeplane/stage-release
promote: stage-release to production
2023-04-01 20:29:39 +05:30
Vamsi Kurama
93ba04aebc Merge pull request #669 from makeplane/develop
promote: develop to stage-release
2023-04-01 20:19:02 +05:30
Alejandro Pinar Ruiz
bd3ea456c3 fix: add tags for frontend build action (#445) 2023-04-01 18:30:26 +05:30
Saheb Giri
c0bf7783b1 style: designed user activity. (#666) 2023-03-31 23:00:28 +05:30
Anmol Singh Bhatia
9f34f41982 feat: list and kanban view group by header icon (#665) 2023-03-31 21:20:23 +05:30
Kunal Vishwakarma
c940641ba1 Fix: view list bugs (#654)
* fix: viewlist link

* fix/removed side effects

* fix: deadzones in the link
2023-03-31 19:27:07 +05:30
Kunal Vishwakarma
567966459b style: added icons to ellipses in project settings label (#662) 2023-03-31 18:31:44 +05:30
Anmol Singh Bhatia
6055f5c4ee fix: cycle list page mutation fix (#661)
* fix: cycle list page mutation fix

* fix: cycle mutation fix
2023-03-31 18:31:21 +05:30
Saheb Giri
abe34ad7b1 fix: add scroll into view when editing label in settings page (#660) 2023-03-31 18:31:01 +05:30
Anmol Singh Bhatia
d596e41d4d fix: project setting control fix (#658)
* fix: project setting control fix

* fix: project member endpoint fix
2023-03-31 18:30:39 +05:30
Aaryan Khandelwal
fae1534887 fix: issues list flicker (#659)
* fix: issues list flicker

* fix: useeffect dependencies
2023-03-31 18:29:24 +05:30
Saheb Giri
448d8c63f3 fix: old labels must have black color in project settings (#657) 2023-03-31 18:03:42 +05:30
Kunal Vishwakarma
844ae4869a fix: view list link (#653)
* fix: viewlist link

* fix/removed side effects

* fix: deadzones in the link
2023-03-31 17:54:05 +05:30
Anmol Singh Bhatia
afd7741d0c fix: cycle status bug fix (#656) 2023-03-31 17:52:20 +05:30
Saheb Giri
f074f9f003 fix: graphs issue (#655)
* fix: prevent y axis to have decimal

* fix: add padding and labels to line chart
2023-03-31 17:33:51 +05:30
Anmol Singh Bhatia
f6500914be style: transfer issue modal empty state added (#652) 2023-03-31 16:05:02 +05:30
Saheb Giri
a6f306209d fix: issue modal title textfield reset (#651) 2023-03-31 16:04:51 +05:30
Anmol Singh Bhatia
e5507651c3 fix: issue sidebar module , cycle and label dropdown fix (#650) 2023-03-31 16:04:36 +05:30
Aaryan Khandelwal
e3005b7776 fix: project identifier check in project settings (#649) 2023-03-31 16:04:17 +05:30
Aaryan Khandelwal
480e2c4d7f refactor: cycles toggle favorite (#648) 2023-03-31 16:03:58 +05:30
Aaryan Khandelwal
09e17858fe chore: remove edit and push issue from page block (#647) 2023-03-31 16:03:48 +05:30
Saheb Giri
13b2a6fd53 fix: persist data on tab switch in workspace (#646)
* fix: persist data on tab switch in workspace

* fix: build fail
2023-03-31 16:03:35 +05:30
Kunal Vishwakarma
4ab82b9616 fix: style and bugs (#644)
* fix: style and bugs

* fix: removed unnecessary classes
2023-03-31 16:03:25 +05:30
Saheb Giri
09d73c5e04 fix: issue activity (#645)
- fix: set and remove activity logs are showing problems
- fix: removing due date is showing static value of 1 Jan.
- fix:  old labels to have black color.
- fix:  word 'Description' should be bold
2023-03-31 14:46:17 +05:30
Vamsi Kurama
ed60707bae Merge pull request #643 from makeplane/develop
promote: develop to stage release
2023-03-31 04:41:24 +05:30
Aaryan Khandelwal
b2c15125fc fix: image upload (#642) 2023-03-31 04:24:57 +05:30
Aaryan Khandelwal
a8f125cfa8 fix: blocked and blocking in issue details sidebar (#641) 2023-03-31 03:50:35 +05:30
pablohashescobar
15ce3537ad fix: recent pages endpoint (#640)
* fix: recent pages endpoint for date

* fix: order by
2023-03-31 03:32:32 +05:30
Aaryan Khandelwal
448f383ec9 chore: cycle sidebar content updated (#639) 2023-03-31 03:21:37 +05:30
Aaryan Khandelwal
0c39f0c563 style: custom error page (#638) 2023-03-31 03:09:55 +05:30
Aaryan Khandelwal
65ddcb6d79 chore: pages content update, empty state for recent pages (#637) 2023-03-31 02:51:39 +05:30
Aaryan Khandelwal
0c94b494ed refactor: calendar view (#636) 2023-03-31 02:43:38 +05:30
Aaryan Khandelwal
e2921539d0 refactor: sidebar stats mutation (#635) 2023-03-31 02:20:44 +05:30
Aaryan Khandelwal
66d07e340b fix: delete mutations for issues, cycles and modules (#634) 2023-03-31 02:17:35 +05:30
vamsi
29ea592c4a dev: upgrade redis requirements to 4.5.4 2023-03-31 02:08:29 +05:30
vamsi
05323d4697 dev: new migrations for Pages related attributes 2023-03-31 02:04:33 +05:30
Anmol Singh Bhatia
8fcfebf0fc fix: invalid date toast message updated (#633) 2023-03-31 01:40:06 +05:30
Anmol Singh Bhatia
5d0533a44f style: ellipsis consistent style (#632)
* style: ellipsis consistent style

* style: consistent ellipsis menu for module and cycle
2023-03-31 00:31:00 +05:30
Anmol Singh Bhatia
3cf2172520 style: delete workspace modal (#631) 2023-03-31 00:25:42 +05:30
Saheb Giri
a8a5873d88 fix: add icons to dropdown and replace link icon (#630) 2023-03-30 20:45:15 +05:30
Kunal Vishwakarma
73c7b1bddc fix: modal typo (#629)
* fix: modal width inconsistency

* fix: modal typo
2023-03-30 20:25:04 +05:30
Anmol Singh Bhatia
4441651f81 style: empty state image updated (#628) 2023-03-30 19:34:50 +05:30
Saheb Giri
64c936b9b5 style: module modal consistent design (#625) 2023-03-30 19:28:04 +05:30
Dakshesh Jain
66ed6a1dc8 feat: added tracker for page, page block, and gpt (#623)
* refactor: made events function generic

* feat: added tracker for page, page block, and gpt
2023-03-30 19:27:46 +05:30
Anmol Singh Bhatia
50275fd2ad fix: sidebar pending issue stats fix (#627) 2023-03-30 19:26:41 +05:30
Kunal Vishwakarma
112fe8e7e6 fix: modal width inconsistency (#626) 2023-03-30 19:02:05 +05:30
Anmol Singh Bhatia
02e6439bd5 feat: completed cycle transfer issue (#624)
* feat: bulk transfer issue for completed cycle added

* feat: toast alert added for issue transfer
2023-03-30 18:59:53 +05:30
pablohashescobar
f9ee898d88 chore: add workspace details and project details in page responses (#615)
* chore: add workspace details and project details in page responses

* fix: typo in workspace queryset
2023-03-30 18:59:39 +05:30
pablohashescobar
f79fdbf782 chore: create activity when a block is converter into an issue (#609) 2023-03-30 18:58:51 +05:30
pablohashescobar
1d7b65ad83 fix: transfer issues endpoint (#620) 2023-03-30 18:58:23 +05:30
Saheb Giri
1558f51c23 fix: show divider only when filter is selected (#618) 2023-03-30 18:54:44 +05:30
Aaryan Khandelwal
bc7dc43171 chore: ai assistant limit error (#619) 2023-03-30 18:45:33 +05:30
Kunal Vishwakarma
70a00a6309 style: issue modal scroll (#621) 2023-03-30 18:45:11 +05:30
Saheb Giri
4d56adba43 style: create cycle modal makeover (#617) 2023-03-30 18:35:29 +05:30
Anmol Singh Bhatia
624d9dfd39 fix: icon and ellipsis (#622)
* fix: consistent icon for end date for cycle card

* fix: sidebar ellipsis fix
2023-03-30 18:35:05 +05:30
Aaryan Khandelwal
3e8c375d1c fix: old labels color set to black (#614) 2023-03-30 18:07:18 +05:30
Aaryan Khandelwal
880813685b fix: sidebar dropdowns height (#616)
* fix: old labels color set to black

* fix: issue details sidebar select dropdowns height
2023-03-30 18:07:00 +05:30
Aaryan Khandelwal
16abbe0b3e fix: project identifier check in project settings (#613) 2023-03-30 17:48:03 +05:30
Aaryan Khandelwal
b65fa89cdb fix: role input on my profile page (#612) 2023-03-30 17:47:49 +05:30
Aaryan Khandelwal
ed4aae47a2 style: my profile page (#608) 2023-03-30 17:04:41 +05:30
Aaryan Khandelwal
5feaed3961 fix: fetch correct list of issues on the calendar view (#611) 2023-03-30 17:03:37 +05:30
Saheb Giri
be5c4140ff refactor: issue label and make design consistent (#610) 2023-03-30 16:59:07 +05:30
pablohashescobar
9c4fcca6c1 fix: ordering in queryset (#598) 2023-03-30 16:33:16 +05:30
pablohashescobar
5aad20e7ed fix: project update for identifier (#604) 2023-03-30 16:33:04 +05:30
pablohashescobar
3a599b6436 chore: workspace detail on issue activity serializer (#607) 2023-03-30 16:32:48 +05:30
Kunal Vishwakarma
c5ccc29418 feat: added invitaion pending pills (#606) 2023-03-30 16:01:24 +05:30
Anmol Singh Bhatia
f5f90dab69 fix : module and cycle invalid date fix (#605)
* fix: module and cycle modal invalid date validation

* fix: cycle and module sidebar invalid date
2023-03-30 16:00:48 +05:30
Aaryan Khandelwal
a94e38c093 fix: minor bugs in the onboarding screens (#603) 2023-03-30 13:55:50 +05:30
Saheb Giri
63b7c1ee47 style: icons consistency and minor fixes (#601)
* fix: change discord casing

* style: icon and style consistency in cmd k

- change discord icon color
- make link copy link consistent
-  bolt to rocket icon for shortcut

* style: make icon color throughout the activity log
2023-03-30 13:54:18 +05:30
Kunal Vishwakarma
1866fd77bb fix: changed buttons to primary (#602) 2023-03-30 13:53:03 +05:30
Kunal Vishwakarma
531b9e3d64 style: fixed height issue in module card (#599) 2023-03-30 12:09:42 +05:30
Anmol Singh Bhatia
06fb3e9b58 fix: calendar view bugs (#600)
* fix: text turncate added for issue

* fix: next week btn fix, style:calendar cell height fix
2023-03-30 12:09:11 +05:30
Aaryan Khandelwal
fb01e6d22c fix: module status line break (#597) 2023-03-30 02:07:48 +05:30
pablohashescobar
89bb439d62 chore: return user request count from logger (#596) 2023-03-30 02:04:41 +05:30
Anmol Singh Bhatia
e6055da150 feat: calendar view (#561)
* feat:start and last day of month helper function

* feat: start and last day of week helper function

* feat: weekday and everyday interval helper function

* feat: calendar date formater helper function

* feat: monthly calendar view , feat: weekend date toggle, feat: calendar month and year picker

* feat: monthly , weekly view and weekend toggle

* feat: drag and drop added in calendar view

* fix: drag and drop mutation fix

* chore: refactoring , feat: calendar view option added

* fix: calendar view menu fix

* style: calendar view style improvement

* style: drag and drop styling

* fix:week day format fix

* chore: calendar constant added

* feat: calendar helper function added

* feat: month and year picker, month navigator, jump to today funtionality added

* feat: weekly navigation and jump to today fix, style: month year picker fix

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-03-30 02:01:53 +05:30
Aaryan Khandelwal
952c64d449 fix: mutation error for project issues (#595) 2023-03-30 01:50:00 +05:30
Aaryan Khandelwal
dcf8b562d3 chore: cycle and module sidebar stats filter (#594) 2023-03-30 01:31:43 +05:30
pablohashescobar
6a40dd911f fix: cycles date check for null and incomplete cycles endpoint (#580)
Co-authored-by: Vamsi Kurama <vamsi.kurama@gmail.com>
2023-03-30 01:26:14 +05:30
pablohashescobar
9064709d5d feat: user activities endpoint (#590) 2023-03-30 01:25:55 +05:30
pablohashescobar
6d8eda9814 chore: update API endpoints for analytics (#574)
* chore: return workspace details on project create and update

* chore: update endpoints to return workspace and project details

---------

Co-authored-by: Vamsi Kurama <vamsi.kurama@gmail.com>
2023-03-30 01:25:32 +05:30
pablohashescobar
7eaec16381 chore: add cycle id and module id in issues list endpoint (#586) 2023-03-30 01:25:16 +05:30
pablohashescobar
d7ed237f78 feat: add API limit for AI assistance (#592) 2023-03-30 01:23:56 +05:30
kunalv17
5c1607f39b style: finished module card design (#593)
* style: finished modulecard design

* fix: use assignee list component
2023-03-30 01:17:51 +05:30
Saheb Giri
c75ca8203f feat: add label to create view modal (#591) 2023-03-30 01:08:14 +05:30
Anmol Singh Bhatia
cfd97041b8 feat: incomplete cycle endpoint added , issue sidebar cycle fix (#582)
* feat: incomplete cycle endpoint added , issue sidebar cycle fix

* fix: fetch key
2023-03-29 19:21:15 +05:30
Saheb Giri
7337707a4e style: redesign issue activity (#579)
* style: redesign the activity feed and refactor the code

* chore: remove console logs

* revert: back to remirror rich text editor

* style: make icons, text smaller and reduce the spacing between logs
2023-03-29 19:19:37 +05:30
Dakshesh Jain
b441a2ce20 feat: added labels in filters (#585)
* feat: added labels in filters

* fix: added labels in fetch keys
2023-03-29 19:18:57 +05:30
Aaryan Khandelwal
1509c8611d fix: mutation while adding issue to cycle or module (#589) 2023-03-29 19:13:53 +05:30
kunalv17
4e9715a5b2 style: added divider to the pages block (#571)
* style: added hr to the pages block

* style: added divider and removed hr

* chore: removed index prop

* chore: removed index
2023-03-29 18:36:52 +05:30
Dakshesh Jain
10657d4796 fix: filter menu not closing on select other parent option (#587) 2023-03-29 18:18:45 +05:30
Saheb Giri
653cc29290 style: issue filter design (#588)
* style: redesign issue filter pill

* style: redesign issue label on the view modal
2023-03-29 18:18:08 +05:30
Dakshesh Jain
fa9c6581fd fix: using proper name for tracker key (#581)
* fix: transmitting selective data for analytics

* fix: using proper name for tracker key

* fix: using proper name for tracker key
2023-03-29 16:34:56 +05:30
Aaryan Khandelwal
96910e1897 chore: ai for issue description (#575)
* feat: block sync

* chore: ai assistant for issue description
2023-03-29 16:30:40 +05:30
sphynxux
2f69761130 Merge pull request #583 from makeplane/chore/analytics_payload
chore: analytics payload
2023-03-29 16:29:17 +05:30
sphynxux
a8f5a3eda1 Merge pull request #584 from makeplane/fix/parent_issue_modal
fix: design of select parent issue modal
2023-03-29 16:28:55 +05:30
Anmol Singh Bhatia
248d094762 feat: cycle list page (#577)
* style: cycle list page

* fix:typo fix
2023-03-29 16:27:55 +05:30
pablohashescobar
1255f4756d fix: uuid serilaizable error 2023-03-29 16:25:06 +05:30
Aaryan Khandelwal
22f8eb9a68 fix: design of select parent issue modal 2023-03-29 16:24:04 +05:30
pablohashescobar
3ba9cddc2a chore: add user id when logging for analytics 2023-03-29 16:15:11 +05:30
kunalv17
e3cb0ed13e feat/added toggle for pages in settings features (#576)
* feat/added toggle for pages in settings features

* style:changed pages icon
2023-03-29 15:21:08 +05:30
pablohashescobar
2786f09e85 Merge branch 'develop' of github.com:makeplane/plane into develop 2023-03-29 14:52:38 +05:30
Dakshesh Jain
06daf68753 fix: transmitting selective data for analytics (#578) 2023-03-29 14:38:30 +05:30
Anmol Singh Bhatia
2138ddf1f5 fix: profile page header fix (#572) 2023-03-29 13:17:31 +05:30
pablohashescobar
f9fa345b25 Merge branch 'develop' of github.com:makeplane/plane into develop 2023-03-29 12:54:33 +05:30
Dakshesh Jain
c3e1d33518 feat: jitsu tracker setup (#542)
* feat: jitsu tracker setup

also using it in create, update and delete project & workspace

* refactor: added some more check condition on track-event api

* fix: added env vars in turbo.json

* feat: added user onboard event, workspace invite and workspace invite accept events

* feat: add tracker for issues, state, modules and cycles

* fix: add @jitsu/nextjs in package.json
2023-03-29 12:24:19 +05:30
kunalv17
9eb9b7bf6c style: dashboard color (#568) 2023-03-29 11:54:37 +05:30
Saheb Giri
c60b152a7c fix: add crisp chat with us option in cmdk (#570) 2023-03-29 11:53:09 +05:30
Anmol Singh Bhatia
e07ffc3a46 fix: module sidebar link section relocation (#569) 2023-03-29 11:52:39 +05:30
Saheb Giri
dd3bca9a32 fix: cmdk integration (#567)
* fix: issues not showing on cmd k

* fix: text overflows on longer issue title

* fix: add loading state whenever there is a network call

* fix: minor ux changes

* feat: replace loading with spinner
2023-03-29 00:51:47 +05:30
pablohashescobar
628591854d fix: search endpoint to return distint results (#566)
Co-authored-by: Vamsi Kurama <vamsi.kurama@gmail.com>
2023-03-29 00:23:35 +05:30
pablohashescobar
05e9c0f76f fix: cycle validation for completed cycles (#559) 2023-03-29 00:23:16 +05:30
pablohashescobar
3bebcc4714 chore: return gpt response in html (#555)
* chore: return gpt response in html

* chore: update the response br
2023-03-29 00:23:02 +05:30
pablohashescobar
d16d32cea8 feat: move issues from one cycle to another (#554)
* feat: move issues from one cycle to another

* fix: push method when updating

* fix: new cycle completed validation
2023-03-29 00:22:48 +05:30
Aaryan Khandelwal
b654d30aeb chore: minor fixes on pages (#557)
* feat: block sync

* chore: minor fixes on pages

* fix: remove dangerously set inner html

* fix: pages crud operations mutation

* fix: favorites mutation for recent pages

* fix: remove dangerously set inner html
2023-03-29 00:20:00 +05:30
Saheb Giri
c0a471e916 fix: don't allow decimal in the y axis of completed issues graph (#564) 2023-03-29 00:08:34 +05:30
Anmol Singh Bhatia
e2eeec8f79 feat: completed cycle message added (#565) 2023-03-28 18:48:57 +05:30
kunalv17
ccd03a4a45 refactor: constants fetchkeys strings to upper case (#563) 2023-03-28 18:28:26 +05:30
pablohashescobar
20bbe74b57 Merge branch 'develop' of github.com:makeplane/plane into develop 2023-03-28 17:47:45 +05:30
kunalv17
b7b8d3914a style: views list page, chore: views favotire (#562) 2023-03-28 16:48:46 +05:30
Saheb Giri
afb92ea850 feat: add global search through cmd k (#560)
* feat: cmdk integration

* feat: create view, cycle, project, module and workspace from command k

* feat: user can logout directly from command menu

* feat: user can visit sub page like various settings

* feat: change state of issue from command menu

* chore: add current issue state and minor UX improvements

* refactor: moved change issue state to new file

* feat: change issue priority from command k

* feat: delete issue from command k

* feat: copy issue url to clipboard

* fix: change placeholder when settings page is selected

* chore: remove logout option from cmd k

* feat: add help options to cmd k

* feat: assign issue to member from cmd k

* feat: now assign issue to yourself from cmd k

* chore: implement new cmd k design with icons

* feat: implemented global search feature in the cmd k

* feat: add keyboard acessibility to cmd k list items

* chore: remove console logs

* fix: pages icon in cmd list

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-03-28 14:49:27 +05:30
kunalv17
fc4d06fe0c style: changed the workspace cards height (#558) 2023-03-28 14:17:24 +05:30
pablohashescobar
dd90f26d93 Merge branch 'master' of github.com:makeplane/plane into develop 2023-03-28 13:58:38 +05:30
Aaryan Khandelwal
fbbf97f3a6 chore: remove docs (#553)
* feat: block sync

* chore: remove docs from repo
2023-03-28 03:54:48 +05:30
dependabot[bot]
d9f31a1eb7 chore(deps): bump redis from 4.4.2 to 4.5.3 in /apiserver/requirements (#556)
Bumps [redis](https://github.com/redis/redis-py) from 4.4.2 to 4.5.3.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/v4.4.2...v4.5.3)

---
updated-dependencies:
- dependency-name: redis
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-28 03:41:58 +05:30
pablohashescobar
a06d59f77d feat: sync flag for syncing issues with page blocks (#547) 2023-03-28 01:52:46 +05:30
pablohashescobar
722a053461 fix: date for earlier this week (#540) 2023-03-28 01:52:34 +05:30
pablohashescobar
d6818e74fd feat: page view toggle in project settings (#536) 2023-03-28 01:52:21 +05:30
Aaryan Khandelwal
37aade5ef6 fix: order by last created (#550)
* feat: block sync

* fix: order by last created order
2023-03-28 01:52:13 +05:30
Aaryan Khandelwal
b9e42d116e fix: issue modal overflow (#549)
* feat: block sync

* fix: create issue modal overflow
2023-03-28 01:52:04 +05:30
Aaryan Khandelwal
e0928d6ec5 fix: default label color (#551)
* feat: block sync

* fix: default label color
2023-03-28 01:50:55 +05:30
Aaryan Khandelwal
909ccd578b chore: crisp integration (#552)
* feat: block sync

* chore: crisp integration

* fix: chat with us icon
2023-03-28 01:50:36 +05:30
Aaryan Khandelwal
08ee5dc6b1 feat: block sync (#548) 2023-03-28 00:36:20 +05:30
pablohashescobar
a5a96d9f66 fix: add slack sdk in requirements file (#546) 2023-03-28 00:33:14 +05:30
pablohashescobar
691ea0c080 feat: slack bot setup (#545) 2023-03-27 23:37:00 +05:30
pablohashescobar
8bd557a743 feat: gzip compressor for performance upgrades (#538) 2023-03-27 23:36:13 +05:30
pablohashescobar
35b80b422d fix: gpt task and prompt (#537) 2023-03-27 23:36:00 +05:30
pablohashescobar
d6ffc3176e fix: global search endpoint to show entities within projects and add filtering through identifiers (#543) 2023-03-27 23:34:04 +05:30
Aaryan Khandelwal
3503b22dd9 refactor: pages folder structure (#544)
* refactor: pages folder structure, mutation issues

* fix: block edit and push

* fix: block title placeholder
2023-03-27 23:19:05 +05:30
Aaryan Khandelwal
e13b679c28 fix: join project screen flicker (#541) 2023-03-27 16:53:31 +05:30
Aaryan Khandelwal
21dd2e703b fix: module progress bar (#535) 2023-03-26 11:37:06 +05:30
Aaryan Khandelwal
5dd5fe2d09 feat: gpt integration for page block description (#539) 2023-03-26 11:36:10 +05:30
pablohashescobar
52d4828e1d fix: issue filters for start date and target date (#530) 2023-03-25 23:57:31 +05:30
pablohashescobar
c5baa6183c fix: pages endpoint for dates and access (#531)
* fix: pages endpoint for dates and access

* fix: recent pages endpoint

* fix: recent pages endpoint

* fix: date object in recent pages endpoint

* dev: update nomenclature
2023-03-25 23:57:16 +05:30
pablohashescobar
69387ffd8c fix: page labels update (#532) 2023-03-25 23:57:06 +05:30
pablohashescobar
32ab7951f7 perf: update issue serializer (#534) 2023-03-25 23:56:53 +05:30
Aaryan Khandelwal
5d67029b5a feat: pages (#533)
* style: page details

* style: page blocks design

* chore: pages list end points

* feat: add blocks, push blocks to issues

* feat: page labels, color options

* feat: added labels to pages

* fix: update page mutation
2023-03-25 23:39:46 +05:30
pablohashescobar
578d724e41 feat: global search endpoint for workspace (#529) 2023-03-25 11:16:33 +05:30
pablohashescobar
a3a792741f feat: GPT integration (#526)
* feat: GPT integration

* dev: move engine value to env variable
2023-03-25 11:14:26 +05:30
pablohashescobar
31624f3ae6 fix: start date and target date issue filter (#525) 2023-03-25 11:14:16 +05:30
pablohashescobar
5152deb2d0 fix: model ordering (#521)
* fix: model ordering

* fix: my pages and create by others pages
2023-03-25 11:14:05 +05:30
pablohashescobar
c6ba93da72 fix: dashboard issues filters (#519)
* fix: upcoming issues filters

* dev: update dashboard endpoint to return correct month
2023-03-25 11:13:14 +05:30
pablohashescobar
28b3c999ae dev: update recent pages endpoint and return blocks on page listing (#517)
* dev: update recent pages endpoint and return blocks on page listing

* fix: yesterday's pages
2023-03-25 11:12:54 +05:30
Dakshesh Jain
82b9275609 fix: deselecting filter option when clicked again (#528)
* fix: filters dropdown overflowing issue

* filters dropdown z-index

* fix: deselecting filter option when clicked again

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-03-24 23:33:28 +05:30
Dakshesh Jain
f2054b6945 style: removed color text from label modal (#527)
also closing color picker on color select
2023-03-24 23:32:33 +05:30
Dakshesh Jain
f3583f6415 feat: added filter 'created_by' (#524)
* feat: clear filter button

* feat: added filter 'created_by'

* style: text align left for all the issues in filters dropdown
2023-03-24 23:31:56 +05:30
Aaryan Khandelwal
02f423bcb6 fix: workspace dashboard (#522)
* chore: completed issues graph

* style: issue stats
2023-03-24 11:06:52 +05:30
Aaryan Khandelwal
3d34741356 chore: update view button (#523) 2023-03-24 10:56:06 +05:30
sphynxux
7731ee5de4 Merge pull request #520 from makeplane/feat/custom_error_page
fix: removed unnecessary variable
2023-03-24 01:15:19 +05:30
Aaryan Khandelwal
0ba2c5456a fix: removed unnecessary variable 2023-03-24 01:14:17 +05:30
sphynxux
a0ce3f0be6 Merge pull request #518 from makeplane/feat/custom_error_page
feat: custom error page
2023-03-24 01:12:29 +05:30
Aaryan Khandelwal
472767ab67 feat: group by created by option (#516) 2023-03-24 01:11:42 +05:30
Aaryan Khandelwal
ad60b8774e feat: custom error page 2023-03-24 01:11:33 +05:30
pablohashescobar
6c6f9a5bfd fix: dashboard endpoint for overdue and upcoming issues (#502)
* fix: dashboard endpoint for overdue and upcoming issues

* dev: update for upcoming issue to get target date null issues as well

* dev: update the filter
2023-03-24 00:13:48 +05:30
pablohashescobar
3056727190 dev: endpoints for my, other, recent and favorite pages, add sort order and color for pages (#499)
* dev: endpoints for my, other, recent and favorite pages, add sort order and color for pages

* dev: fix state attribute error while saving page blocks
2023-03-24 00:13:26 +05:30
pablohashescobar
053ae2063e fix: issue filtering keyerror (#494) 2023-03-24 00:13:05 +05:30
pablohashescobar
2501c819d3 fix: keyerror on comment create and update (#492) 2023-03-24 00:12:56 +05:30
Aaryan Khandelwal
765cfdbf7e fix: kanban loading state (#514) 2023-03-23 23:36:52 +05:30
guru_sainath
2f2caaaf6e Feat: Github importer to sync issues, users, and labels with workspace projects. (#509)
* Dev: Github integration with issues and layout integration

* dev: Github Integration route and UI configuration
2023-03-23 23:27:11 +05:30
Aaryan Khandelwal
7892a563b7 fix: minor ui fixes (#515)
* fix: sidebar arror positioning

* chore: show empty groups default value as true
2023-03-23 23:25:30 +05:30
Aaryan Khandelwal
f3b7fc6eb5 fix: filters dropdown overflowing issue (#513)
* fix: filters dropdown overflowing issue

* filters dropdown z-index
2023-03-23 23:25:08 +05:30
Aaryan Khandelwal
f01f2fb9bd style: my profiles page responsiveness (#512) 2023-03-23 22:55:58 +05:30
Aaryan Khandelwal
19434342d3 fix: delete image preview after modal close (#511) 2023-03-23 22:55:12 +05:30
Aaryan Khandelwal
6962d7718f chore: updated my issues text (#507) 2023-03-23 22:54:53 +05:30
Anmol Singh Bhatia
b6a3615f66 feat: completed cycle validation , fix: quick action and kanban fix (#505)
* feat: completed cycle card validation

* fix: unique key to hidden group

* feat: completed cycle sidebar validation

* fix: remove console log from progress chart hover

* feat: kanban and list view completed cycle validation

* feat: quick action validation

* refactor: code refactor

* fix: sidebar draft cycle status
2023-03-23 22:42:08 +05:30
Anmol Singh Bhatia
5191fc5f7c style: create workspace bg fix (#510) 2023-03-23 22:41:30 +05:30
Aaryan Khandelwal
567afa6d39 fix: kanban drag and drop (#508) 2023-03-23 18:52:18 +05:30
Dakshesh Jain
feb0e40559 refactor: state with group 'completed' or 'cancelled' are collapsed by default (#506) 2023-03-23 18:10:28 +05:30
Saheb Giri
4a81b988b4 feat: implemented new pages design with bare minimum functionality (#503)
* chore: add page types and page api service

* chore: add create, list, update and delete on pages

* chore: add create, delete and patch page blocks

* feat: add and remove pages to favorite

* fix: made neccessary changes

- used tailwind for hover events
- add error toast alert
- used partial for patch request

* fix: replace absolute positiong with a flex box

* fix: design list page view to match with ui

* feat: add top large textarea for page title and description

* refactor: add page label with types

* feat: add pages grid layout

* feat: add tabs and masonry layout

* fix: build errors

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-03-23 16:12:14 +05:30
Aaryan Khandelwal
c755907d99 chore: new workspace endpoint (#504)
* chore: new workspace dashboard endpoint

* chore: overdue and upcoming issues
2023-03-23 15:54:59 +05:30
Aaryan Khandelwal
ad2fa91a2b chore: new global select filters component (#501) 2023-03-23 12:01:50 +05:30
Saheb Giri
10e5ba7b3e feat: add pages and page blocks (#495)
* chore: add page types and page api service

* chore: add create, list, update and delete on pages

* chore: add create, delete and patch page blocks

* feat: add and remove pages to favorite

* fix: made neccessary changes

- used tailwind for hover events
- add error toast alert
- used partial for patch request

* fix: replace absolute positiong with a flex box
2023-03-23 11:01:06 +05:30
Aaryan Khandelwal
d477c19ad9 feat: show empty states toggle button in the views dropdown (#500)
* feat: show empty states toggle button in views dropdown

* refactor: empty state toggle naming convention, feat: hidden groups in section in the kanban board
2023-03-23 02:13:52 +05:30
Aaryan Khandelwal
79249c5c9b fix: states order (#498)
* fix: order of states in the kanban board

* fix: state name in list view
2023-03-23 01:00:50 +05:30
pablohashescobar
4e3c9397ea feat: page labels and favorites (#487)
* dev: initiate page labels

* dev: page labels

* dev: my pages endpoint
2023-03-22 23:41:30 +05:30
Aaryan Khandelwal
cd26b2e096 Revert "fix: sidebar and shortcut modal (#493)" (#497)
This reverts commit f615f8ac0c.
2023-03-22 23:40:25 +05:30
pablohashescobar
27b1308227 fix: file asset uploading and deleting (#496) 2023-03-22 23:38:47 +05:30
Anmol Singh Bhatia
f615f8ac0c fix: sidebar and shortcut modal (#493)
* fix: shortcut modal cmd and ctrl fix

* fix: sidebar collapse state ordering
2023-03-22 19:08:04 +05:30
Dakshesh Jain
031f6443a0 style: kanban loader (#491) 2023-03-22 19:06:36 +05:30
Dakshesh Jain
e48d98cea6 feat: showing progress while page is being loaded (#485) 2023-03-22 19:05:36 +05:30
Dakshesh Jain
a830808f9d refactor: views & filter (#490)
* fix: not saving filters on views detail page

* refactor: using issues endpoint to get issues in views detail page

feat: showing toast alert on saving view
2023-03-22 18:18:19 +05:30
Aaryan Khandelwal
9a97c97336 chore: new modules and cycles response (#489) 2023-03-22 18:10:38 +05:30
Aaryan Khandelwal
2e346158ba fix: minor ui fixes (#488) 2023-03-22 16:58:32 +05:30
Aaryan Khandelwal
283950c8e2 style: views (#486) 2023-03-22 14:47:13 +05:30
vamsi
818d1147d5 dev: new migrations for added fields and introducing Pages 2023-03-22 01:39:53 +05:30
pablohashescobar
c4594bff01 feat: cycles and modules issues state group percentages (#484)
* dev: state group issue percentage on cycle list

* dev: add issue percentage fields for modules and query updates on cycle apis
2023-03-22 01:36:52 +05:30
pablohashescobar
5e81600e38 feat: jira issue importer (#476)
* dev: initialize jira importer

* dev: create service import for jira

* dev: update task to create all users for project and workspace and also create assignees when importing bulk assignees

* dev: create bulk modules import endpoint for jira epics

* dev: create bulk module issues when importing modules
2023-03-22 01:36:38 +05:30
pablohashescobar
846e73e3b8 feat: add issue filters for cycles and modules (#475) 2023-03-22 01:36:06 +05:30
pablohashescobar
4dc76eac19 fix: project url max length (#471) 2023-03-22 01:35:53 +05:30
pablohashescobar
f7dbc5e9c0 feat: page and page-blocks (#468)
* dev: initiate paper models

* feat: page and page-blocks

* dev: page id filter for page blocks
2023-03-22 01:34:10 +05:30
pablohashescobar
025c8b3835 feat: sub issue toggle (#464) 2023-03-22 01:33:56 +05:30
pablohashescobar
9339138c0e feat: user workspace dashboard endpoint (#461)
* dev: initiate new dashboard endpoint

* fix: updated issue week for this count and pending issues

* dev: add try catch block

* dev: add exception

* dev: issue state distribution endpoint

* dev: move from state name to state group

* dev: add overdue issues and upcoming issues
2023-03-22 01:33:44 +05:30
pablohashescobar
988b27f909 refactor: users endpoint to return invites and assigned issues count (#457) 2023-03-22 01:33:31 +05:30
pablohashescobar
a3bacbfef1 fix: workspace invitation datetime import (#456)
* chore: update the endpoint to return last 6 months data

* dev: add datetime import
2023-03-22 01:33:19 +05:30
pablohashescobar
698718aa8d chore: rename analytics env variable keys (#455) 2023-03-22 01:33:06 +05:30
pablohashescobar
7fd775ab05 chore: update the endpoint to return last 6 months data (#453) 2023-03-22 01:32:51 +05:30
pablohashescobar
e5f8c94de8 feat: add flag for toggling issue views (#452) 2023-03-22 01:32:37 +05:30
Dakshesh Jain
9c388d8e50 refactor: setting filters as null if value is an empty array (#483)
* refractor: added params to fetch key

* feat: create views directly from views list page

fix: selected filter not showing up in multi-level dropdown, refactor: arranged imports

* refactor: setting filters as null if value is an empty array
2023-03-21 17:11:04 +05:30
Dakshesh Jain
bf09673d09 refactor: making unsplash api request from api folder (#482)
* refractor: added params to fetch key

* feat: create views directly from views list page

fix: selected filter not showing up in multi-level dropdown, refactor: arranged imports

* refactor: making unsplash api request from api folder

to hide acces key from client side
2023-03-21 16:31:01 +05:30
Dakshesh Jain
5869c91d70 fix: added redirection to sign-in page if fetching user was a fail in the context (#481)
* refractor: added params to fetch key

* feat: create views directly from views list page

fix: selected filter not showing up in multi-level dropdown, refactor: arranged imports

* fix: added redirection to sign-in page if fetching user was a fail in the context
2023-03-21 12:48:17 +05:30
Dakshesh Jain
53df658b60 refactor: added params to filters, and removed manual mutation (#480)
* refractor: added params to fetch key

* feat: create views directly from views list page

fix: selected filter not showing up in multi-level dropdown, refactor: arranged imports

* refactor: added params to filters, and removed manual mutation
2023-03-21 12:47:47 +05:30
Anmol Singh Bhatia
505b14e3a6 fix: ui fixes and improvement (#479)
* fix: list view longer title tooltip fix

* fix: module and cycle sidebar ui improvement
2023-03-21 12:47:10 +05:30
Anmol Singh Bhatia
b96d40f106 style: auth screens (#478)
* style: sign in page

* style: github and google sign

* style: sign with code and password

* style: not a member and not authorized for project setting

* style: join project icon

* chore: comment removed
2023-03-21 12:46:12 +05:30
Dakshesh Jain
68150a9d2b feat: create views directly from the views list page (#472)
* refractor: added params to fetch key

* feat: create views directly from views list page

fix: selected filter not showing up in multi-level dropdown, refactor: arranged imports
2023-03-18 11:34:49 +05:30
Dakshesh Jain
e6b0012fe2 fix: mutation on issue create (#473)
* refractor: added params to fetch key

* feat: create views directly from views list page

fix: selected filter not showing up in multi-level dropdown, refactor: arranged imports

* fix: mutation on project create
2023-03-18 11:34:29 +05:30
Anmol Singh Bhatia
5739d95ab4 style: onboarding, chore: refactoring (#474)
* style: onboarding screens

* style: onboarding card component and refactoring

* fix: onboarding card text fix

* fix: merge conflict fix
2023-03-18 11:34:09 +05:30
pablohashescobar
350e183375 dev: update importer task to create user automatically and adding it to project and workspace (#467) 2023-03-17 22:57:10 +05:30
Aaryan Khandelwal
e7ef6275cd style: new buttons added (#470) 2023-03-17 10:40:38 +05:30
Aaryan Khandelwal
4de0abfc22 fix: minor ui fixes (#469) 2023-03-17 10:39:06 +05:30
Aaryan Khandelwal
5f796e732a fix: bot activity and comment log name (#463)
* fix: github bot activity log details

* fix: bot comment details

* fix: updated bot logs

* refactor: bot name logic
2023-03-17 10:38:01 +05:30
Dakshesh Jain
0fb9a14f15 refractor: added params to fetch key (#465) 2023-03-16 18:15:08 +05:30
Aaryan Khandelwal
23c468786d style: filter issues dropdown (#466) 2023-03-16 18:14:07 +05:30
Dakshesh Jain
0f06589b83 style: made new issue filter dropdown (#462) 2023-03-16 16:27:18 +05:30
Aaryan Khandelwal
a84abc60b2 style: workspace dashboard (#460)
* style: workspace dashboard

* feat: activity graph

* chore: change tile colors for activity graph

* fix: activity graph tiles order, color

* style: activity intensity
2023-03-16 15:53:49 +05:30
Aaryan Khandelwal
27324ddd93 fix: github description not appearing (#459) 2023-03-16 15:53:25 +05:30
Aaryan Khandelwal
d413dd1169 chore: update user profile stats (#458) 2023-03-16 15:53:09 +05:30
Dakshesh Jain
ef0e326ca0 feat: issues filter using views (#448)
* fix: made basic UI for views, binded services and logic for views

* feat: views list, delete view, and conditionally updating filters or my view props
2023-03-16 14:07:19 +05:30
Aaryan Khandelwal
96ad751e11 style: new workspace dashboard design (#454)
* style: workspace dashboard

* feat: activity graph
2023-03-16 01:36:21 +05:30
vamsi
8370511a66 dev: new migrations Importer, IssueView, IssueViewFavorite and a few alterations 2023-03-16 00:41:50 +05:30
pablohashescobar
836dc4027b feat: jitsu events for sign in and sign up (#423)
* feat: jitsu events for sign in and sign up

* dev: update event data
2023-03-15 23:25:38 +05:30
pablohashescobar
88754e6fc0 dev: separate endpoints for workspace assets and user assets (#420) 2023-03-15 23:25:23 +05:30
pablohashescobar
b6ee197b40 feat: issue filter views (#418)
* dev: views initiated

* dev: refactor filtering logic

* dev: move state grouping filter to util function

* dev: view issues create endpoint and update on filters for time

* dev: rename views to issue views

* dev: rename in serilaizer and views

* dev: update issue filters

* dev: update filter

* feat: create issue favorites

* dev: update query keys

* dev: update create and update method
2023-03-15 23:25:09 +05:30
pablohashescobar
46f6b61928 refactor: grouper function to fix priority keys (#415) 2023-03-15 23:24:55 +05:30
pablohashescobar
5d8f2b6b75 feat: github importer (#425)
* dev: init github importer

* dev: add endpoint for creating import

* dev: create endpoint to bulk create issues

* dev: bulk issue importer

* dev: bulk create endpoints for labels and updates in issue bulk create endpoint to create labels and links

* dev: add comments in bluk create

* dev: status import endpoint and user invitaion workflow

* dev: initiate github repo sync

* dev: bulk issue sync endpoint and fix key issue in bg task

* dev: update endpoints for service imports

* dev: update labels logic

* dev: update importer task

* dev: bulk issue activities

* dev: update importer task for mapped users

* dev: update importer endpoint to send github token

* dev: update bulk import endpoint

* fix: workspace get query

* dev: update bulk import endpoints
2023-03-15 23:24:44 +05:30
pablohashescobar
d3ca8560fc fix: project list ordering (#427) 2023-03-15 23:24:26 +05:30
pablohashescobar
ab9e0cf559 refactor: update response structure for cycle issue and module issues (#432) 2023-03-15 23:21:37 +05:30
pablohashescobar
c07cfee018 refactor: update favorites for project, cycle and module (#434)
* dev: refactor favorites

* dev: fix typo
2023-03-15 23:21:23 +05:30
pablohashescobar
ed8f0b8473 feat: user activity graph (#437)
* feat: user activity graph

* dev: issue completed and activity graph
2023-03-15 23:21:08 +05:30
pablohashescobar
0082a98d53 dev: add cycle date validation (#442) 2023-03-15 23:20:49 +05:30
pablohashescobar
d6aadb115d refactor: users endpoint to return invites and assigned issues count (#449) 2023-03-15 23:20:31 +05:30
Aaryan Khandelwal
4639ab3d9c fix: workspace dropdown (#447)
* fix: workspace dropdown links

* fix: module progress round off
2023-03-15 18:50:37 +05:30
Aaryan Khandelwal
c11bf7c7de feat: progress bar for module (#446) 2023-03-15 18:00:40 +05:30
Anmol Singh Bhatia
ae8902e815 style: sidebar icon color (#444) 2023-03-15 17:41:52 +05:30
Anmol Singh Bhatia
164072e3cc fix: date checker edge case fix (#443) 2023-03-15 17:41:24 +05:30
Dakshesh Jain
928ebdf632 fix: mutation for issue update on both kanban & list (#436)
* refactor: issues filter logic

* fix: removed fetch logic from hooks

* feat: filter by assignee and label

* chore: remove filter buttons

* feat: filter options

* fix: mutation for issue update on both kanban & list

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-03-15 11:44:44 +05:30
Anmol Singh Bhatia
636e8e6c60 style: empty state global component (#435) 2023-03-15 11:01:54 +05:30
Aaryan Khandelwal
bfab4865cd chore: update user file assets endpoint (#438)
* chore: new service for user assets

* chore: update user file assets endpoint
2023-03-15 11:00:42 +05:30
Aaryan Khandelwal
dbd6de0988 feat: views template created (#439) 2023-03-15 11:00:05 +05:30
Aaryan Khandelwal
32d37ec45e refactor: custom search select component (#440) 2023-03-15 10:59:43 +05:30
Aaryan Khandelwal
bcd2ac1317 feat: issue filters dropdown created (#441) 2023-03-15 10:59:23 +05:30
Dakshesh Jain
0117ccfca2 fix: made project list authenticated (#428) 2023-03-14 12:21:06 +05:30
Aaryan Khandelwal
0ba81a10f1 style: made the paddings and text sizes smaller (#433) 2023-03-14 12:18:14 +05:30
Aaryan Khandelwal
3f5bbf336c fix: truncate text function (#431) 2023-03-14 12:16:38 +05:30
Aaryan Khandelwal
d6d51c2f43 fix: modules sidebar lead select not working (#429) 2023-03-14 12:16:26 +05:30
Anmol Singh Bhatia
d5d64e09d4 style: design (#430)
* style: shortcut modal

* style: feature setting module icon

* style: delete issue modal

* style: delete project modal

* style: sidebar prompt for chart and other info

* fix: create issue modal state icon

* fix: workspace dropdown
2023-03-13 23:38:43 +05:30
Narayana Vadapalli
7d7683ae6f Merge pull request #424 from pinarruiz/feature/upload-images
Github actions to push images
2023-03-13 10:20:37 +05:30
Narayana Vadapalli
fcd64de8af Update push-image-frontend.yml 2023-03-13 10:19:17 +05:30
Narayana Vadapalli
b2765d47b4 Update push-image-backend.yml 2023-03-13 10:15:05 +05:30
Alejandro Pinar Ruiz
aca0c251b8 Github actions to push images 2023-03-12 20:35:47 +01:00
pablohashescobar
6de6522a41 chore: permissions for api endpoints (#419) 2023-03-11 23:51:06 +05:30
Vihar Kurama
bff89ee4c6 Merge pull request #422 from makeplane/feat/issue_templates
feat: new issue templates
2023-03-11 23:50:16 +05:30
pablohashescobar
7744d9b69a feat: new issue templates 2023-03-11 23:49:02 +05:30
Aaryan Khandelwal
441cf39d2c refactor: global workspace form (#421) 2023-03-11 17:23:23 +05:30
Anmol Singh Bhatia
4a7f80712b style: workspace sidebar (#417) 2023-03-10 16:05:10 +05:30
Aaryan Khandelwal
c7923f6d44 feat: added load more button to github repos dropdown (#414) 2023-03-10 16:03:49 +05:30
Anmol Singh Bhatia
4fad685ec8 style: workspace dropdown (#416)
* style: workspace dropdown

* style: workspace dropdown hover fix
2023-03-10 12:32:29 +05:30
Anmol Singh Bhatia
704b7d02ef style : ui fixes (#412)
* fix: kanban view vertical scroll fix

* fix: delete option remove from my issue page

* fix: my issue filter key renamed with id

* fix: sidebar ellipsis alignment

* fix: cycle card favorite icon alignment

* style: icon added in card options

* fix: progress icon alignment

* style: my issue page list view
2023-03-09 22:50:34 +05:30
Anmol Singh Bhatia
4e9149a27c style: empty cycle state (#410) 2023-03-09 22:49:03 +05:30
pablohashescobar
0416e07f46 refactor: self hosting setup (#411)
* merge-commit: self hosted updates

* dev: updates in self hosting setup

* dev: update script to get the instance IP

* dev: update script to generate backend secret key
2023-03-09 20:49:12 +05:30
Anmol Singh Bhatia
e3e57df4a2 style: list view (#409)
* style: list view

* style: list board header spacing fix
2023-03-09 16:05:25 +05:30
Vamsi Kurama
2e1c113fdd Merge pull request #402 from makeplane/develop
dev: promote to staging
2023-03-08 20:30:28 +05:30
vamsi
981a246db1 Merge branch 'develop' of https://github.com/makeplane/plane into develop 2023-03-08 20:29:42 +05:30
vamsi
8641e35a61 Merge branch 'stage-release' into develop 2023-03-08 20:28:36 +05:30
Aaryan Khandelwal
20aa3ce318 dev: promote the develop to stage-release (#399) (#403)
* chore: new link endpoints

* chore: added created by info for link

* chore: cannot have empty state group

* feat: filtering for cycle and module issue and updated grouper function for grouping in modules and cycles (#342)

* docs: github integration (#346)

* fix: add pagination for github repositories endpoint (#345)

* fix: remove bot accounts from list api (#344)

* refactor: create new endpoints for date checking getting current upcoming and past cycles (#343)

* refactor: create new endpoints for date checking getting current upcoming and past cycles

* refactor: rename endpoint to match consistency

* fix: remove project slug (#340)

* refactor: update links to different endpoints (#338)

* chore: cycle validation services and constants added

* style: kanban board

* chore:  cycle type and services updated

* chore: completed cycle dynamic importing and refactor

* feat: cycle modal date validation

* fix: build fix

* style: redesigned sidebar, added new icons and spacing changes

* style: changed app header color to white

* feat: cover image selector for project create

* style/projects_page

* style: added dragging state design

* fix: cycle form date

* chore: draft cycle services and types

* feat: draft tab and cycle sidebar update

* style: projects list page

* fix: image aspect ratio

* style: assignee drop down label

* style: new primary button design

* style: assignee dropdown

* style: assignee dropdown stlye fix

* style: state dropdown redesign

* style: dropdown ui consisteny

* style: priority dropdown redesign

* style: label dropdown redesign

* style: issue dropdown re-order

* style: state Icon

* style: date dropdown redesign

* fix: dropdown issue label

* style: transsition

* style: color fixed

* chore: labels list file and function rename

* style: redesigned create project modal

style: changed image picker to pop-over instread of modal

* fix: upload button on workspace settings page not working, UX of workspace settings image upload

* feat: date range status function added

* style: project settings pages

* fix: merge conflicts

* fix: mutation fix and date range helper fn added

* style: workspace settings pages

* style: dropdowns, feat: favorite projects in sidebar

* feat: global component for combobox with new design

* feat: custom context menu for issues in kanban board

* refactor: global context menu component

* chore: updated context menu component

* chore: updated sidebar selects

* style: kanban horizontal scrollbar added (#372)

* style: new cycle list (#374)

* feat: short date helper function

* feat: linear progress indicator added

* style: new cyce list and cycle card design

* feat: short date function improve

* feat: linear progress indicator improvement

* style: cycle card and progress indicator

* fix: helper date function and progress indicator fix

* fix: build error

---------



* chore: updated project favorites endpoints (#375)

* feat: favorite cycle and style: style improvements (#376)

* style: consistent btn

* style: caret direction for disclosure

* fix: progress tooltip value rounded

* chore: favorite cycle serivces

* chore: favorite cycle type and constant

* feat: favorite cycle feat added

* refactor: favorite services and type

* fix: build fix

* refactor: sidebar projects menu (#377)

* feat: add endpoint for draft cycles and add validation for creating draft cycles (#355)

* feat: add endpoint for draft cycles and add validation for creating draft cycles

* fix: key error in cycle create endpoint

* feat: delete file assets from storage (#373)

* chore: rename past cycle to completed cycle (#347)

* fix: workspace member listing endpoint (#348)

* fix: module issue viewset typo (#349)

* feat: add project to favourites (#352)

* feat: add project to favourites

* feat: add project is_favourite attribute to list endpoints

* refactor: updated destroy endpoint to send project_id

* chore: nomenclature update

* feat: add cover image to project (#353)

* fix: cycle date filtering for current and upcoming cycle (#357)

* fix: update filtering for completed cycles

* fix: filter updated for upcoming cycles

* fix: cycle and module issue filtering (#363)

* feat: already exisiting  url validation (#368)

* feat: cycle favourites for user (#369)

* feat: cycle favourites for user

* chore: update nomenclature

* chore: update on nomenclature

* feat: add favorites for completed and current cycle endpoints

* feat: module favourites for user (#370)

* feat: added floating toolbar on text selection (#378)

style: re-designed create-issue modal

* dev: migrations added for ProjectFavorite, ModuleFavorite, CycleFavorite including a bunch of other attribs

* chore: cycles loading, fix: cycles favorite mutation (#379)

* style: cycle sidebar, fix: cycle card bug fix   (#383)

* style: new cycle sidebar

* style: other information section

* style: progress bar bg fix

* fix: cycle card bug fix

* style: progress chart

* style: chart tooltip

* style : module sidebar (#385)

* style: new cycle sidebar

* style: other information section

* style: progress bar bg fix

* fix: cycle card bug fix

* style: progress chart

* style: chart tooltip

* style: module link tab added in sidebar stats

* style: lead and member select

* fix: text selection moving when typing in between (#384)

* feat: added floating toolbar on text selection (#386)

style: re-designed create-issue modal

* style :module list (#387)

* chore: module favorite type and services

* style: module list

* style: module list and card

* fix: link fix

* style: truncate (#388)

* style: truncate

* fix: truncate text added to cycle and module card

* fix: custom menu link item (#390)

* fix: ui fixes (#392)

* fix: ui fixes

* chore: kanban issue title length

* style: ui fix (#393)

* style: truncate

* fix: truncate text added to cycle and module card

* fix: progress percentage

* feat: cycle card tooltip

* fix: sidebar fix

* fix: edit module mutation error (#394)

* fix: issue details mutation (#389)

* fix: ui improvement (#395)

* fix: current cycle date updation

* fix: sidebar overflow fix , date helper fn added

* chore: update module dropdowns (#396)

* fix: project member filter for bot accounts (#391)

* fix: make api token only view once (#382)

* dev: add back migration for project cover images (#381)

* fix: rename db host name for docker setup (#380)

* dev: promote to staging (#397)













* Revert "dev: promote to staging (#397)" (#398)

This reverts commit f7405ba1d6.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
Co-authored-by: vamsi <vamsi.kurama@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>
Co-authored-by: sphynxux <122926002+sphynxux@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@caravel.tech>
Co-authored-by: Dakshesh Jain <dakshesh.jain14@gmail.com>
2023-03-08 19:58:36 +05:30
Vamsi Kurama
aa240b90b0 Merge pull request #401 from makeplane/fix/order_by_text
fix: order by text
2023-03-08 19:22:57 +05:30
Aaryan Khandelwal
674ecd33ef fix: order by text 2023-03-08 19:15:28 +05:30
Vamsi Kurama
523308a768 Merge pull request #400 from makeplane/fix/kanban_overlay
fix: drag overlay z-index, sidebar dropdowns
2023-03-08 19:12:32 +05:30
Aaryan Khandelwal
223a204a97 fix: drag overlay z-index, sidebar dropdowns 2023-03-08 19:08:57 +05:30
Vamsi Kurama
c9252c9713 dev: promote the develop to stage-release (#399)
* chore: new link endpoints

* chore: added created by info for link

* chore: cannot have empty state group

* feat: filtering for cycle and module issue and updated grouper function for grouping in modules and cycles (#342)

* docs: github integration (#346)

* fix: add pagination for github repositories endpoint (#345)

* fix: remove bot accounts from list api (#344)

* refactor: create new endpoints for date checking getting current upcoming and past cycles (#343)

* refactor: create new endpoints for date checking getting current upcoming and past cycles

* refactor: rename endpoint to match consistency

* fix: remove project slug (#340)

* refactor: update links to different endpoints (#338)

* chore: cycle validation services and constants added

* style: kanban board

* chore:  cycle type and services updated

* chore: completed cycle dynamic importing and refactor

* feat: cycle modal date validation

* fix: build fix

* style: redesigned sidebar, added new icons and spacing changes

* style: changed app header color to white

* feat: cover image selector for project create

* style/projects_page

* style: added dragging state design

* fix: cycle form date

* chore: draft cycle services and types

* feat: draft tab and cycle sidebar update

* style: projects list page

* fix: image aspect ratio

* style: assignee drop down label

* style: new primary button design

* style: assignee dropdown

* style: assignee dropdown stlye fix

* style: state dropdown redesign

* style: dropdown ui consisteny

* style: priority dropdown redesign

* style: label dropdown redesign

* style: issue dropdown re-order

* style: state Icon

* style: date dropdown redesign

* fix: dropdown issue label

* style: transsition

* style: color fixed

* chore: labels list file and function rename

* style: redesigned create project modal

style: changed image picker to pop-over instread of modal

* fix: upload button on workspace settings page not working, UX of workspace settings image upload

* feat: date range status function added

* style: project settings pages

* fix: merge conflicts

* fix: mutation fix and date range helper fn added

* style: workspace settings pages

* style: dropdowns, feat: favorite projects in sidebar

* feat: global component for combobox with new design

* feat: custom context menu for issues in kanban board

* refactor: global context menu component

* chore: updated context menu component

* chore: updated sidebar selects

* style: kanban horizontal scrollbar added (#372)

* style: new cycle list (#374)

* feat: short date helper function

* feat: linear progress indicator added

* style: new cyce list and cycle card design

* feat: short date function improve

* feat: linear progress indicator improvement

* style: cycle card and progress indicator

* fix: helper date function and progress indicator fix

* fix: build error

---------

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

* chore: updated project favorites endpoints (#375)

* feat: favorite cycle and style: style improvements (#376)

* style: consistent btn

* style: caret direction for disclosure

* fix: progress tooltip value rounded

* chore: favorite cycle serivces

* chore: favorite cycle type and constant

* feat: favorite cycle feat added

* refactor: favorite services and type

* fix: build fix

* refactor: sidebar projects menu (#377)

* feat: add endpoint for draft cycles and add validation for creating draft cycles (#355)

* feat: add endpoint for draft cycles and add validation for creating draft cycles

* fix: key error in cycle create endpoint

* feat: delete file assets from storage (#373)

* chore: rename past cycle to completed cycle (#347)

* fix: workspace member listing endpoint (#348)

* fix: module issue viewset typo (#349)

* feat: add project to favourites (#352)

* feat: add project to favourites

* feat: add project is_favourite attribute to list endpoints

* refactor: updated destroy endpoint to send project_id

* chore: nomenclature update

* feat: add cover image to project (#353)

* fix: cycle date filtering for current and upcoming cycle (#357)

* fix: update filtering for completed cycles

* fix: filter updated for upcoming cycles

* fix: cycle and module issue filtering (#363)

* feat: already exisiting  url validation (#368)

* feat: cycle favourites for user (#369)

* feat: cycle favourites for user

* chore: update nomenclature

* chore: update on nomenclature

* feat: add favorites for completed and current cycle endpoints

* feat: module favourites for user (#370)

* feat: added floating toolbar on text selection (#378)

style: re-designed create-issue modal

* dev: migrations added for ProjectFavorite, ModuleFavorite, CycleFavorite including a bunch of other attribs

* chore: cycles loading, fix: cycles favorite mutation (#379)

* style: cycle sidebar, fix: cycle card bug fix   (#383)

* style: new cycle sidebar

* style: other information section

* style: progress bar bg fix

* fix: cycle card bug fix

* style: progress chart

* style: chart tooltip

* style : module sidebar (#385)

* style: new cycle sidebar

* style: other information section

* style: progress bar bg fix

* fix: cycle card bug fix

* style: progress chart

* style: chart tooltip

* style: module link tab added in sidebar stats

* style: lead and member select

* fix: text selection moving when typing in between (#384)

* feat: added floating toolbar on text selection (#386)

style: re-designed create-issue modal

* style :module list (#387)

* chore: module favorite type and services

* style: module list

* style: module list and card

* fix: link fix

* style: truncate (#388)

* style: truncate

* fix: truncate text added to cycle and module card

* fix: custom menu link item (#390)

* fix: ui fixes (#392)

* fix: ui fixes

* chore: kanban issue title length

* style: ui fix (#393)

* style: truncate

* fix: truncate text added to cycle and module card

* fix: progress percentage

* feat: cycle card tooltip

* fix: sidebar fix

* fix: edit module mutation error (#394)

* fix: issue details mutation (#389)

* fix: ui improvement (#395)

* fix: current cycle date updation

* fix: sidebar overflow fix , date helper fn added

* chore: update module dropdowns (#396)

* fix: project member filter for bot accounts (#391)

* fix: make api token only view once (#382)

* dev: add back migration for project cover images (#381)

* fix: rename db host name for docker setup (#380)

* dev: promote to staging (#397)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>

* Revert "dev: promote to staging (#397)" (#398)

This reverts commit f7405ba1d6.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: sphynxux <122926002+sphynxux@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@caravel.tech>
Co-authored-by: Dakshesh Jain <dakshesh.jain14@gmail.com>
Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>
2023-03-08 01:07:00 +05:30
Vamsi Kurama
303f266fc7 Revert "dev: promote to staging (#397)" (#398)
This reverts commit f7405ba1d6.
2023-03-08 01:05:38 +05:30
Vamsi Kurama
f7405ba1d6 dev: promote to staging (#397)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>
2023-03-08 01:03:11 +05:30
pablohashescobar
cf72a187fe fix: rename db host name for docker setup (#380) 2023-03-08 01:00:52 +05:30
pablohashescobar
2967fb1bee dev: add back migration for project cover images (#381) 2023-03-08 01:00:34 +05:30
pablohashescobar
1a04eda613 fix: make api token only view once (#382) 2023-03-08 01:00:10 +05:30
pablohashescobar
0bd3e8ae95 fix: project member filter for bot accounts (#391) 2023-03-08 00:59:48 +05:30
Aaryan Khandelwal
cc498096f3 chore: update module dropdowns (#396) 2023-03-07 22:56:22 +05:30
Anmol Singh Bhatia
afe2b029c0 fix: ui improvement (#395)
* fix: current cycle date updation

* fix: sidebar overflow fix , date helper fn added
2023-03-07 22:38:49 +05:30
Dakshesh Jain
30a91a6b91 fix: issue details mutation (#389) 2023-03-07 22:22:06 +05:30
Aaryan Khandelwal
f725ea5b15 fix: edit module mutation error (#394) 2023-03-07 22:21:50 +05:30
Anmol Singh Bhatia
cf94b92be2 style: ui fix (#393)
* style: truncate

* fix: truncate text added to cycle and module card

* fix: progress percentage

* feat: cycle card tooltip

* fix: sidebar fix
2023-03-07 20:48:19 +05:30
Aaryan Khandelwal
88fca3c67c fix: ui fixes (#392)
* fix: ui fixes

* chore: kanban issue title length
2023-03-07 20:27:16 +05:30
Aaryan Khandelwal
cadb67a018 fix: custom menu link item (#390) 2023-03-07 20:02:03 +05:30
Anmol Singh Bhatia
d18765a613 style: truncate (#388)
* style: truncate

* fix: truncate text added to cycle and module card
2023-03-07 19:32:29 +05:30
Anmol Singh Bhatia
61102952d0 style :module list (#387)
* chore: module favorite type and services

* style: module list

* style: module list and card

* fix: link fix
2023-03-07 18:46:56 +05:30
Dakshesh Jain
d8bf9b4c2a feat: added floating toolbar on text selection (#386)
style: re-designed create-issue modal
2023-03-07 16:09:37 +05:30
Dakshesh Jain
388d5b054a fix: text selection moving when typing in between (#384) 2023-03-07 16:09:17 +05:30
Anmol Singh Bhatia
09eab9e6bf style : module sidebar (#385)
* style: new cycle sidebar

* style: other information section

* style: progress bar bg fix

* fix: cycle card bug fix

* style: progress chart

* style: chart tooltip

* style: module link tab added in sidebar stats

* style: lead and member select
2023-03-07 15:04:02 +05:30
Anmol Singh Bhatia
0246e0585b style: cycle sidebar, fix: cycle card bug fix (#383)
* style: new cycle sidebar

* style: other information section

* style: progress bar bg fix

* fix: cycle card bug fix

* style: progress chart

* style: chart tooltip
2023-03-07 13:43:09 +05:30
Aaryan Khandelwal
64978969a0 chore: cycles loading, fix: cycles favorite mutation (#379) 2023-03-07 11:04:51 +05:30
vamsi
b54a1f221f dev: migrations added for ProjectFavorite, ModuleFavorite, CycleFavorite including a bunch of other attribs 2023-03-07 03:09:04 +05:30
Dakshesh Jain
82f8b6d387 feat: added floating toolbar on text selection (#378)
style: re-designed create-issue modal
2023-03-06 22:49:06 +05:30
pablohashescobar
d28fe930a6 feat: module favourites for user (#370) 2023-03-06 19:00:00 +05:30
pablohashescobar
cb8b6b43dc feat: cycle favourites for user (#369)
* feat: cycle favourites for user

* chore: update nomenclature

* chore: update on nomenclature

* feat: add favorites for completed and current cycle endpoints
2023-03-06 18:59:47 +05:30
pablohashescobar
79d7b6fec3 feat: already exisiting url validation (#368) 2023-03-06 18:58:10 +05:30
pablohashescobar
39f54d8265 fix: cycle and module issue filtering (#363) 2023-03-06 18:57:58 +05:30
pablohashescobar
3d57edfcf8 fix: cycle date filtering for current and upcoming cycle (#357)
* fix: update filtering for completed cycles

* fix: filter updated for upcoming cycles
2023-03-06 18:57:46 +05:30
pablohashescobar
ae64b53cf3 feat: add cover image to project (#353) 2023-03-06 18:57:20 +05:30
pablohashescobar
689eaad0f0 feat: add project to favourites (#352)
* feat: add project to favourites

* feat: add project is_favourite attribute to list endpoints

* refactor: updated destroy endpoint to send project_id

* chore: nomenclature update
2023-03-06 18:57:07 +05:30
pablohashescobar
697e7f13b5 fix: module issue viewset typo (#349) 2023-03-06 18:56:53 +05:30
pablohashescobar
cee8a6a8cd fix: workspace member listing endpoint (#348) 2023-03-06 18:56:41 +05:30
pablohashescobar
f5e96b8078 chore: rename past cycle to completed cycle (#347) 2023-03-06 18:56:21 +05:30
pablohashescobar
cecd025a78 feat: delete file assets from storage (#373) 2023-03-06 18:56:05 +05:30
pablohashescobar
3a81a6c186 feat: add endpoint for draft cycles and add validation for creating draft cycles (#355)
* feat: add endpoint for draft cycles and add validation for creating draft cycles

* fix: key error in cycle create endpoint
2023-03-06 18:45:20 +05:30
Aaryan Khandelwal
27653907f9 refactor: sidebar projects menu (#377) 2023-03-06 18:38:01 +05:30
Anmol Singh Bhatia
626aae696f feat: favorite cycle and style: style improvements (#376)
* style: consistent btn

* style: caret direction for disclosure

* fix: progress tooltip value rounded

* chore: favorite cycle serivces

* chore: favorite cycle type and constant

* feat: favorite cycle feat added

* refactor: favorite services and type

* fix: build fix
2023-03-06 16:36:22 +05:30
Aaryan Khandelwal
d6badcd9b8 chore: updated project favorites endpoints (#375) 2023-03-06 11:37:18 +05:30
Anmol Singh Bhatia
786816ed41 style: new cycle list (#374)
* feat: short date helper function

* feat: linear progress indicator added

* style: new cyce list and cycle card design

* feat: short date function improve

* feat: linear progress indicator improvement

* style: cycle card and progress indicator

* fix: helper date function and progress indicator fix

* fix: build error

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-03-06 11:36:48 +05:30
Anmol Singh Bhatia
fef72ccc70 style: kanban horizontal scrollbar added (#372) 2023-03-06 11:13:08 +05:30
Aaryan Khandelwal
a4dc4d1f15 Merge pull request #371 from makeplane/style/dropdowns
style: consistent dropdowns, feat: custom context menu
2023-03-06 10:39:50 +05:30
Aaryan Khandelwal
4f4f3ebbde chore: updated sidebar selects 2023-03-05 23:24:50 +05:30
Aaryan Khandelwal
6d99557de5 chore: updated context menu component 2023-03-05 20:22:01 +05:30
Aaryan Khandelwal
a4da4bf889 refactor: global context menu component 2023-03-05 03:24:24 +05:30
Aaryan Khandelwal
0a681937fd feat: custom context menu for issues in kanban board 2023-03-04 19:33:24 +05:30
Aaryan Khandelwal
a875c608d4 feat: global component for combobox with new design 2023-03-04 19:10:35 +05:30
Aaryan Khandelwal
4d598fd6b6 style: dropdowns, feat: favorite projects in sidebar 2023-03-04 17:47:03 +05:30
Dakshesh Jain
067859b4bd Merge pull request #367 from makeplane/style/workspace_settings
style: workspace settings pages
2023-03-03 18:16:53 +05:30
Aaryan Khandelwal
1d8b4296fb style: workspace settings pages 2023-03-03 14:30:21 +05:30
Aaryan Khandelwal
433276c833 Merge pull request #359 from makeplane/style/projects_page
style: projects page
2023-03-03 14:06:59 +05:30
Aaryan Khandelwal
03a8ad336e Merge pull request #366 from makeplane/style/project_settings
style: project settings pages
2023-03-03 14:04:04 +05:30
Aaryan Khandelwal
e281feddf5 fix: merge conflicts 2023-03-03 13:55:18 +05:30
Aaryan Khandelwal
f290a417bc Merge pull request #358 from makeplane/feat/cycle_validations
feat: cycle validations
2023-03-03 13:53:09 +05:30
Anmol Singh Bhatia
f965734f3b fix: mutation fix and date range helper fn added 2023-03-03 13:49:19 +05:30
Aaryan Khandelwal
530edbe149 fix: merge conflicts 2023-03-03 13:38:40 +05:30
Aaryan Khandelwal
ad7b691b2b Merge branch 'develop' of https://github.com/makeplane/plane into style/project_settings 2023-03-03 13:32:42 +05:30
Aaryan Khandelwal
76b615d964 Merge pull request #365 from makeplane/fix/workspace_settings_logo
fix: upload button on workspace settings page not working
2023-03-03 13:32:25 +05:30
Aaryan Khandelwal
2b01ae6500 Merge pull request #364 from makeplane/style/create_project
style: redesigned create project modal
2023-03-03 13:31:45 +05:30
Aaryan Khandelwal
db547cc51a style: project settings pages 2023-03-03 13:29:36 +05:30
Anmol Singh Bhatia
02e4e58f19 feat: date range status function added 2023-03-03 11:32:00 +05:30
Dakshesh Jain
6bf26617a3 fix: upload button on workspace settings page not working, UX of workspace settings image upload 2023-03-02 18:39:51 +05:30
Dakshesh Jain
63d0a0dea7 Merge branch 'develop' of https://github.com/makeplane/plane into style/create_project 2023-03-02 17:09:28 +05:30
Dakshesh Jain
e96a755a2e style: redesigned create project modal
style: changed image picker to pop-over instread of modal
2023-03-02 17:06:21 +05:30
Aaryan Khandelwal
aeadf0ebbf Merge pull request #362 from makeplane/style/issue_dropdown
style: new dropdown
2023-03-02 17:01:19 +05:30
Anmol Singh Bhatia
c6d54a0ad2 chore: labels list file and function rename 2023-03-02 15:43:50 +05:30
Anmol Singh Bhatia
1fe1596f9d style: color fixed 2023-03-02 14:23:38 +05:30
Anmol Singh Bhatia
6bf608a37a style: transsition 2023-03-02 13:36:20 +05:30
Anmol Singh Bhatia
5ae1f63985 fix: dropdown issue label 2023-03-02 13:29:55 +05:30
Aaryan Khandelwal
f5db3dc07b Merge pull request #351 from makeplane/style/app_header
style: changed app header color to white
2023-03-02 13:16:23 +05:30
Aaryan Khandelwal
2e6cd2638d Merge pull request #350 from makeplane/style/app_sidebar
style: redesigned sidebar, added new icons and spacing changes
2023-03-02 13:15:29 +05:30
Anmol Singh Bhatia
1f1fa19432 style: date dropdown redesign 2023-03-02 12:33:12 +05:30
Aaryan Khandelwal
ea509211a0 Merge pull request #354 from makeplane/feat/unsplash_modal
feat: cover image selector for project create
2023-03-02 12:00:16 +05:30
Aaryan Khandelwal
032f39d9ec Merge pull request #360 from makeplane/style/button
style: new primary button design
2023-03-02 11:59:20 +05:30
Anmol Singh Bhatia
9a88803a3f style: state Icon 2023-03-02 11:32:18 +05:30
Anmol Singh Bhatia
216c565afc Merge branch 'develop' of github.com:makeplane/plane into style/issue_dropdown 2023-03-02 11:02:01 +05:30
Anmol Singh Bhatia
700769665f style: issue dropdown re-order 2023-03-02 10:37:09 +05:30
Anmol Singh Bhatia
1476896005 style: label dropdown redesign 2023-03-02 10:36:19 +05:30
Anmol Singh Bhatia
cb2f0633f7 style: priority dropdown redesign 2023-03-02 09:38:54 +05:30
Anmol Singh Bhatia
fdbad4ff1a style: dropdown ui consisteny 2023-03-02 09:38:13 +05:30
Anmol Singh Bhatia
d8e1710a9b style: state dropdown redesign 2023-03-02 09:01:47 +05:30
Anmol Singh Bhatia
9a52031d59 style: assignee dropdown stlye fix 2023-03-02 09:01:16 +05:30
Anmol Singh Bhatia
217d6ea51c style: assignee dropdown 2023-03-02 08:03:41 +05:30
Dakshesh Jain
c5d7d4f751 style: new primary button design 2023-03-01 18:43:24 +05:30
Anmol Singh Bhatia
c897f04926 style: assignee drop down label 2023-03-01 16:10:48 +05:30
Aaryan Khandelwal
99cf2d4e8d Merge pull request #356 from makeplane/style/kanban_board
style: kanban board
2023-03-01 15:07:21 +05:30
Aaryan Khandelwal
35af45ddd7 fix: image aspect ratio 2023-03-01 14:18:02 +05:30
Aaryan Khandelwal
8f0ef7bf13 fix: merge conflicts 2023-03-01 14:14:24 +05:30
Aaryan Khandelwal
6afcf1f0e3 style: projects list page 2023-03-01 14:11:27 +05:30
Anmol Singh Bhatia
8a941d0d14 feat: draft tab and cycle sidebar update 2023-03-01 11:58:30 +05:30
Anmol Singh Bhatia
7ab6eb7b48 chore: draft cycle services and types 2023-03-01 11:56:14 +05:30
Anmol Singh Bhatia
a840cea9e9 fix: cycle form date 2023-03-01 11:55:04 +05:30
Aaryan Khandelwal
8589ce777f style: added dragging state design 2023-03-01 11:30:49 +05:30
Aaryan Khandelwal
f7e0e257a4 Merge branch 'develop' of https://github.com/makeplane/plane into style/kanban_board 2023-03-01 11:30:17 +05:30
Aaryan Khandelwal
2c0b27d838 Merge pull request #341 from makeplane/chore/delete_state_options
chore: cannot have empty state group
2023-03-01 10:48:40 +05:30
Aaryan Khandelwal
76b8b9eaef style/projects_page 2023-02-28 23:50:21 +05:30
Dakshesh Jain
b660b1d814 feat: cover image selector for project create 2023-02-28 20:54:55 +05:30
Dakshesh Jain
dea21cd660 style: changed app header color to white 2023-02-28 17:09:49 +05:30
Dakshesh Jain
73567dc7fc style: redesigned sidebar, added new icons and spacing changes 2023-02-28 16:48:02 +05:30
Anmol Singh Bhatia
7d42262e72 fix: build fix 2023-02-28 15:17:14 +05:30
Anmol Singh Bhatia
19e9f510bc feat: cycle modal date validation 2023-02-28 14:55:19 +05:30
Anmol Singh Bhatia
17e09d70e2 chore: completed cycle dynamic importing and refactor 2023-02-28 14:53:10 +05:30
Anmol Singh Bhatia
443c9300dd chore: cycle type and services updated 2023-02-28 14:47:32 +05:30
Aaryan Khandelwal
0cd3bb5956 style: kanban board 2023-02-28 14:42:46 +05:30
Anmol Singh Bhatia
d480325829 chore: cycle validation services and constants added 2023-02-28 10:31:52 +05:30
pablohashescobar
1b369feb6a refactor: update links to different endpoints (#338) 2023-02-28 02:09:22 +05:30
pablohashescobar
7b4d7f12f5 fix: remove project slug (#340) 2023-02-28 02:09:09 +05:30
pablohashescobar
1255552ebe refactor: create new endpoints for date checking getting current upcoming and past cycles (#343)
* refactor: create new endpoints for date checking getting current upcoming and past cycles

* refactor: rename endpoint to match consistency
2023-02-28 02:08:55 +05:30
pablohashescobar
1ff0970ed6 fix: remove bot accounts from list api (#344) 2023-02-28 02:08:34 +05:30
pablohashescobar
90b8d66946 fix: add pagination for github repositories endpoint (#345) 2023-02-28 02:08:17 +05:30
sphynxux
07295ac314 docs: github integration (#346) 2023-02-28 02:07:12 +05:30
pablohashescobar
ec4332ea6b feat: filtering for cycle and module issue and updated grouper function for grouping in modules and cycles (#342) 2023-02-27 15:32:15 +05:30
Aaryan Khandelwal
3af3bb0fb5 Merge pull request #339 from makeplane/chore/new_link_endpoint
chore: new link endpoints
2023-02-27 15:20:00 +05:30
Aaryan Khandelwal
522952fa59 chore: cannot have empty state group 2023-02-24 16:22:49 +05:30
Aaryan Khandelwal
9dd5b15cd3 chore: added created by info for link 2023-02-24 15:53:25 +05:30
Aaryan Khandelwal
df836d55d5 chore: new link endpoints 2023-02-24 15:50:15 +05:30
Vamsi Kurama
397a3cec4f Merge pull request #336 from makeplane/develop
release: bug-fixes and ui/ux improvements for 23 Feb 2023
2023-02-24 00:03:37 +05:30
Vamsi Kurama
3c6752807d Merge pull request #335 from makeplane/style/ui_consistency
style: kanban dropdowns
2023-02-23 23:58:06 +05:30
pablohashescobar
517600ac89 fix: add filter for workspace integrations (#325)
* fix: add filter for workspace integrations

* fix: update url for delete

* fix: remove github installation when deleted

* fix: delete old repos

* fix: add filter on repository endpoints
2023-02-23 23:56:48 +05:30
Aaryan Khandelwal
90c913ce03 fix: merge conflicts 2023-02-23 22:36:20 +05:30
Aaryan Khandelwal
b4c4271f66 style: kanban dropdowns, github integration loaders 2023-02-23 22:34:36 +05:30
Dakshesh Jain
b53b0bc3f0 fix: create issue modal close on escape click (#333) 2023-02-23 19:56:18 +05:30
Anmol Singh Bhatia
443c187cde feat: sidebar select option truncate (#334) 2023-02-23 19:54:28 +05:30
Anmol Singh Bhatia
946dddb6b2 fix: kanban assignees tooltip (#332) 2023-02-23 19:04:08 +05:30
Anmol Singh Bhatia
69e8b504de fix: ui fix (#331)
* fix: project card id removed

* feat: my issue page copy issue option
2023-02-23 18:12:43 +05:30
Aaryan Khandelwal
36a733cd06 style: github integration ui (#329)
* fix: ellipsis added to issue title

* feat: toolttip added

* feat: assignees tooltip added

* fix: build fix

* fix: build fix

* fix: build error

* fix: minor bugs and ux improvements

* style: github integration ui

* chore: updated .env.example file

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@caravel.tech>
2023-02-23 18:12:07 +05:30
sriram veeraghanta
2b3cb839ad environmental example variables fixes (#330) 2023-02-23 18:05:32 +05:30
Dakshesh Jain
98d4473501 fix: issue view not updating order_by value (#324) 2023-02-23 17:50:47 +05:30
Dakshesh Jain
a550f4b161 refractor: added proper types to getServerSideProps context (#321)
* fix: redirection after login

* refractor: added proper types to getServerSideProps context
2023-02-23 17:50:37 +05:30
Dakshesh Jain
1e63c5b1b3 style: added direction for multi-level drop-down (#328)
* feat: made new multi-level select listbox

* refractor: changeds Multi-level-select component and added direction props

* style: added direction for multi-level drop-down
2023-02-23 17:02:26 +05:30
Anmol Singh Bhatia
4caa4e33b1 fix: ui improvements (#327)
* fix: kanban board header scroll fix

* style: enable scrollbar style added

* fix: emoji picker overflow

* fix: delete project modal text overflow

* fix: cycle card ellipsis

* fix: tooltip position updated and custom class added

* fix: assignees tooltip overflow

* fix: module card

* fix: my issue page  tooltip and responsive title  added

* fix: home page tooltip and responsiveness
2023-02-23 16:46:52 +05:30
Dakshesh Jain
6a10faca68 feat: made new multi-level select listbox (#326) 2023-02-23 15:36:46 +05:30
sriram veeraghanta
ad5a8be0e2 Merge pull request #323 from makeplane/develop
release: Stage Release 23rd Feb 2023
2023-02-23 10:58:57 +05:30
Aaryan Khandelwal
92f717962c fix: minor bugs and ux improvements (#322)
* fix: ellipsis added to issue title

* feat: toolttip added

* feat: assignees tooltip added

* fix: build fix

* fix: build fix

* fix: build error

* fix: minor bugs and ux improvements

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia@caravel.tech>
2023-02-23 10:54:54 +05:30
vamsi
702cfeb4ee dev: added new migrations 2023-02-23 01:04:44 +05:30
vamsi
649748f801 Merge branch 'develop' of https://github.com/makeplane/plane into develop 2023-02-23 01:02:34 +05:30
vamsi
2fffad130e Merge branch 'master' of https://github.com/makeplane/plane into develop 2023-02-23 01:01:52 +05:30
pablohashescobar
937222fdd4 feat: assignee and label details in cycle and module issues (#319) 2023-02-23 01:01:09 +05:30
pablohashescobar
a9802f816e feat: github integration (#315)
* feat: initiate integrations

* feat: initiate github integration create models for the same

* feat: github integration views

* fix: update workspace integration view to create bot users

* refactor: rename repository model

* refactor: update github repo sync endpoint to create repo and sync in one go

* refactor: update issue activities to post the updates to segway hook

* refactor: update endpoints to get project id and add actor as a member of project in repo sync

* fix: make is bot as a read only field

* fix: remove github repo imports

* fix: url mapping

* feat: repo views

* refactor: update webhook request endpoint

* refactor: rename repositories table to github_repositories

* fix: workpace integration actor

* feat: label for github integration

* refactor: issue activity on create issue

* refactor: repo create endpoint and add db constraints for repo sync and issues

* feat: create api token on workpsace integration and avatar_url for integrations

* refactor: add uuid primary key for Audit model

* refactor: remove id from auditfield to maintain integrity and make avatar blank if none supplied

* feat: track comments on an issue

* feat: comment syncing from plane to github

* fix: prevent activities created by bot to be sent to webhook

* feat: github app installation id retrieve

* feat: github app installation id saved into db

* feat: installation_id for the github integragation and unique provider and project base integration for repo

* refactor: remove actor logic from activity task

* feat: saving github metadata using installation id in workspace integration table

* feat: github repositories endpoint

* feat: github and project repos synchronisation

* feat: delete issue and delete comment activity

* refactor: remove print logs

* FIX: reading env names for github app while installation

* refactor: update bot user firstname with title

* fix: add is_bot value in field

---------

Co-authored-by: venplane <venkatesh@plane.so>
2023-02-22 19:40:57 +05:30
Dakshesh Jain
c1a78cc230 fix: redirection after login (#320) 2023-02-22 17:54:27 +05:30
Anmol Singh Bhatia
d29f34566c fix : tooltip fix (#318)
* fix: ellipsis added to issue title

* feat: toolttip added

* feat: assignees tooltip added

* fix: build fix

* fix: build fix

* fix: build error

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-02-22 13:24:59 +05:30
Anmol Singh Bhatia
d8c10b6bc0 feat: issues tooltip , fix: ui improvement (#317)
* fix: ellipsis added to issue title

* feat: toolttip added

* feat: assignees tooltip added

* fix: build fix
2023-02-22 11:42:17 +05:30
sriram veeraghanta
2cadb3784b env fixes (#316) 2023-02-22 00:53:22 +05:30
pablohashescobar
f17ecd597b Merge pull request #278 from makeplane/feat/multiple_sub_issues
feat: assign multiple sub issues
2023-02-21 23:52:33 +05:30
pablohashescobar
33ed2f6c35 Merge pull request #287 from makeplane/fix/state_ordering
fix: state ordering in group
2023-02-21 23:52:21 +05:30
pablohashescobar
a904c4a7de Merge pull request #302 from makeplane/feat/issue_sorting_grouping
feat: updated issue grouping and filtering
2023-02-21 23:52:08 +05:30
pablohashescobar
71f9ae41f3 feat: created_by details for links (#313) 2023-02-21 23:50:54 +05:30
sriram veeraghanta
1b94c7b640 Merge pull request #314 from makeplane/develop
* chore: update all backend dependencies to the latest version

* feat: record issue completed at date when the issues are moved to fompleted group (#262)

* feat: cycle status (#265)

* feat: cycle status and dates added in sidebar

* feat: update status added

* chore: update python runtime

* feat: label grouping in dropdowns, default state in project settings (#266)

* feat: label grouping in dropdowns, default state in project settings

* feat: label disclosure default open

* refactor: label setting page

* chore: tooltip component updated

* chore: tooltip component updated

* feat/state_sequence_change

* fix: remirror buttons (#267)

* feat: burndown chart (#268)

* chore: recharts dependencie added

* chore: tpye added for issue completed at

* feat: date range helper fn added

* feat: progress chart added

* feat: ideal task line added in progress chart

* feat: chart legends added

* fix: state reordering (#269)

* fix: state reordering

* refactor: remove unnecessary argument

* refactor: mutation after setting default

* feat: drag and drop an issue to delete (#270)

* feat: drag and drop an issue to delete

* style: repositioned trash box

* feat : cycle sidebar revamp (#271)

* feat: range date picker added

* feat: cycle status ui improved

* feat : sidebar progress improvement (#272)

* feat: progress chart render validation

* fix: sidebar stats tab

* feat: sidebar active tab context

* chore: removed minor bugs (#273)

* fix: ui bug (#274)

* fix: shortcut search fix
shortcut modal ui fixes
shortcut search fix
email us label change
* fix: email us label updated

* feat: default state for project (#264)

* build: add channels requirement for the asgi configuration (#225)

* refactor: combine sign in and sign up endpoint to a single endpoint (#263)

* feat: state grouping and ordering list (#253)

* feat: state grouping and ordering list

* fix: state grouping in state list endpoint

* dev: added migrations for new models schema changes

* fix: mac text copy fix (#277)

* feat: state description in settings (#275)

* chore: removed minor bugs

* feat: state description in settings

* feat: group by assignee

* refactor: update django admin panel heading (#276)

* feat: create label option in create issue modal (#281)

* refactor: issue details page (#282)

* fix: shortcut search  (#283)

* fix: search case innsensitive

* style: email icon updated

* feat: module sidebar date and status updated (#285)

* feat: bulk assign sub-issues (#284)

* fix: consistent dropdowns, refactor: ui components (#286)

* build(deps): bump django in /apiserver/requirements (#289)

Bumps [django](https://github.com/django/django) from 3.2.17 to 3.2.18.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.2.17...3.2.18)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: workspace name and breadcrumb title , refactor: command palette (#290)

* refactor: command pallette

* fix: workspace name trim

* fix: breadcrumb title responsiveness added

* feat: copy link option (#292)

* feat: copy issue link added in issue card

* feat: copy cycle link added

* feat: ellipsis added in module card

* fix: origin path and handlecopytext added

* fix: remirror image not updating (#294)

* feat: resend login magic code  (#291)

* feat: resend login code on signing page after 30 seconds

* feat: handling error on code send

* refractor: isResendDisabled varible for resend button

* dev: timer count-down hook

* refractor: using new timer hook in sign in page

* feat: issue links (#288)

* feat: links for issues

* fix: add issue link in serilaizer

* feat: links can be added to issues

---------

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

* fix: default label color (#295)

* fix: colors of old labels can now be changed

* fix: black color for labels with no color

* fix: ui changes (#297)

* fix: module card height and invalid date

* fix: issue details page title resizing fix

* refractor: use local storage hook (#293)

* feat: resend login code on signing page after 30 seconds

* refractor: use local storage hook

* refractor: properly using new local storage hook on modules sidebar

* fix: assignee and labels field while editing an issue (#296)

* fix: assignee and labels field while editing an issue

* chore: remove unused declarations

* fix: issue title resizing fix (#300)

* fix: issue title resizing fix

* fix: header ui fix and invalid date label updated

* fix: try/catch for invalid values stored in local storage (#301)

* fix: create issue modal closing on clicking on Grammarly recommendation (#299)

fixed it by not closing modal on outside click

* style: not showing pointer & theme color on resend code button disabled (#298)

* fix: new project issues response (#303)

* refactor/cycles_folder_structure (#304)

* fix: ui changes (#306)

* fix: sidebar date range

* fix: renamed key with id in filters

* fix: replace progress bar

* chore: react progress bar package removed

* fix: progress chart legends position

* fix: progress chart legends alignment fix

* feat: manual ordering of issues (#305)

* feat: global component for links list (#307)

* Feat: Dockerizing using nginx reverse proxy (#280)

* minor docker fixes

* eslint config changes

* dockerfile changes to backend and frontend

* oauth enabled env flag

* sentry enabled env flag

* build: get alternatives for environment variables and static file storage

* build: automatically generate random secret key if not provided

* build: update docker compose for next url env add channels to requirements for asgi server and save files in local machine for docker environment

* build: update nginx conf for backend base url update backend dockerfile to make way for static file uploads

* feat: create a default user with given values else default values

* chore: update docker python version and other dependency version in docker

* build: update local settings file to run it in docker

* fix: update script to run in default production setting

* fix: env variable changes and env setup shell script added

* Added Single Dockerfile to run the Entire plane application

* docs build fixes

---------

Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>

* feat: edit module (#309)

* feat: edit module

* fix: build fix

* refactor: dnd function (#308)

* refactor: manual ordering bugs (#312)

* refactor: create issue modal input fields (#310)

* style: showing user sign-in progress on sign-in with code (#311)

* style: not showing pointer & theme color on resend code button disabled

* style: showing user sign-in progress on sign-in with code

* style: showing error from server on sign-in with code fail

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: vamsi <vamsi.kurama@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>
2023-02-21 19:17:32 +05:30
Dakshesh Jain
5cbb3ecd4d style: showing user sign-in progress on sign-in with code (#311)
* style: not showing pointer & theme color on resend code button disabled

* style: showing user sign-in progress on sign-in with code

* style: showing error from server on sign-in with code fail
2023-02-21 19:14:12 +05:30
Aaryan Khandelwal
c0263acb8a refactor: create issue modal input fields (#310) 2023-02-21 19:12:38 +05:30
Aaryan Khandelwal
8d6a357a7f refactor: manual ordering bugs (#312) 2023-02-21 19:11:54 +05:30
Aaryan Khandelwal
8c15a1519f refactor: dnd function (#308) 2023-02-21 14:56:32 +05:30
Anmol Singh Bhatia
3d28cde91d feat: edit module (#309)
* feat: edit module

* fix: build fix
2023-02-21 12:45:04 +05:30
sriram veeraghanta
bdca84bd09 Feat: Dockerizing using nginx reverse proxy (#280)
* minor docker fixes

* eslint config changes

* dockerfile changes to backend and frontend

* oauth enabled env flag

* sentry enabled env flag

* build: get alternatives for environment variables and static file storage

* build: automatically generate random secret key if not provided

* build: update docker compose for next url env add channels to requirements for asgi server and save files in local machine for docker environment

* build: update nginx conf for backend base url update backend dockerfile to make way for static file uploads

* feat: create a default user with given values else default values

* chore: update docker python version and other dependency version in docker

* build: update local settings file to run it in docker

* fix: update script to run in default production setting

* fix: env variable changes and env setup shell script added

* Added Single Dockerfile to run the Entire plane application

* docs build fixes

---------

Co-authored-by: Narayana <narayana.vadapalli1996@gmail.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
2023-02-21 11:31:43 +05:30
Aaryan Khandelwal
33e2986062 feat: global component for links list (#307) 2023-02-21 11:23:50 +05:30
Aaryan Khandelwal
818fe3ecf7 feat: manual ordering of issues (#305) 2023-02-20 19:19:46 +05:30
Anmol Singh Bhatia
202096500e fix: ui changes (#306)
* fix: sidebar date range

* fix: renamed key with id in filters

* fix: replace progress bar

* chore: react progress bar package removed

* fix: progress chart legends position

* fix: progress chart legends alignment fix
2023-02-20 19:00:40 +05:30
Aaryan Khandelwal
e5934e0b07 refactor/cycles_folder_structure (#304) 2023-02-20 11:23:04 +05:30
Aaryan Khandelwal
77c319c748 fix: new project issues response (#303) 2023-02-18 21:19:04 +05:30
pablohashescobar
d50cc14972 fix: typo in model aggregation key 2023-02-18 18:21:42 +05:30
pablohashescobar
495ac0ca00 feat: improved grouper with grouping function 2023-02-18 15:43:47 +05:30
pablohashescobar
236c660cc7 feat: sort order during create 2023-02-18 12:35:42 +05:30
pablohashescobar
eba0f02aeb feat: back migration script to populate random sort_order values 2023-02-18 12:29:46 +05:30
pablohashescobar
2505417dbd feat: updated issue grouping and filtering 2023-02-18 12:22:17 +05:30
Dakshesh Jain
393638c700 style: not showing pointer & theme color on resend code button disabled (#298) 2023-02-17 20:10:44 +05:30
Dakshesh Jain
11a36b4398 fix: create issue modal closing on clicking on Grammarly recommendation (#299)
fixed it by not closing modal on outside click
2023-02-17 20:10:21 +05:30
Dakshesh Jain
d71cf567e9 fix: try/catch for invalid values stored in local storage (#301) 2023-02-17 20:10:02 +05:30
Anmol Singh Bhatia
fcb932dc5d fix: issue title resizing fix (#300)
* fix: issue title resizing fix

* fix: header ui fix and invalid date label updated
2023-02-17 19:58:27 +05:30
Aaryan Khandelwal
c979599e53 fix: assignee and labels field while editing an issue (#296)
* fix: assignee and labels field while editing an issue

* chore: remove unused declarations
2023-02-17 19:07:36 +05:30
Dakshesh Jain
a0d176c952 refractor: use local storage hook (#293)
* feat: resend login code on signing page after 30 seconds

* refractor: use local storage hook

* refractor: properly using new local storage hook on modules sidebar
2023-02-17 18:52:16 +05:30
Anmol Singh Bhatia
8c39717068 fix: ui changes (#297)
* fix: module card height and invalid date

* fix: issue details page title resizing fix
2023-02-17 18:51:45 +05:30
Aaryan Khandelwal
45319d81db fix: default label color (#295)
* fix: colors of old labels can now be changed

* fix: black color for labels with no color
2023-02-17 17:06:30 +05:30
pablohashescobar
7c1f357bed feat: issue links (#288)
* feat: links for issues

* fix: add issue link in serilaizer

* feat: links can be added to issues

---------

Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
2023-02-17 17:04:12 +05:30
Dakshesh Jain
a66b2fd73d feat: resend login magic code (#291)
* feat: resend login code on signing page after 30 seconds

* feat: handling error on code send

* refractor: isResendDisabled varible for resend button

* dev: timer count-down hook

* refractor: using new timer hook in sign in page
2023-02-17 16:58:00 +05:30
Aaryan Khandelwal
4b068398bd fix: remirror image not updating (#294) 2023-02-17 16:57:31 +05:30
Anmol Singh Bhatia
1665863bd9 feat: copy link option (#292)
* feat: copy issue link added in issue card

* feat: copy cycle link added

* feat: ellipsis added in module card

* fix: origin path and handlecopytext added
2023-02-17 14:04:34 +05:30
Anmol Singh Bhatia
a28be95002 fix: workspace name and breadcrumb title , refactor: command palette (#290)
* refactor: command pallette

* fix: workspace name trim

* fix: breadcrumb title responsiveness added
2023-02-16 18:01:14 +05:30
dependabot[bot]
6ed5c05164 build(deps): bump django in /apiserver/requirements (#289)
Bumps [django](https://github.com/django/django) from 3.2.17 to 3.2.18.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.2.17...3.2.18)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-16 16:04:26 +05:30
Aaryan Khandelwal
667dafbda4 fix: consistent dropdowns, refactor: ui components (#286) 2023-02-16 12:03:52 +05:30
pablohashescobar
2d2751c58d fix: state ordering in group 2023-02-15 17:53:37 +05:30
Aaryan Khandelwal
ec37bb9d23 feat: bulk assign sub-issues (#284) 2023-02-15 14:45:28 +05:30
Anmol Singh Bhatia
f21135d955 feat: module sidebar date and status updated (#285) 2023-02-15 14:44:19 +05:30
Anmol Singh Bhatia
9b51a918cf fix: shortcut search (#283)
* fix: search case innsensitive

* style: email icon updated
2023-02-15 12:28:22 +05:30
Aaryan Khandelwal
ab0ce2f649 refactor: issue details page (#282) 2023-02-15 12:21:41 +05:30
pablohashescobar
9a5d7b1049 Merge branch 'develop' of github.com:makeplane/plane into feat/multiple_sub_issues 2023-02-14 20:08:39 +05:30
pablohashescobar
b8c1305883 fix: error validation for empty length 2023-02-14 20:08:04 +05:30
Aaryan Khandelwal
6f0539f01d feat: create label option in create issue modal (#281) 2023-02-14 20:05:32 +05:30
pablohashescobar
c9dce08842 feat: assign multiple sub issues 2023-02-14 15:33:53 +05:30
pablohashescobar
fcba332589 refactor: update django admin panel heading (#276) 2023-02-14 14:50:16 +05:30
Aaryan Khandelwal
e53ff4c02e feat: state description in settings (#275)
* chore: removed minor bugs

* feat: state description in settings

* feat: group by assignee
2023-02-14 14:46:48 +05:30
Anmol Singh Bhatia
9c8c7f1dda fix: mac text copy fix (#277) 2023-02-14 14:35:14 +05:30
vamsi
7950f191e7 dev: added migrations for new models schema changes 2023-02-14 01:19:59 +05:30
pablohashescobar
92d5749997 feat: state grouping and ordering list (#253)
* feat: state grouping and ordering list

* fix: state grouping in state list endpoint
2023-02-14 01:16:35 +05:30
pablohashescobar
af1d49bbf5 refactor: combine sign in and sign up endpoint to a single endpoint (#263) 2023-02-14 01:14:56 +05:30
pablohashescobar
0477db69a0 build: add channels requirement for the asgi configuration (#225) 2023-02-14 01:14:24 +05:30
pablohashescobar
7a3c00aba4 Merge pull request #226 from makeplane/chore/backend_dependencies
chore: update all backend dependencies to the latest version
2023-02-14 01:14:05 +05:30
pablohashescobar
97ffdc8124 feat: default state for project (#264) 2023-02-14 01:12:32 +05:30
Anmol Singh Bhatia
c6f0990605 fix: ui bug (#274)
* fix: shortcut search fix
shortcut modal ui fixes
shortcut search fix
email us label change
* fix: email us label updated
2023-02-13 20:19:46 +05:30
Aaryan Khandelwal
214e860e67 chore: removed minor bugs (#273) 2023-02-13 19:38:58 +05:30
Anmol Singh Bhatia
8fb34fe1e3 feat : sidebar progress improvement (#272)
* feat: progress chart render validation

* fix: sidebar stats tab

* feat: sidebar active tab context
2023-02-13 13:14:23 +05:30
Anmol Singh Bhatia
ebf294af55 feat : cycle sidebar revamp (#271)
* feat: range date picker added

* feat: cycle status ui improved
2023-02-13 10:33:02 +05:30
Aaryan Khandelwal
d0afa486c7 feat: drag and drop an issue to delete (#270)
* feat: drag and drop an issue to delete

* style: repositioned trash box
2023-02-13 10:32:02 +05:30
Aaryan Khandelwal
0a88b3ed84 fix: state reordering (#269)
* fix: state reordering

* refactor: remove unnecessary argument

* refactor: mutation after setting default
2023-02-13 10:30:44 +05:30
Anmol Singh Bhatia
bb4ffec7e8 feat: burndown chart (#268)
* chore: recharts dependencie added

* chore: tpye added for issue completed at

* feat: date range helper fn added

* feat: progress chart added

* feat: ideal task line added in progress chart

* feat: chart legends added
2023-02-10 18:40:02 +05:30
Aaryan Khandelwal
af22dc9c58 fix: remirror buttons (#267) 2023-02-10 18:39:23 +05:30
Aaryan Khandelwal
a403c0c346 feat: label grouping in dropdowns, default state in project settings (#266)
* feat: label grouping in dropdowns, default state in project settings

* feat: label disclosure default open

* refactor: label setting page

* chore: tooltip component updated

* chore: tooltip component updated

* feat/state_sequence_change
2023-02-10 18:02:18 +05:30
pablohashescobar
37c28b251d chore: update python runtime 2023-02-09 19:07:08 +05:30
Anmol Singh Bhatia
7c06be19fc feat: cycle status (#265)
* feat: cycle status and dates added in sidebar

* feat: update status added

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
2023-02-09 17:54:47 +05:30
pablohashescobar
9e9a6f4cce feat: record issue completed at date when the issues are moved to fompleted group (#262) 2023-02-09 10:41:43 +05:30
sriram veeraghanta
605ab26bb0 Merge pull request #261 from makeplane/develop
Merge pull request #260 from makeplane/stage-release
2023-02-09 00:21:51 +05:30
sriram veeraghanta
a94a3e2726 Merge pull request #260 from makeplane/stage-release
Branch Sync
2023-02-09 00:21:12 +05:30
sriram veeraghanta
394c73885d Merge pull request #259 from makeplane/stage-release-develop
release: Stage Release
2023-02-09 00:19:42 +05:30
sriramveeraghanta
7f406ceb39 fix: merge conflicts resolved 2023-02-09 00:12:59 +05:30
venplane
56030b1c2c fix: github auth login (#250)
* fix: added PROJECT_ISSUES_LIST on the imports (#221)

* fix: github signin by parsing email

* refactor: changed variable names

---------

Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: Vamsi Kurama <vamsi.kurama@gmail.com>
2023-02-09 00:01:45 +05:30
Aaryan Khandelwal
4ffa31fd02 fix: create issue modal bugs (#257) 2023-02-08 23:58:53 +05:30
Aaryan Khandelwal
8e3541b947 fix: mutation of states (#256)
* feat: label grouping, fix: new states response

* fix: mutation of states
2023-02-08 23:58:17 +05:30
sriram veeraghanta
bd399d6d1a sentry changes (#255) 2023-02-08 20:44:35 +05:30
Aaryan Khandelwal
166520dfda feat: label grouping, fix: new states response (#254) 2023-02-08 18:51:03 +05:30
Anmol Singh Bhatia
c978632938 feat: sidebar progress (#252)
* feat: cycle assignees and labels progress added

* fix: build fix

* feat: sidebar progress stats added and refactor

* refactor: progress stats and cycle sidebar

* feat: module sidebar progress added

* feat: sidebar progress no assignee added

* feat: states tab added

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
2023-02-08 18:50:08 +05:30
sriram veeraghanta
d3b73dc32f release: Stage Release (#251)
* feat: manual ordering for issues in kanban

* refactor: issues folder structure

* refactor: modules and states folder structure

* refactor: datepicker code

* fix: create issue modal bug

* feat: custom progress bar added

* refactor: created global component for kanban board

* refactor: update cycle and module issue create

* refactor: return modules created

* refactor: integrated global kanban view everywhere

* refactor: integrated global list view everywhere

* refactor: removed unnecessary api calls

* refactor: update nomenclature for consistency

* refactor: global select component for issue view

* refactor: track cycles and modules for issue

* fix: tracking new cycles and modules in activities

* feat: segregate api token workspace

* fix: workpsace id during token creation

* refactor: update model association to cascade on delete

* feat: sentry integrated (#235)

* feat: sentry integrated

* fix: removed unnecessary env variable

* fix: update remirror description to save empty string and empty paragraph (#237)

* Update README.md

* fix: description and comment_json default value to remove warnings

* feat: link option in remirror (#240)

* feat: link option in remirror

* fix: removed link import from remirror toolbar

* feat: module and cycle settings under project

* fix:  module issue assignment

* fix: module issue updation and activity logging

* fix: typo while creating module issues

* fix: string comparison for update operation

* fix: ui fixes (#246)

* style: shortcut command label bg color change

* sidebar shortcut ui fix

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>

* fix: update empty passwords to hashed string and add hashing for magic sign in

* refactor: remove print logs from back migrations

* build(deps): bump django in /apiserver/requirements

Bumps [django](https://github.com/django/django) from 3.2.16 to 3.2.17.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.2.16...3.2.17)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* feat: cycles and modules toggle in settings, refactor: folder structure (#247)

* feat: link option in remirror

* fix: removed link import from remirror toolbar

* refactor: constants folder

* refactor: layouts folder structure

* fix: issue view context

* feat: cycles and modules toggle in settings

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
Co-authored-by: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com>
Co-authored-by: pablohashescobar <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: sphynxux <122926002+sphynxux@users.noreply.github.com>
Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-08 10:15:18 +05:30
Aaryan Khandelwal
76cc634a46 feat: cycles and modules toggle in settings, refactor: folder structure (#247)
* feat: link option in remirror

* fix: removed link import from remirror toolbar

* refactor: constants folder

* refactor: layouts folder structure

* fix: issue view context

* feat: cycles and modules toggle in settings
2023-02-08 10:13:07 +05:30
pablohashescobar
4e27e93739 Merge pull request #243 from makeplane/fix/description_comment_migration_warnings
fix: description and comment_json default value to remove warnings
2023-02-08 01:47:46 +05:30
pablohashescobar
8e1ba90a34 Merge pull request #244 from makeplane/feat/module_cycle_settings
feat: module and cycle settings under project
2023-02-08 01:47:23 +05:30
pablohashescobar
a67690186a Merge pull request #245 from makeplane/fix/module_issue
fix:  module issue assignment
2023-02-08 01:46:41 +05:30
pablohashescobar
5785ab9e96 Merge pull request #248 from makeplane/fix/password_empty
fix: update empty passwords to hashed string and add hashing for magic sign in
2023-02-08 01:46:13 +05:30
pablohashescobar
e77defc622 chore: update django version to 3.2.17
chore: update django version to 3.2.17
2023-02-08 01:03:04 +05:30
dependabot[bot]
27849ee079 build(deps): bump django in /apiserver/requirements
Bumps [django](https://github.com/django/django) from 3.2.16 to 3.2.17.
- [Release notes](https://github.com/django/django/releases)
- [Commits](https://github.com/django/django/compare/3.2.16...3.2.17)

---
updated-dependencies:
- dependency-name: django
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-07 19:30:23 +00:00
pablohashescobar
d36e8af571 refactor: remove print logs from back migrations 2023-02-08 00:58:51 +05:30
pablohashescobar
343718cd2a fix: update empty passwords to hashed string and add hashing for magic sign in 2023-02-08 00:45:56 +05:30
Anmol Singh Bhatia
d5bf1f7a91 fix: ui fixes (#246)
* style: shortcut command label bg color change

* sidebar shortcut ui fix

---------

Co-authored-by: Anmol Singh Bhatia <anmolsinghbhatia1001@gmail.com>
2023-02-07 19:28:09 +05:30
pablohashescobar
1d44071a77 fix: string comparison for update operation 2023-02-07 14:26:28 +05:30
pablohashescobar
51b3815b72 fix: typo while creating module issues 2023-02-07 14:10:06 +05:30
pablohashescobar
8801a291af fix: module issue updation and activity logging 2023-02-07 14:05:09 +05:30
pablohashescobar
f09c9b67f6 fix: module issue assignment 2023-02-07 13:25:06 +05:30
pablohashescobar
8872f3f627 feat: module and cycle settings under project 2023-02-07 13:20:15 +05:30
Aaryan Khandelwal
859fef24f4 feat: link option in remirror (#240)
* feat: link option in remirror

* fix: removed link import from remirror toolbar
2023-02-07 11:20:41 +05:30
pablohashescobar
32d83ac2c9 fix: description and comment_json default value to remove warnings 2023-02-07 02:29:36 +05:30
sphynxux
f308fe2ce1 Merge pull request #242 from makeplane/sphynxux-patch-1
content: updated the discord link on Readme
2023-02-07 01:32:08 +05:30
sphynxux
240be69c7f Update README.md 2023-02-07 01:31:15 +05:30
pablohashescobar
2c4dbc84a2 Merge pull request #231 from makeplane/feat/issue_manual_ordering
feat: manual ordering for issues in kanban
2023-02-07 01:22:02 +05:30
pablohashescobar
c7ad9f3da1 Merge pull request #236 from makeplane/refactor/cycle_modules
refactor: update cycle and module create operation
2023-02-07 01:20:13 +05:30
pablohashescobar
b93abb4b37 fix: update remirror description to save empty string and empty paragraph (#237) 2023-02-07 01:19:42 +05:30
pablohashescobar
aaaf75c5da Merge pull request #239 from makeplane/refactor/color_nomenclature
refactor: update nomenclature for consistency
2023-02-07 01:15:14 +05:30
pablohashescobar
d256472776 Merge pull request #241 from makeplane/feat/api_token_workspace
feat: segregate api token workspace
2023-02-07 01:13:55 +05:30
Aaryan Khandelwal
21e042c852 feat: sentry integrated (#235)
* feat: sentry integrated

* fix: removed unnecessary env variable
2023-02-07 01:07:01 +05:30
pablohashescobar
cd41a05022 refactor: update model association to cascade on delete 2023-02-06 23:20:21 +05:30
pablohashescobar
f69b76c77d fix: workpsace id during token creation 2023-02-06 22:52:20 +05:30
pablohashescobar
0b7f0640c9 feat: segregate api token workspace 2023-02-06 20:22:08 +05:30
pablohashescobar
a576a2ab59 fix: tracking new cycles and modules in activities 2023-02-06 19:25:11 +05:30
sriram veeraghanta
e1b7e8d139 Merge pull request #233 from makeplane/feat/progress_bar
feat: custom progress bar added
2023-02-06 19:15:43 +05:30
sriram veeraghanta
c7e006d2c1 Merge pull request #232 from makeplane/refactor/folder_structure
refactor: folder structure
2023-02-06 19:14:59 +05:30
pablohashescobar
67a1052b7b refactor: track cycles and modules for issue 2023-02-06 15:31:05 +05:30
Aaryan Khandelwal
adbe16f8ae refactor: global select component for issue view 2023-02-06 15:18:57 +05:30
pablohashescobar
eec82eca2f refactor: update nomenclature for consistency 2023-02-06 13:56:02 +05:30
Aaryan Khandelwal
0e07c1e19f refactor: removed unnecessary api calls 2023-02-05 22:01:23 +05:30
Aaryan Khandelwal
d673aedf48 refactor: integrated global list view everywhere 2023-02-05 16:57:37 +05:30
Aaryan Khandelwal
85b7f39ed3 refactor: integrated global kanban view everywhere 2023-02-04 20:08:13 +05:30
pablohashescobar
7207d92d62 refactor: return modules created 2023-02-03 19:03:58 +05:30
pablohashescobar
a4f095fb59 refactor: update cycle and module issue create 2023-02-03 19:03:27 +05:30
Aaryan Khandelwal
58eda658c8 refactor: created global component for kanban board 2023-02-03 16:03:27 +05:30
Anmol Singh Bhatia
aa805b2b16 feat: custom progress bar added 2023-02-03 02:35:25 +05:30
Aaryan Khandelwal
4f85773a48 fix: create issue modal bug 2023-02-02 19:03:54 +05:30
Aaryan Khandelwal
563921d0cf refactor: datepicker code 2023-02-02 18:33:46 +05:30
Aaryan Khandelwal
b2eab805e9 refactor: modules and states folder structure 2023-02-02 18:04:13 +05:30
Aaryan Khandelwal
8b1bf53831 refactor: issues folder structure 2023-02-02 15:00:35 +05:30
pablohashescobar
c4fff45429 feat: manual ordering for issues in kanban 2023-02-02 13:29:17 +05:30
pablohashescobar
c60e771e9c chore: update all backend dependencies to the latest version 2023-02-01 15:08:52 +05:30
1628 changed files with 136568 additions and 44227 deletions

35
.env.example Normal file
View File

@@ -0,0 +1,35 @@
# Database Settings
PGUSER="plane"
PGPASSWORD="plane"
PGHOST="plane-db"
PGDATABASE="plane"
DATABASE_URL=postgresql://${PGUSER}:${PGPASSWORD}@${PGHOST}/${PGDATABASE}
# Redis Settings
REDIS_HOST="plane-redis"
REDIS_PORT="6379"
REDIS_URL="redis://${REDIS_HOST}:6379/"
# AWS Settings
AWS_REGION=""
AWS_ACCESS_KEY_ID="access-key"
AWS_SECRET_ACCESS_KEY="secret-key"
AWS_S3_ENDPOINT_URL="http://plane-minio:9000"
# Changing this requires change in the nginx.conf for uploads if using minio setup
AWS_S3_BUCKET_NAME="uploads"
# Maximum file upload limit
FILE_SIZE_LIMIT=5242880
# GPT settings
OPENAI_API_BASE="https://api.openai.com/v1" # change if using a custom endpoint
OPENAI_API_KEY="sk-" # add your openai key here
GPT_ENGINE="gpt-3.5-turbo" # use "gpt-4" if you have access
# Settings related to Docker
DOCKERIZED=1
# set to 1 If using the pre-configured minio setup
USE_MINIO=1
# Nginx Configuration
NGINX_PORT=80

View File

@@ -1,10 +1,10 @@
module.exports = {
root: true,
// This tells ESLint to load the config from the package `config`
// extends: ["custom"],
// This tells ESLint to load the config from the package `eslint-config-custom`
extends: ["custom"],
settings: {
next: {
rootDir: ["apps/*/"],
rootDir: ["web/", "space/"],
},
},
};

View File

@@ -0,0 +1,65 @@
name: Bug report
description: Create a bug report to help us improve Plane
title: "[bug]: "
labels: [bug, need testing]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out this bug report.
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Current behavior
description: A concise description of what you're experiencing and what you expect
placeholder: |
When I do <X>, <Y> happens and I see the error message attached below:
```...```
What I expect is <Z>
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Add steps to reproduce this behaviour, include console or network logs and screenshots
placeholder: |
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
validations:
required: true
- type: dropdown
id: env
attributes:
label: Environment
options:
- Production
- Deploy preview
validations:
required: true
type: dropdown
id: browser
attributes:
label: Browser
options:
- Google Chrome
- Mozilla Firefox
- Safari
- Other
- type: dropdown
id: version
attributes:
label: Version
options:
- Cloud
- Self-hosted
- Local
validations:
required: true

View File

@@ -0,0 +1,28 @@
name: Feature request
description: Suggest a feature to improve Plane
title: "[feature]: "
labels: [feature]
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to request a feature for Plane
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue related to this feature request already exists
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Summary
description: One paragraph description of the feature
validations:
required: true
- type: textarea
attributes:
label: Why should this be worked on?
description: A concise description of the problems or use cases for this feature request
validations:
required: true

6
.github/ISSUE_TEMPLATE/config.yaml vendored Normal file
View File

@@ -0,0 +1,6 @@
contact_links:
- name: Help and support
about: Reach out to us on our Discord server or GitHub discussions.
- name: Dedicated support
url: mailto:support@plane.so
about: Write to us if you'd like dedicated support using Plane

View File

@@ -0,0 +1,50 @@
name: Build Pull Request Contents
on:
pull_request:
types: ["opened", "synchronize"]
jobs:
build-pull-request-contents:
name: Build Pull Request Contents
runs-on: ubuntu-20.04
permissions:
pull-requests: read
steps:
- name: Checkout Repository to Actions
uses: actions/checkout@v3.3.0
- name: Setup Node.js 18.x
uses: actions/setup-node@v2
with:
node-version: 18.x
cache: 'yarn'
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v38
with:
files_yaml: |
apiserver:
- apiserver/**
web:
- web/**
deploy:
- space/**
- name: Build Plane's Main App
if: steps.changed-files.outputs.web_any_changed == 'true'
run: |
cd web
yarn
yarn build
- name: Build Plane's Deploy App
if: steps.changed-files.outputs.deploy_any_changed == 'true'
run: |
cd space
yarn
yarn build

View File

@@ -0,0 +1,107 @@
name: Update Docker Images for Plane on Release
on:
release:
types: [released, prereleased]
jobs:
build_push_backend:
name: Build and Push Api Server Docker Image
runs-on: ubuntu-20.04
steps:
- name: Check out the repo
uses: actions/checkout@v3.3.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2.5.0
- name: Login to Docker Hub
uses: docker/login-action@v2.1.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker (Docker Hub) from Github Release
id: metaFrontend
uses: docker/metadata-action@v4.3.0
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend
tags: |
type=ref,event=tag
- name: Extract metadata (tags, labels) for Docker (Docker Hub) from Github Release
id: metaBackend
uses: docker/metadata-action@v4.3.0
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/plane-backend
tags: |
type=ref,event=tag
- name: Extract metadata (tags, labels) for Docker (Docker Hub) from Github Release
id: metaDeploy
uses: docker/metadata-action@v4.3.0
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/plane-deploy
tags: |
type=ref,event=tag
- name: Extract metadata (tags, labels) for Docker (Docker Hub) from Github Release
id: metaProxy
uses: docker/metadata-action@v4.3.0
with:
images: ${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy
tags: |
type=ref,event=tag
- name: Build and Push Frontend to Docker Container Registry
uses: docker/build-push-action@v4.0.0
with:
context: .
file: ./web/Dockerfile.web
platforms: linux/amd64
tags: ${{ steps.metaFrontend.outputs.tags }}
push: true
env:
DOCKER_BUILDKIT: 1
DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKET_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and Push Backend to Docker Hub
uses: docker/build-push-action@v4.0.0
with:
context: ./apiserver
file: ./apiserver/Dockerfile.api
platforms: linux/amd64
push: true
tags: ${{ steps.metaBackend.outputs.tags }}
env:
DOCKER_BUILDKIT: 1
DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKET_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and Push Plane-Deploy to Docker Hub
uses: docker/build-push-action@v4.0.0
with:
context: .
file: ./space/Dockerfile.space
platforms: linux/amd64
push: true
tags: ${{ steps.metaDeploy.outputs.tags }}
env:
DOCKER_BUILDKIT: 1
DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKET_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and Push Plane-Proxy to Docker Hub
uses: docker/build-push-action@v4.0.0
with:
context: ./nginx
file: ./nginx/Dockerfile
platforms: linux/amd64
push: true
tags: ${{ steps.metaProxy.outputs.tags }}
env:
DOCKER_BUILDKIT: 1
DOCKER_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKET_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }}

11
.gitignore vendored
View File

@@ -43,6 +43,7 @@ yarn-error.log*
## Django ##
venv
.venv
*.pyc
staticfiles
mediafiles
@@ -62,3 +63,13 @@ yarn-error.log
*.sln
package-lock.json
.vscode
# Sentry
.sentryclirc
# lock files
package-lock.json
pnpm-lock.yaml
pnpm-workspace.yaml
.npmrc

View File

@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
- Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
- The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
@@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
@@ -125,4 +125,4 @@ enforcement ladder](https://github.com/mozilla/diversity).
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
https://www.contributor-covenant.org/translations.

View File

@@ -8,8 +8,8 @@ Before submitting a new issue, please search the [issues](https://github.com/mak
While we want to fix all the [issues](https://github.com/makeplane/plane/issues), before fixing a bug we need to be able to reproduce and confirm it. Please provide us with a minimal reproduction scenario using a repository or [Gist](https://gist.github.com/). Having a live, reproducible scenario gives us the information without asking questions back & forth with additional questions like:
- 3rd-party libraries being used and their versions
- a use-case that fails
- 3rd-party libraries being used and their versions
- a use-case that fails
Without said minimal reproduction, we won't be able to investigate all [issues](https://github.com/makeplane/plane/issues), and the issue might not be resolved.
@@ -19,11 +19,10 @@ You can open a new issue with this [issue form](https://github.com/makeplane/pla
### Requirements
- Node.js version v16.18.0
- Python version 3.8+
- Postgres version v14
- Redis version v6.2.7
- pnpm version 7.22.0
- Node.js version v16.18.0
- Python version 3.8+
- Postgres version v14
- Redis version v6.2.7
### Setup the project
@@ -31,6 +30,48 @@ The project is a monorepo, with backend api and frontend in a single repo.
The backend is a django project which is kept inside apiserver
1. Clone the repo
```bash
git clone https://github.com/makeplane/plane
cd plane
chmod +x setup.sh
```
2. Run setup.sh
```bash
./setup.sh
```
3. Define `NEXT_PUBLIC_API_BASE_URL=http://localhost` in **web/.env** and **space/.env** file
```bash
echo "\nNEXT_PUBLIC_API_BASE_URL=http://localhost\n" >> ./web/.env
```
```bash
echo "\nNEXT_PUBLIC_API_BASE_URL=http://localhost\n" >> ./space/.env
```
4. Run Docker compose up
```bash
docker compose up -d
```
5. Install dependencies
```bash
yarn install
```
6. Run the web app in development mode
```bash
yarn dev
```
## Missing a Feature?
If a feature is missing, you can directly _request_ a new one [here](https://github.com/makeplane/plane/issues/new?assignees=&labels=feature&template=feature_request.yml&title=%F0%9F%9A%80+Feature%3A+). You also can do the same by choosing "🚀 Feature" when raising a [New Issue](https://github.com/makeplane/plane/issues/new/choose) on our GitHub Repository.
@@ -40,8 +81,8 @@ If you would like to _implement_ it, an issue with your proposal must be submitt
To ensure consistency throughout the source code, please keep these rules in mind as you are working:
- All features or bug fixes must be tested by one or more specs (unit-tests).
- We use [Eslint default rule guide](https://eslint.org/docs/rules/), with minor changes. An automated formatter is available using prettier.
- All features or bug fixes must be tested by one or more specs (unit-tests).
- We use [Eslint default rule guide](https://eslint.org/docs/rules/), with minor changes. An automated formatter is available using prettier.
## Need help? Questions and suggestions
@@ -49,11 +90,11 @@ Questions, suggestions, and thoughts are most welcome. We can also be reached in
## Ways to contribute
- Try Plane Cloud and the self hosting platform and give feedback
- Add new integrations
- Help with open [issues](https://github.com/makeplane/plane/issues) or [create your own](https://github.com/makeplane/plane/issues/new/choose)
- Share your thoughts and suggestions with us
- Help create tutorials and blog posts
- Request a feature by submitting a proposal
- Report a bug
- **Improve documentation** - fix incomplete or missing [docs](https://docs.plane.so/), bad wording, examples or explanations.
- Try Plane Cloud and the self hosting platform and give feedback
- Add new integrations
- Help with open [issues](https://github.com/makeplane/plane/issues) or [create your own](https://github.com/makeplane/plane/issues/new/choose)
- Share your thoughts and suggestions with us
- Help create tutorials and blog posts
- Request a feature by submitting a proposal
- Report a bug
- **Improve documentation** - fix incomplete or missing [docs](https://docs.plane.so/), bad wording, examples or explanations.

132
Dockerfile Normal file
View File

@@ -0,0 +1,132 @@
FROM node:18-alpine AS builder
RUN apk add --no-cache libc6-compat
# Set working directory
WORKDIR /app
ENV NEXT_PUBLIC_API_BASE_URL=http://NEXT_PUBLIC_API_BASE_URL_PLACEHOLDER
RUN yarn global add turbo
RUN apk add tree
COPY . .
RUN turbo prune --scope=app --scope=plane-deploy --docker
CMD tree -I node_modules/
# Add lockfile and package.json's of isolated subworkspace
FROM node:18-alpine AS installer
RUN apk add --no-cache libc6-compat
WORKDIR /app
ARG NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
# First install the dependencies (as they change less often)
COPY .gitignore .gitignore
COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/yarn.lock ./yarn.lock
RUN yarn install
# # Build the project
COPY --from=builder /app/out/full/ .
COPY turbo.json turbo.json
COPY replace-env-vars.sh /usr/local/bin/
USER root
RUN chmod +x /usr/local/bin/replace-env-vars.sh
RUN yarn turbo run build
ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL \
BUILT_NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL
RUN /usr/local/bin/replace-env-vars.sh http://NEXT_PUBLIC_WEBAPP_URL_PLACEHOLDER ${NEXT_PUBLIC_API_BASE_URL}
FROM python:3.11.1-alpine3.17 AS backend
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
ENV DJANGO_SETTINGS_MODULE plane.settings.production
ENV DOCKERIZED 1
WORKDIR /code
RUN apk --no-cache add \
"libpq~=15" \
"libxslt~=1.1" \
"nodejs-current~=19" \
"xmlsec~=1.2" \
"nginx" \
"nodejs" \
"npm" \
"supervisor"
COPY apiserver/requirements.txt ./
COPY apiserver/requirements ./requirements
RUN apk add --no-cache libffi-dev
RUN apk add --no-cache --virtual .build-deps \
"bash~=5.2" \
"g++~=12.2" \
"gcc~=12.2" \
"cargo~=1.64" \
"git~=2" \
"make~=4.3" \
"postgresql13-dev~=13" \
"libc-dev" \
"linux-headers" \
&& \
pip install -r requirements.txt --compile --no-cache-dir \
&& \
apk del .build-deps
# Add in Django deps and generate Django's static files
COPY apiserver/manage.py manage.py
COPY apiserver/plane plane/
COPY apiserver/templates templates/
COPY apiserver/gunicorn.config.py ./
RUN apk --no-cache add "bash~=5.2"
COPY apiserver/bin ./bin/
RUN chmod +x ./bin/takeoff ./bin/worker
RUN chmod -R 777 /code
# Expose container port and run entry point script
WORKDIR /app
# Don't run production as root
RUN addgroup --system --gid 1001 plane
RUN adduser --system --uid 1001 captain
COPY --from=installer /app/apps/app/next.config.js .
COPY --from=installer /app/apps/app/package.json .
COPY --from=installer /app/apps/space/next.config.js .
COPY --from=installer /app/apps/space/package.json .
COPY --from=installer --chown=captain:plane /app/apps/app/.next/standalone ./
COPY --from=installer --chown=captain:plane /app/apps/app/.next/static ./apps/app/.next/static
COPY --from=installer --chown=captain:plane /app/apps/space/.next/standalone ./
COPY --from=installer --chown=captain:plane /app/apps/space/.next ./apps/space/.next
ENV NEXT_TELEMETRY_DISABLED 1
# RUN rm /etc/nginx/conf.d/default.conf
#######################################################################
COPY nginx/nginx-single-docker-image.conf /etc/nginx/http.d/default.conf
#######################################################################
COPY nginx/supervisor.conf /code/supervisor.conf
ARG NEXT_PUBLIC_API_BASE_URL=http://localhost:8000
ENV NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL \
BUILT_NEXT_PUBLIC_API_BASE_URL=$NEXT_PUBLIC_API_BASE_URL
USER root
COPY replace-env-vars.sh /usr/local/bin/
COPY start.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/replace-env-vars.sh
RUN chmod +x /usr/local/bin/start.sh
EXPOSE 80
CMD ["supervisord","-c","/code/supervisor.conf"]

View File

@@ -1,201 +1,661 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
1. Definitions.
Preamble
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
The precise terms and conditions for copying, distribution and
modification follow.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
TERMS AND CONDITIONS
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
0. Definitions.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
"This License" refers to version 3 of the GNU Affero General Public License.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
A "covered work" means either the unmodified Program or a work based
on the Program.
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
1. Source Code.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
END OF TERMS AND CONDITIONS
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
APPENDIX: How to apply the Apache License to your work.
The Corresponding Source for a work in source code form is that
same work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
2. Basic Permissions.
Copyright 2022 Plane Software Labs Private Limited
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
http://www.apache.org/licenses/LICENSE-2.0
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

154
README.md
View File

@@ -2,50 +2,156 @@
<p align="center">
<a href="https://plane.so">
<img src="https://res.cloudinary.com/dgxawjvpo/image/upload/v1673379660/Plane/plane-logo_0m83xue7R_f0v9r9.png" alt="Plane Logo" width="350">
<img src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_logo_.webp" alt="Plane Logo" width="70">
</a>
</p>
<h3 align="center"><b>Plane</b></h3>
<p align="center"><b>Open-source, self-hosted project planning tool</b></p>
<p align="center">
<a href="https://discord.com/invite/29tPNhaV">
<img alt="Discord" src="https://img.shields.io/discord/1031547764020084846?color=5865F2&label=Discord&style=for-the-badge" />
<a href="https://discord.com/invite/A92xrEGCge">
<img alt="Discord online members" src="https://img.shields.io/discord/1031547764020084846?color=5865F2&label=Discord&style=for-the-badge" />
</a>
<img alt="Discord" src="https://img.shields.io/github/commit-activity/m/makeplane/plane?style=for-the-badge" />
<img alt="Commit activity per month" src="https://img.shields.io/github/commit-activity/m/makeplane/plane?style=for-the-badge" />
</p>
<br />
Plane is an open-source project planning tool that is designed to help individuals and teams streamline their issues, sprints, and product roadmaps. It is easy to use and can be accessed by anyone, making it an ideal choice for a wide range of projects and organizations.
<br /> <br />
<p>
<a href="https://app.plane.so/#gh-light-mode-only" target="_blank">
<img
src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_screen.webp"
alt="Plane Screens"
width="100%"
/>
</a>
<a href="https://app.plane.so/#gh-dark-mode-only" target="_blank">
<img
src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_screens_dark_mode.webp"
alt="Plane Screens"
width="100%"
/>
</a>
</p>
> Plane is still in its early days, not everything will be perfect yet, and hiccups may happen. Please let us know of any suggestions, ideas, or bugs that you encounter on our [Discord](https://discord.com/invite/29tPNhaV) or GitHub issues, and we will use your feedback to improve on our upcoming releases.
Meet [Plane](https://plane.so). An open-source software development tool to manage issues, sprints, and product roadmaps with peace of mind 🧘‍♀️.
## Getting Started
> Plane is still in its early days, not everything will be perfect yet, and hiccups may happen. Please let us know of any suggestions, ideas, or bugs that you encounter on our [Discord](https://discord.com/invite/A92xrEGCge) or GitHub issues, and we will use your feedback to improve on our upcoming releases.
Visit https://app.plane.so to get started with Plane.
The easiest way to get started with Plane is by creating a [Plane Cloud](https://app.plane.so) account. Plane Cloud offers a hosted solution for Plane. If you prefer to self-host Plane, please refer to our [deployment documentation](https://docs.plane.so/self-hosting).
## Documentation
## ⚡️ Quick start with Docker Compose
### Docker Compose Setup
- Clone the repository
```bash
git clone https://github.com/makeplane/plane
cd plane
chmod +x setup.sh
```
- Run setup.sh
```bash
./setup.sh http://localhost
```
> If running in a cloud env replace localhost with public facing IP address of the VM
- Run Docker compose up
```bash
docker compose up -d
```
<strong>You can use the default email and password for your first login `captain@plane.so` and `password123`.</strong>
## 🚀 Features
- **Issue Planning and Tracking**: Quickly create issues and add details using a powerful rich text editor that supports file uploads. Add sub-properties and references to issues for better organization and tracking.
- **Issue Attachments**: Collaborate effectively by attaching files to issues, making it easy for your team to find and share important project-related documents.
- **Layouts**: Customize your project view with your preferred layout - choose from List, Kanban, or Calendar to visualize your project in a way that makes sense to you.
- **Cycles**: Plan sprints with Cycles to keep your team on track and productive. Gain insights into your project's progress with burn-down charts and other useful features.
- **Modules**: Break down your large projects into smaller, more manageable modules. Assign modules between teams to easily track and plan your project's progress.
- **Views**: Create custom filters to display only the issues that matter to you. Save and share your filters in just a few clicks.
- **Pages**: Plane pages function as an AI-powered notepad, allowing you to easily document issues, cycle plans, and module details, and then synchronize them with your issues.
- **Command K**: Enjoy a better user experience with the new Command + K menu. Easily manage and navigate through your projects from one convenient location.
- **GitHub Sync**: Streamline your planning process by syncing your GitHub issues with Plane. Keep all your issues in one place for better tracking and collaboration.
## 📸 Screenshots
<p>
<a href="https://plane.so" target="_blank">
<img
src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_views_dark_mode.webp"
alt="Plane Views"
width="100%"
/>
</a>
</p>
<p>
<a href="https://plane.so" target="_blank">
<img
src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_issue_detail_dark_mode.webp"
alt="Plane Issue Details"
width="100%"
/>
</a>
</p>
<p>
<a href="https://plane.so" target="_blank">
<img
src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_cycles_modules_dark_mode.webp"
alt="Plane Cycles and Modules"
width="100%"
/>
</a>
</p>
<p>
<a href="https://plane.so" target="_blank">
<img
src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_analytics_dark_mode.webp"
alt="Plane Analytics"
width="100%"
/>
</a>
</p>
<p>
<a href="https://plane.so" target="_blank">
<img
src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_pages_dark_mode.webp"
alt="Plane Pages"
width="100%"
/>
</a>
</p>
</p>
<p>
<a href="https://plane.so" target="_blank">
<img
src="https://plane-marketing.s3.ap-south-1.amazonaws.com/plane-readme/plane_commad_k_dark_mode.webp"
alt="Plane Command Menu"
width="100%"
/>
</a>
</p>
</p>
## 📚Documentation
For full documentation, visit [docs.plane.so](https://docs.plane.so/)
To see how to Contribute, visit [here](https://github.com/makeplane/plane/blob/master/CONTRIBUTING.md).
## Status
- [x] Early Community Previews: We are open-sourcing and sharing the development version of Plane
- [ ] Alpha: We are testing Plane with a closed set of customers
- [ ] Public Alpha: Anyone can sign up over at [app.plane.so](https://app.plane.so). But go easy on us, there are a few hiccups
- [ ] Public Beta: Stable enough for most non-enterprise use-cases
- [ ] Public: Production-ready
## Community
## ❤️ Community
The Plane community can be found on GitHub Discussions, where you can ask questions, voice ideas, and share your projects.
To chat with other community members you can join the [Plane Discord](https://discord.com/invite/q9HKAdau).
To chat with other community members you can join the [Plane Discord](https://discord.com/invite/A92xrEGCge).
Our [Code of Conduct](https://github.com/makeplane/plane/blob/master/CODE_OF_CONDUCT.md) applies to all Plane community channels.
## Security
## ⛓️ Security
If you believe you have found a security vulnerability in Plane, we encourage you to responsibly disclose this and not open a public issue. We will investigate all legitimate reports. Email security@plane.so to disclose any security vulnerabilities.
If you believe you have found a security vulnerability in Plane, we encourage you to responsibly disclose this and not open a public issue. We will investigate all legitimate reports. Email engineering@plane.so to disclose any security vulnerabilities.

View File

@@ -1,18 +1,61 @@
# Backend
SECRET_KEY="<-- django secret -->"
EMAIL_HOST="<-- email smtp -->"
EMAIL_HOST_USER="<-- email host user -->"
EMAIL_HOST_PASSWORD="<-- email host password -->"
# Debug value for api server use it as 0 for production use
DEBUG=0
DJANGO_SETTINGS_MODULE="plane.settings.selfhosted"
AWS_REGION="<-- aws region -->"
AWS_ACCESS_KEY_ID="<-- aws access key -->"
AWS_SECRET_ACCESS_KEY="<-- aws secret acess key -->"
AWS_S3_BUCKET_NAME="<-- aws s3 bucket name -->"
# Error logs
SENTRY_DSN=""
SENTRY_DSN="<-- sentry dsn -->"
WEB_URL="<-- frontend web url -->"
# Database Settings
PGUSER="plane"
PGPASSWORD="plane"
PGHOST="plane-db"
PGDATABASE="plane"
DATABASE_URL=postgresql://${PGUSER}:${PGPASSWORD}@${PGHOST}/${PGDATABASE}
GITHUB_CLIENT_SECRET="<-- github secret -->"
# Redis Settings
REDIS_HOST="plane-redis"
REDIS_PORT="6379"
REDIS_URL="redis://${REDIS_HOST}:6379/"
DISABLE_COLLECTSTATIC=1
DOCKERIZED=0 //True if running docker compose else 0
# Email Settings
EMAIL_HOST=""
EMAIL_HOST_USER=""
EMAIL_HOST_PASSWORD=""
EMAIL_PORT=587
EMAIL_FROM="Team Plane <team@mailer.plane.so>"
EMAIL_USE_TLS="1"
EMAIL_USE_SSL="0"
# AWS Settings
AWS_REGION=""
AWS_ACCESS_KEY_ID="access-key"
AWS_SECRET_ACCESS_KEY="secret-key"
AWS_S3_ENDPOINT_URL="http://plane-minio:9000"
# Changing this requires change in the nginx.conf for uploads if using minio setup
AWS_S3_BUCKET_NAME="uploads"
# Maximum file upload limit
FILE_SIZE_LIMIT=5242880
# GPT settings
OPENAI_API_BASE="https://api.openai.com/v1" # change if using a custom endpoint
OPENAI_API_KEY="sk-" # add your openai key here
GPT_ENGINE="gpt-3.5-turbo" # use "gpt-4" if you have access
# Github
GITHUB_CLIENT_SECRET="" # For fetching release notes
# Settings related to Docker
DOCKERIZED=1
# set to 1 If using the pre-configured minio setup
USE_MINIO=1
# Nginx Configuration
NGINX_PORT=80
# Default Creds
DEFAULT_EMAIL="captain@plane.so"
DEFAULT_PASSWORD="password123"
# SignUps
ENABLE_SIGNUP="1"

View File

@@ -1,4 +1,4 @@
FROM python:3.8.14-alpine3.16 AS backend
FROM python:3.11.1-alpine3.17 AS backend
# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
@@ -7,20 +7,20 @@ ENV PIP_DISABLE_PIP_VERSION_CHECK=1
WORKDIR /code
RUN apk --update --no-cache add \
"libpq~=14" \
RUN apk --no-cache add \
"libpq~=15" \
"libxslt~=1.1" \
"nodejs-current~=18" \
"nodejs-current~=19" \
"xmlsec~=1.2"
COPY requirements.txt ./
COPY requirements ./requirements
RUN apk add libffi-dev
RUN apk --update --no-cache --virtual .build-deps add \
"bash~=5.1" \
"g++~=11.2" \
"gcc~=11.2" \
"cargo~=1.60" \
RUN apk add --no-cache libffi-dev
RUN apk add --no-cache --virtual .build-deps \
"bash~=5.2" \
"g++~=12.2" \
"gcc~=12.2" \
"cargo~=1.64" \
"git~=2" \
"make~=4.3" \
"postgresql13-dev~=13" \
@@ -46,15 +46,16 @@ COPY templates templates/
COPY gunicorn.config.py ./
USER root
RUN apk --update --no-cache add "bash~=5.1"
RUN apk --no-cache add "bash~=5.2"
COPY ./bin ./bin/
RUN chmod +x ./bin/takeoff ./bin/worker
RUN chmod +x ./bin/takeoff ./bin/worker ./bin/beat
RUN chmod -R 777 /code
USER captain
# Expose container port and run entry point script
EXPOSE 8000
CMD [ "./bin/takeoff" ]
# CMD [ "./bin/takeoff" ]

View File

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

View File

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

5
apiserver/bin/beat Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
set -e
python manage.py wait_for_db
celery -A plane beat -l info

View File

@@ -2,4 +2,8 @@
set -e
python manage.py wait_for_db
python manage.py migrate
exec gunicorn -w 8 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --config gunicorn.config.py --max-requests 1200 --max-requests-jitter 1000 --access-logfile -
# Create a Default User
python bin/user_script.py
exec gunicorn -w 8 -k uvicorn.workers.UvicornWorker plane.asgi:application --bind 0.0.0.0:8000 --max-requests 1200 --max-requests-jitter 1000 --access-logfile -

View File

@@ -0,0 +1,28 @@
import os, sys, random, string
import uuid
sys.path.append("/code")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plane.settings.production")
import django
django.setup()
from plane.db.models import User
def populate():
default_email = os.environ.get("DEFAULT_EMAIL", "captain@plane.so")
default_password = os.environ.get("DEFAULT_PASSWORD", "password123")
if not User.objects.filter(email=default_email).exists():
user = User.objects.create(email=default_email, username=uuid.uuid4().hex)
user.set_password(default_password)
user.save()
print(f"User created with an email: {default_email}")
else:
print(f"User already exists with the default email: {default_email}")
if __name__ == "__main__":
populate()

View File

@@ -2,5 +2,4 @@
set -e
python manage.py wait_for_db
python manage.py migrate
python manage.py rqworker
celery -A plane worker -l info

View File

@@ -0,0 +1,3 @@
from .celery import app as celery_app
__all__ = ('celery_app',)

View File

@@ -1,2 +1,2 @@
from .workspace import WorkSpaceBasePermission, WorkSpaceAdminPermission
from .project import ProjectBasePermission, ProjectEntityPermission, ProjectMemberPermission
from .workspace import WorkSpaceBasePermission, WorkSpaceAdminPermission, WorkspaceEntityPermission, WorkspaceViewerPermission
from .project import ProjectBasePermission, ProjectEntityPermission, ProjectMemberPermission, ProjectLitePermission

View File

@@ -89,3 +89,16 @@ class ProjectEntityPermission(BasePermission):
role__in=[Admin, Member],
project_id=view.project_id,
).exists()
class ProjectLitePermission(BasePermission):
def has_permission(self, request, view):
if request.user.is_anonymous:
return False
return ProjectMember.objects.filter(
workspace__slug=view.workspace_slug,
member=request.user,
project_id=view.project_id,
).exists()

View File

@@ -5,7 +5,6 @@ from rest_framework.permissions import BasePermission, SAFE_METHODS
from plane.db.models import WorkspaceMember
# Permission Mappings
Owner = 20
Admin = 15
@@ -44,7 +43,6 @@ class WorkSpaceBasePermission(BasePermission):
class WorkSpaceAdminPermission(BasePermission):
def has_permission(self, request, view):
if request.user.is_anonymous:
return False
@@ -53,3 +51,32 @@ class WorkSpaceAdminPermission(BasePermission):
workspace__slug=view.workspace_slug,
role__in=[Owner, Admin],
).exists()
class WorkspaceEntityPermission(BasePermission):
def has_permission(self, request, view):
if request.user.is_anonymous:
return False
## Safe Methods -> Handle the filtering logic in queryset
if request.method in SAFE_METHODS:
return WorkspaceMember.objects.filter(
workspace__slug=view.workspace_slug,
member=request.user,
).exists()
return WorkspaceMember.objects.filter(
member=request.user,
workspace__slug=view.workspace_slug,
role__in=[Owner, Admin],
).exists()
class WorkspaceViewerPermission(BasePermission):
def has_permission(self, request, view):
if request.user.is_anonymous:
return False
return WorkspaceMember.objects.filter(
member=request.user, workspace__slug=view.workspace_slug, role__gte=10
).exists()

View File

@@ -1,15 +1,13 @@
from .base import BaseSerializer
from .people import (
ChangePasswordSerializer,
ResetPasswordSerializer,
TokenSerializer,
)
from .user import UserSerializer, UserLiteSerializer
from .user import UserSerializer, UserLiteSerializer, ChangePasswordSerializer, ResetPasswordSerializer, UserAdminLiteSerializer
from .workspace import (
WorkSpaceSerializer,
WorkSpaceMemberSerializer,
TeamSerializer,
WorkSpaceMemberInviteSerializer,
WorkspaceLiteSerializer,
WorkspaceThemeSerializer,
WorkspaceMemberAdminSerializer,
)
from .project import (
ProjectSerializer,
@@ -17,27 +15,73 @@ from .project import (
ProjectMemberSerializer,
ProjectMemberInviteSerializer,
ProjectIdentifierSerializer,
ProjectFavoriteSerializer,
ProjectLiteSerializer,
ProjectMemberLiteSerializer,
ProjectDeployBoardSerializer,
ProjectMemberAdminSerializer,
ProjectPublicMemberSerializer
)
from .state import StateSerializer
from .shortcut import ShortCutSerializer
from .view import ViewSerializer
from .cycle import CycleSerializer, CycleIssueSerializer
from .state import StateSerializer, StateLiteSerializer
from .view import GlobalViewSerializer, IssueViewSerializer, IssueViewFavoriteSerializer
from .cycle import CycleSerializer, CycleIssueSerializer, CycleFavoriteSerializer, CycleWriteSerializer
from .asset import FileAssetSerializer
from .issue import (
IssueCreateSerializer,
IssueActivitySerializer,
IssueCommentSerializer,
TimeLineIssueSerializer,
IssuePropertySerializer,
BlockerIssueSerializer,
BlockedIssueSerializer,
IssueAssigneeSerializer,
LabelSerializer,
IssueSerializer,
IssueFlatSerializer,
IssueStateSerializer,
IssueLinkSerializer,
IssueLiteSerializer,
IssueAttachmentSerializer,
IssueSubscriberSerializer,
IssueReactionSerializer,
CommentReactionSerializer,
IssueVoteSerializer,
IssueRelationSerializer,
RelatedIssueSerializer,
IssuePublicSerializer,
)
from .module import ModuleWriteSerializer, ModuleSerializer, ModuleIssueSerializer
from .module import (
ModuleWriteSerializer,
ModuleSerializer,
ModuleIssueSerializer,
ModuleLinkSerializer,
ModuleFavoriteSerializer,
)
from .api_token import APITokenSerializer
from .api_token import APITokenSerializer
from .integration import (
IntegrationSerializer,
WorkspaceIntegrationSerializer,
GithubIssueSyncSerializer,
GithubRepositorySerializer,
GithubRepositorySyncSerializer,
GithubCommentSyncSerializer,
SlackProjectSyncSerializer,
)
from .importer import ImporterSerializer
from .page import PageSerializer, PageBlockSerializer, PageFavoriteSerializer
from .estimate import (
EstimateSerializer,
EstimatePointSerializer,
EstimateReadSerializer,
)
from .inbox import InboxSerializer, InboxIssueSerializer, IssueStateInboxSerializer
from .analytic import AnalyticViewSerializer
from .notification import NotificationSerializer
from .exporter import ExporterHistorySerializer

View File

@@ -0,0 +1,30 @@
from .base import BaseSerializer
from plane.db.models import AnalyticView
from plane.utils.issue_filters import issue_filters
class AnalyticViewSerializer(BaseSerializer):
class Meta:
model = AnalyticView
fields = "__all__"
read_only_fields = [
"workspace",
"query",
]
def create(self, validated_data):
query_params = validated_data.get("query_dict", {})
if bool(query_params):
validated_data["query"] = issue_filters(query_params, "POST")
else:
validated_data["query"] = dict()
return AnalyticView.objects.create(**validated_data)
def update(self, instance, validated_data):
query_params = validated_data.get("query_data", {})
if bool(query_params):
validated_data["query"] = issue_filters(query_params, "POST")
else:
validated_data["query"] = dict()
validated_data["query"] = issue_filters(query_params, "PATCH")
return super().update(instance, validated_data)

View File

@@ -5,4 +5,10 @@ from plane.db.models import APIToken
class APITokenSerializer(BaseSerializer):
class Meta:
model = APIToken
fields = "__all__"
fields = [
"label",
"user",
"user_type",
"workspace",
"created_at",
]

View File

@@ -1,3 +1,6 @@
# Django imports
from django.db.models.functions import TruncDate
# Third party imports
from rest_framework import serializers
@@ -5,12 +8,60 @@ from rest_framework import serializers
from .base import BaseSerializer
from .user import UserLiteSerializer
from .issue import IssueStateSerializer
from plane.db.models import Cycle, CycleIssue
from .workspace import WorkspaceLiteSerializer
from .project import ProjectLiteSerializer
from plane.db.models import Cycle, CycleIssue, CycleFavorite
class CycleWriteSerializer(BaseSerializer):
def validate(self, data):
if data.get("start_date", None) is not None and data.get("end_date", None) is not None and data.get("start_date", None) > data.get("end_date", None):
raise serializers.ValidationError("Start date cannot exceed end date")
return data
class Meta:
model = Cycle
fields = "__all__"
class CycleSerializer(BaseSerializer):
owned_by = UserLiteSerializer(read_only=True)
is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
cancelled_issues = serializers.IntegerField(read_only=True)
completed_issues = serializers.IntegerField(read_only=True)
started_issues = serializers.IntegerField(read_only=True)
unstarted_issues = serializers.IntegerField(read_only=True)
backlog_issues = serializers.IntegerField(read_only=True)
assignees = serializers.SerializerMethodField(read_only=True)
total_estimates = serializers.IntegerField(read_only=True)
completed_estimates = serializers.IntegerField(read_only=True)
started_estimates = serializers.IntegerField(read_only=True)
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
def validate(self, data):
if data.get("start_date", None) is not None and data.get("end_date", None) is not None and data.get("start_date", None) > data.get("end_date", None):
raise serializers.ValidationError("Start date cannot exceed end date")
return data
def get_assignees(self, obj):
members = [
{
"avatar": assignee.avatar,
"display_name": assignee.display_name,
"id": assignee.id,
}
for issue_cycle in obj.issue_cycle.prefetch_related("issue__assignees").all()
for assignee in issue_cycle.issue.assignees.all()
]
# Use a set comprehension to return only the unique objects
unique_objects = {frozenset(item.items()) for item in members}
# Convert the set back to a list of dictionaries
unique_list = [dict(item) for item in unique_objects]
return unique_list
class Meta:
model = Cycle
@@ -23,7 +74,6 @@ class CycleSerializer(BaseSerializer):
class CycleIssueSerializer(BaseSerializer):
issue_detail = IssueStateSerializer(read_only=True, source="issue")
sub_issues_count = serializers.IntegerField(read_only=True)
@@ -35,3 +85,16 @@ class CycleIssueSerializer(BaseSerializer):
"project",
"cycle",
]
class CycleFavoriteSerializer(BaseSerializer):
cycle_detail = CycleSerializer(source="cycle", read_only=True)
class Meta:
model = CycleFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"user",
]

View File

@@ -0,0 +1,44 @@
# Module imports
from .base import BaseSerializer
from plane.db.models import Estimate, EstimatePoint
from plane.api.serializers import WorkspaceLiteSerializer, ProjectLiteSerializer
class EstimateSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
class Meta:
model = Estimate
fields = "__all__"
read_only_fields = [
"workspace",
"project",
]
class EstimatePointSerializer(BaseSerializer):
class Meta:
model = EstimatePoint
fields = "__all__"
read_only_fields = [
"estimate",
"workspace",
"project",
]
class EstimateReadSerializer(BaseSerializer):
points = EstimatePointSerializer(read_only=True, many=True)
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
class Meta:
model = Estimate
fields = "__all__"
read_only_fields = [
"points",
"name",
"description",
]

View File

@@ -0,0 +1,26 @@
# Module imports
from .base import BaseSerializer
from plane.db.models import ExporterHistory
from .user import UserLiteSerializer
class ExporterHistorySerializer(BaseSerializer):
initiated_by_detail = UserLiteSerializer(source="initiated_by", read_only=True)
class Meta:
model = ExporterHistory
fields = [
"id",
"created_at",
"updated_at",
"project",
"provider",
"status",
"url",
"initiated_by",
"initiated_by_detail",
"token",
"created_by",
"updated_by",
]
read_only_fields = fields

View File

@@ -0,0 +1,16 @@
# Module imports
from .base import BaseSerializer
from .user import UserLiteSerializer
from .project import ProjectLiteSerializer
from .workspace import WorkspaceLiteSerializer
from plane.db.models import Importer
class ImporterSerializer(BaseSerializer):
initiated_by_detail = UserLiteSerializer(source="initiated_by", read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
class Meta:
model = Importer
fields = "__all__"

View File

@@ -0,0 +1,58 @@
# Third party frameworks
from rest_framework import serializers
# Module imports
from .base import BaseSerializer
from .issue import IssueFlatSerializer, LabelLiteSerializer
from .project import ProjectLiteSerializer
from .state import StateLiteSerializer
from .project import ProjectLiteSerializer
from .user import UserLiteSerializer
from plane.db.models import Inbox, InboxIssue, Issue
class InboxSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(source="project", read_only=True)
pending_issue_count = serializers.IntegerField(read_only=True)
class Meta:
model = Inbox
fields = "__all__"
read_only_fields = [
"project",
"workspace",
]
class InboxIssueSerializer(BaseSerializer):
issue_detail = IssueFlatSerializer(source="issue", read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True)
class Meta:
model = InboxIssue
fields = "__all__"
read_only_fields = [
"project",
"workspace",
]
class InboxIssueLiteSerializer(BaseSerializer):
class Meta:
model = InboxIssue
fields = ["id", "status", "duplicate_to", "snoozed_till", "source"]
read_only_fields = fields
class IssueStateInboxSerializer(BaseSerializer):
state_detail = StateLiteSerializer(read_only=True, source="state")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
label_details = LabelLiteSerializer(read_only=True, source="labels", many=True)
assignee_details = UserLiteSerializer(read_only=True, source="assignees", many=True)
sub_issues_count = serializers.IntegerField(read_only=True)
bridge_id = serializers.UUIDField(read_only=True)
issue_inbox = InboxIssueLiteSerializer(read_only=True, many=True)
class Meta:
model = Issue
fields = "__all__"

View File

@@ -0,0 +1,8 @@
from .base import IntegrationSerializer, WorkspaceIntegrationSerializer
from .github import (
GithubRepositorySerializer,
GithubRepositorySyncSerializer,
GithubIssueSyncSerializer,
GithubCommentSyncSerializer,
)
from .slack import SlackProjectSyncSerializer

View File

@@ -0,0 +1,20 @@
# Module imports
from plane.api.serializers import BaseSerializer
from plane.db.models import Integration, WorkspaceIntegration
class IntegrationSerializer(BaseSerializer):
class Meta:
model = Integration
fields = "__all__"
read_only_fields = [
"verified",
]
class WorkspaceIntegrationSerializer(BaseSerializer):
integration_detail = IntegrationSerializer(read_only=True, source="integration")
class Meta:
model = WorkspaceIntegration
fields = "__all__"

View File

@@ -0,0 +1,45 @@
# Module imports
from plane.api.serializers import BaseSerializer
from plane.db.models import (
GithubIssueSync,
GithubRepository,
GithubRepositorySync,
GithubCommentSync,
)
class GithubRepositorySerializer(BaseSerializer):
class Meta:
model = GithubRepository
fields = "__all__"
class GithubRepositorySyncSerializer(BaseSerializer):
repo_detail = GithubRepositorySerializer(source="repository")
class Meta:
model = GithubRepositorySync
fields = "__all__"
class GithubIssueSyncSerializer(BaseSerializer):
class Meta:
model = GithubIssueSync
fields = "__all__"
read_only_fields = [
"project",
"workspace",
"repository_sync",
]
class GithubCommentSyncSerializer(BaseSerializer):
class Meta:
model = GithubCommentSync
fields = "__all__"
read_only_fields = [
"project",
"workspace",
"repository_sync",
"issue_sync",
]

View File

@@ -0,0 +1,14 @@
# Module imports
from plane.api.serializers import BaseSerializer
from plane.db.models import SlackProjectSync
class SlackProjectSyncSerializer(BaseSerializer):
class Meta:
model = SlackProjectSync
fields = "__all__"
read_only_fields = [
"project",
"workspace",
"workspace_integration",
]

View File

@@ -1,29 +1,36 @@
# Django imports
from django.utils import timezone
# Third Party imports
from rest_framework import serializers
# Module imports
from .base import BaseSerializer
from .user import UserLiteSerializer
from .state import StateSerializer
from .state import StateSerializer, StateLiteSerializer
from .user import UserLiteSerializer
from .project import ProjectSerializer
from .workspace import WorkSpaceSerializer
from .project import ProjectSerializer, ProjectLiteSerializer
from .workspace import WorkspaceLiteSerializer
from plane.db.models import (
User,
Issue,
IssueActivity,
IssueComment,
TimelineIssue,
IssueProperty,
IssueBlocker,
IssueAssignee,
IssueSubscriber,
IssueLabel,
Label,
IssueBlocker,
CycleIssue,
Cycle,
Module,
ModuleIssue,
IssueLink,
IssueAttachment,
IssueReaction,
CommentReaction,
IssueVote,
IssueRelation,
)
@@ -36,32 +43,37 @@ class IssueFlatSerializer(BaseSerializer):
"id",
"name",
"description",
"description_html",
"priority",
"start_date",
"target_date",
"sequence_id",
"sort_order",
"is_draft",
]
# Issue Serializer with state details
class IssueStateSerializer(BaseSerializer):
state_detail = StateSerializer(read_only=True, source="state")
project_detail = ProjectSerializer(read_only=True, source="project")
class IssueProjectLiteSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(source="project", read_only=True)
class Meta:
model = Issue
fields = "__all__"
fields = [
"id",
"project_detail",
"name",
"sequence_id",
]
read_only_fields = fields
##TODO: Find a better way to write this serializer
## Find a better approach to save manytomany?
class IssueCreateSerializer(BaseSerializer):
state_detail = StateSerializer(read_only=True, source="state")
created_by_detail = UserLiteSerializer(read_only=True, source="created_by")
project_detail = ProjectSerializer(read_only=True, source="project")
workspace_detail = WorkSpaceSerializer(read_only=True, source="workspace")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
assignees_list = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()),
@@ -69,25 +81,12 @@ class IssueCreateSerializer(BaseSerializer):
required=False,
)
# List of issues that are blocking this issue
blockers_list = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=Issue.objects.all()),
write_only=True,
required=False,
)
labels_list = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=Label.objects.all()),
write_only=True,
required=False,
)
# List of issues that are blocked by this issue
blocks_list = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=Issue.objects.all()),
write_only=True,
required=False,
)
class Meta:
model = Issue
fields = "__all__"
@@ -100,104 +99,83 @@ class IssueCreateSerializer(BaseSerializer):
"updated_at",
]
def validate(self, data):
if (
data.get("start_date", None) is not None
and data.get("target_date", None) is not None
and data.get("start_date", None) > data.get("target_date", None)
):
raise serializers.ValidationError("Start date cannot exceed target date")
return data
def create(self, validated_data):
blockers = validated_data.pop("blockers_list", None)
assignees = validated_data.pop("assignees_list", None)
labels = validated_data.pop("labels_list", None)
blocks = validated_data.pop("blocks_list", None)
project = self.context["project"]
issue = Issue.objects.create(**validated_data, project=project)
project_id = self.context["project_id"]
workspace_id = self.context["workspace_id"]
default_assignee_id = self.context["default_assignee_id"]
if blockers is not None:
IssueBlocker.objects.bulk_create(
[
IssueBlocker(
block=issue,
blocked_by=blocker,
project=project,
workspace=project.workspace,
created_by=issue.created_by,
updated_by=issue.updated_by,
)
for blocker in blockers
],
batch_size=10,
)
issue = Issue.objects.create(**validated_data, project_id=project_id)
if assignees is not None:
# Issue Audit Users
created_by_id = issue.created_by_id
updated_by_id = issue.updated_by_id
if assignees is not None and len(assignees):
IssueAssignee.objects.bulk_create(
[
IssueAssignee(
assignee=user,
issue=issue,
project=project,
workspace=project.workspace,
created_by=issue.created_by,
updated_by=issue.updated_by,
project_id=project_id,
workspace_id=workspace_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for user in assignees
],
batch_size=10,
)
else:
# Then assign it to default assignee
if default_assignee_id is not None:
IssueAssignee.objects.create(
assignee_id=default_assignee_id,
issue=issue,
project_id=project_id,
workspace_id=workspace_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
if labels is not None:
if labels is not None and len(labels):
IssueLabel.objects.bulk_create(
[
IssueLabel(
label=label,
issue=issue,
project=project,
workspace=project.workspace,
created_by=issue.created_by,
updated_by=issue.updated_by,
project_id=project_id,
workspace_id=workspace_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for label in labels
],
batch_size=10,
)
if blocks is not None:
IssueBlocker.objects.bulk_create(
[
IssueBlocker(
block=block,
blocked_by=issue,
project=project,
workspace=project.workspace,
created_by=issue.created_by,
updated_by=issue.updated_by,
)
for block in blocks
],
batch_size=10,
)
return issue
def update(self, instance, validated_data):
blockers = validated_data.pop("blockers_list", None)
assignees = validated_data.pop("assignees_list", None)
labels = validated_data.pop("labels_list", None)
blocks = validated_data.pop("blocks_list", None)
if blockers is not None:
IssueBlocker.objects.filter(block=instance).delete()
IssueBlocker.objects.bulk_create(
[
IssueBlocker(
block=instance,
blocked_by=blocker,
project=instance.project,
workspace=instance.project.workspace,
created_by=instance.created_by,
updated_by=instance.updated_by,
)
for blocker in blockers
],
batch_size=10,
)
# Related models
project_id = instance.project_id
workspace_id = instance.workspace_id
created_by_id = instance.created_by_id
updated_by_id = instance.updated_by_id
if assignees is not None:
IssueAssignee.objects.filter(issue=instance).delete()
@@ -206,10 +184,10 @@ class IssueCreateSerializer(BaseSerializer):
IssueAssignee(
assignee=user,
issue=instance,
project=instance.project,
workspace=instance.project.workspace,
created_by=instance.created_by,
updated_by=instance.updated_by,
project_id=project_id,
workspace_id=workspace_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for user in assignees
],
@@ -223,39 +201,25 @@ class IssueCreateSerializer(BaseSerializer):
IssueLabel(
label=label,
issue=instance,
project=instance.project,
workspace=instance.project.workspace,
created_by=instance.created_by,
updated_by=instance.updated_by,
project_id=project_id,
workspace_id=workspace_id,
created_by_id=created_by_id,
updated_by_id=updated_by_id,
)
for label in labels
],
batch_size=10,
)
if blocks is not None:
IssueBlocker.objects.filter(blocked_by=instance).delete()
IssueBlocker.objects.bulk_create(
[
IssueBlocker(
block=block,
blocked_by=instance,
project=instance.project,
workspace=instance.project.workspace,
created_by=instance.created_by,
updated_by=instance.updated_by,
)
for block in blocks
],
batch_size=10,
)
# Time updation occues even when other related models are updated
instance.updated_at = timezone.now()
return super().update(instance, validated_data)
class IssueActivitySerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")
issue_detail = IssueFlatSerializer(read_only=True, source="issue")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
class Meta:
model = IssueActivity
@@ -263,10 +227,10 @@ class IssueActivitySerializer(BaseSerializer):
class IssueCommentSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")
issue_detail = IssueFlatSerializer(read_only=True, source="issue")
project_detail = ProjectSerializer(read_only=True, source="project")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
class Meta:
model = IssueComment
@@ -282,21 +246,6 @@ class IssueCommentSerializer(BaseSerializer):
]
class TimeLineIssueSerializer(BaseSerializer):
class Meta:
model = TimelineIssue
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"issue",
"created_by",
"updated_by",
"created_at",
"updated_at",
]
class IssuePropertySerializer(BaseSerializer):
class Meta:
model = IssueProperty
@@ -309,6 +258,9 @@ class IssuePropertySerializer(BaseSerializer):
class LabelSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True)
class Meta:
model = Label
fields = "__all__"
@@ -318,8 +270,17 @@ class LabelSerializer(BaseSerializer):
]
class IssueLabelSerializer(BaseSerializer):
class LabelLiteSerializer(BaseSerializer):
class Meta:
model = Label
fields = [
"id",
"name",
"color",
]
class IssueLabelSerializer(BaseSerializer):
# label_details = LabelSerializer(read_only=True, source="label")
class Meta:
@@ -331,26 +292,42 @@ class IssueLabelSerializer(BaseSerializer):
]
class BlockedIssueSerializer(BaseSerializer):
blocked_issue_detail = IssueFlatSerializer(source="block", read_only=True)
class IssueRelationSerializer(BaseSerializer):
issue_detail = IssueProjectLiteSerializer(read_only=True, source="related_issue")
class Meta:
model = IssueBlocker
fields = "__all__"
model = IssueRelation
fields = [
"issue_detail",
"relation_type",
"related_issue",
"issue",
"id"
]
read_only_fields = [
"workspace",
"project",
]
class BlockerIssueSerializer(BaseSerializer):
blocker_issue_detail = IssueFlatSerializer(source="blocked_by", read_only=True)
class RelatedIssueSerializer(BaseSerializer):
issue_detail = IssueProjectLiteSerializer(read_only=True, source="issue")
class Meta:
model = IssueBlocker
fields = "__all__"
model = IssueRelation
fields = [
"issue_detail",
"relation_type",
"related_issue",
"issue",
"id"
]
read_only_fields = [
"workspace",
"project",
]
class IssueAssigneeSerializer(BaseSerializer):
assignee_details = UserLiteSerializer(read_only=True, source="assignee")
class Meta:
@@ -373,7 +350,6 @@ class CycleBaseSerializer(BaseSerializer):
class IssueCycleDetailSerializer(BaseSerializer):
cycle_detail = CycleBaseSerializer(read_only=True, source="cycle")
class Meta:
@@ -404,7 +380,6 @@ class ModuleBaseSerializer(BaseSerializer):
class IssueModuleDetailSerializer(BaseSerializer):
module_detail = ModuleBaseSerializer(read_only=True, source="module")
class Meta:
@@ -420,19 +395,160 @@ class IssueModuleDetailSerializer(BaseSerializer):
]
class IssueLinkSerializer(BaseSerializer):
created_by_detail = UserLiteSerializer(read_only=True, source="created_by")
class Meta:
model = IssueLink
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"created_by",
"updated_by",
"created_at",
"updated_at",
"issue",
]
# Validation if url already exists
def create(self, validated_data):
if IssueLink.objects.filter(
url=validated_data.get("url"), issue_id=validated_data.get("issue_id")
).exists():
raise serializers.ValidationError(
{"error": "URL already exists for this Issue"}
)
return IssueLink.objects.create(**validated_data)
class IssueAttachmentSerializer(BaseSerializer):
class Meta:
model = IssueAttachment
fields = "__all__"
read_only_fields = [
"created_by",
"updated_by",
"created_at",
"updated_at",
"workspace",
"project",
"issue",
]
class IssueReactionSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")
class Meta:
model = IssueReaction
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"issue",
"actor",
]
class CommentReactionLiteSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")
class Meta:
model = CommentReaction
fields = [
"id",
"reaction",
"comment",
"actor_detail",
]
class CommentReactionSerializer(BaseSerializer):
class Meta:
model = CommentReaction
fields = "__all__"
read_only_fields = ["workspace", "project", "comment", "actor"]
class IssueVoteSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")
class Meta:
model = IssueVote
fields = ["issue", "vote", "workspace", "project", "actor", "actor_detail"]
read_only_fields = fields
class IssueCommentSerializer(BaseSerializer):
actor_detail = UserLiteSerializer(read_only=True, source="actor")
issue_detail = IssueFlatSerializer(read_only=True, source="issue")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
comment_reactions = CommentReactionLiteSerializer(read_only=True, many=True)
is_member = serializers.BooleanField(read_only=True)
class Meta:
model = IssueComment
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"issue",
"created_by",
"updated_by",
"created_at",
"updated_at",
]
class IssueStateFlatSerializer(BaseSerializer):
state_detail = StateLiteSerializer(read_only=True, source="state")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
class Meta:
model = Issue
fields = [
"id",
"sequence_id",
"name",
"state_detail",
"project_detail",
]
# Issue Serializer with state details
class IssueStateSerializer(BaseSerializer):
label_details = LabelLiteSerializer(read_only=True, source="labels", many=True)
state_detail = StateLiteSerializer(read_only=True, source="state")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
assignee_details = UserLiteSerializer(read_only=True, source="assignees", many=True)
sub_issues_count = serializers.IntegerField(read_only=True)
bridge_id = serializers.UUIDField(read_only=True)
attachment_count = serializers.IntegerField(read_only=True)
link_count = serializers.IntegerField(read_only=True)
class Meta:
model = Issue
fields = "__all__"
class IssueSerializer(BaseSerializer):
project_detail = ProjectSerializer(read_only=True, source="project")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
state_detail = StateSerializer(read_only=True, source="state")
parent_detail = IssueFlatSerializer(read_only=True, source="parent")
parent_detail = IssueStateFlatSerializer(read_only=True, source="parent")
label_details = LabelSerializer(read_only=True, source="labels", many=True)
assignee_details = UserLiteSerializer(read_only=True, source="assignees", many=True)
# List of issues blocked by this issue
blocked_issues = BlockedIssueSerializer(read_only=True, many=True)
# List of issues that block this issue
blocker_issues = BlockerIssueSerializer(read_only=True, many=True)
related_issues = IssueRelationSerializer(read_only=True, source="issue_relation", many=True)
issue_relations = RelatedIssueSerializer(read_only=True, source="issue_related", many=True)
issue_cycle = IssueCycleDetailSerializer(read_only=True)
issue_module = IssueModuleDetailSerializer(read_only=True)
issue_link = IssueLinkSerializer(read_only=True, many=True)
issue_attachment = IssueAttachmentSerializer(read_only=True, many=True)
sub_issues_count = serializers.IntegerField(read_only=True)
issue_reactions = IssueReactionSerializer(read_only=True, many=True)
class Meta:
model = Issue
@@ -445,3 +561,70 @@ class IssueSerializer(BaseSerializer):
"created_at",
"updated_at",
]
class IssueLiteSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
state_detail = StateLiteSerializer(read_only=True, source="state")
label_details = LabelLiteSerializer(read_only=True, source="labels", many=True)
assignee_details = UserLiteSerializer(read_only=True, source="assignees", many=True)
sub_issues_count = serializers.IntegerField(read_only=True)
cycle_id = serializers.UUIDField(read_only=True)
module_id = serializers.UUIDField(read_only=True)
attachment_count = serializers.IntegerField(read_only=True)
link_count = serializers.IntegerField(read_only=True)
issue_reactions = IssueReactionSerializer(read_only=True, many=True)
class Meta:
model = Issue
fields = "__all__"
read_only_fields = [
"start_date",
"target_date",
"completed_at",
"workspace",
"project",
"created_by",
"updated_by",
"created_at",
"updated_at",
]
class IssuePublicSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(read_only=True, source="project")
state_detail = StateLiteSerializer(read_only=True, source="state")
reactions = IssueReactionSerializer(read_only=True, many=True, source="issue_reactions")
votes = IssueVoteSerializer(read_only=True, many=True)
class Meta:
model = Issue
fields = [
"id",
"name",
"description_html",
"sequence_id",
"state",
"state_detail",
"project",
"project_detail",
"workspace",
"priority",
"target_date",
"reactions",
"votes",
]
read_only_fields = fields
class IssueSubscriberSerializer(BaseSerializer):
class Meta:
model = IssueSubscriber
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"issue",
]

View File

@@ -4,30 +4,29 @@ from rest_framework import serializers
# Module imports
from .base import BaseSerializer
from .user import UserLiteSerializer
from .project import ProjectSerializer
from .project import ProjectSerializer, ProjectLiteSerializer
from .workspace import WorkspaceLiteSerializer
from .issue import IssueStateSerializer
from plane.db.models import User, Module, ModuleMember, ModuleIssue, ModuleLink
class LinkCreateSerializer(serializers.Serializer):
url = serializers.CharField(required=True)
title = serializers.CharField(required=False)
from plane.db.models import (
User,
Module,
ModuleMember,
ModuleIssue,
ModuleLink,
ModuleFavorite,
)
class ModuleWriteSerializer(BaseSerializer):
members_list = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()),
write_only=True,
required=False,
)
links_list = serializers.ListField(
child=LinkCreateSerializer(),
write_only=True,
required=False,
)
project_detail = ProjectLiteSerializer(source="project", read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
class Meta:
model = Module
@@ -41,10 +40,13 @@ class ModuleWriteSerializer(BaseSerializer):
"updated_at",
]
def create(self, validated_data):
def validate(self, data):
if data.get("start_date", None) is not None and data.get("target_date", None) is not None and data.get("start_date", None) > data.get("target_date", None):
raise serializers.ValidationError("Start date cannot exceed target date")
return data
def create(self, validated_data):
members = validated_data.pop("members_list", None)
links = validated_data.pop("links_list", None)
project = self.context["project"]
@@ -67,30 +69,10 @@ class ModuleWriteSerializer(BaseSerializer):
ignore_conflicts=True,
)
if links is not None:
ModuleLink.objects.bulk_create(
[
ModuleLink(
module=module,
project=project,
workspace=project.workspace,
created_by=module.created_by,
updated_by=module.updated_by,
title=link.get("title", None),
url=link.get("url", None),
)
for link in links
],
batch_size=10,
ignore_conflicts=True,
)
return module
def update(self, instance, validated_data):
members = validated_data.pop("members_list", None)
links = validated_data.pop("links_list", None)
if members is not None:
ModuleMember.objects.filter(module=instance).delete()
@@ -110,25 +92,6 @@ class ModuleWriteSerializer(BaseSerializer):
ignore_conflicts=True,
)
if links is not None:
ModuleLink.objects.filter(module=instance).delete()
ModuleLink.objects.bulk_create(
[
ModuleLink(
module=instance,
project=instance.project,
workspace=instance.project.workspace,
created_by=instance.created_by,
updated_by=instance.updated_by,
title=link.get("title", None),
url=link.get("url", None),
)
for link in links
],
batch_size=10,
ignore_conflicts=True,
)
return super().update(instance, validated_data)
@@ -147,9 +110,8 @@ class ModuleFlatSerializer(BaseSerializer):
class ModuleIssueSerializer(BaseSerializer):
module_detail = ModuleFlatSerializer(read_only=True, source="module")
issue_detail = IssueStateSerializer(read_only=True, source="issue")
issue_detail = ProjectLiteSerializer(read_only=True, source="issue")
sub_issues_count = serializers.IntegerField(read_only=True)
class Meta:
@@ -167,7 +129,6 @@ class ModuleIssueSerializer(BaseSerializer):
class ModuleLinkSerializer(BaseSerializer):
created_by_detail = UserLiteSerializer(read_only=True, source="created_by")
class Meta:
@@ -180,16 +141,32 @@ class ModuleLinkSerializer(BaseSerializer):
"updated_by",
"created_at",
"updated_at",
"module",
]
# Validation if url already exists
def create(self, validated_data):
if ModuleLink.objects.filter(
url=validated_data.get("url"), module_id=validated_data.get("module_id")
).exists():
raise serializers.ValidationError(
{"error": "URL already exists for this Issue"}
)
return ModuleLink.objects.create(**validated_data)
class ModuleSerializer(BaseSerializer):
project_detail = ProjectSerializer(read_only=True, source="project")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
lead_detail = UserLiteSerializer(read_only=True, source="lead")
members_detail = UserLiteSerializer(read_only=True, many=True, source="members")
issue_module = ModuleIssueSerializer(read_only=True, many=True)
link_module = ModuleLinkSerializer(read_only=True, many=True)
is_favorite = serializers.BooleanField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
cancelled_issues = serializers.IntegerField(read_only=True)
completed_issues = serializers.IntegerField(read_only=True)
started_issues = serializers.IntegerField(read_only=True)
unstarted_issues = serializers.IntegerField(read_only=True)
backlog_issues = serializers.IntegerField(read_only=True)
class Meta:
model = Module
@@ -202,3 +179,16 @@ class ModuleSerializer(BaseSerializer):
"created_at",
"updated_at",
]
class ModuleFavoriteSerializer(BaseSerializer):
module_detail = ModuleFlatSerializer(source="module", read_only=True)
class Meta:
model = ModuleFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"user",
]

View File

@@ -0,0 +1,12 @@
# Module imports
from .base import BaseSerializer
from .user import UserLiteSerializer
from plane.db.models import Notification
class NotificationSerializer(BaseSerializer):
triggered_by_details = UserLiteSerializer(read_only=True, source="triggered_by")
class Meta:
model = Notification
fields = "__all__"

View File

@@ -0,0 +1,111 @@
# Third party imports
from rest_framework import serializers
# Module imports
from .base import BaseSerializer
from .issue import IssueFlatSerializer, LabelLiteSerializer
from .workspace import WorkspaceLiteSerializer
from .project import ProjectLiteSerializer
from plane.db.models import Page, PageBlock, PageFavorite, PageLabel, Label
class PageBlockSerializer(BaseSerializer):
issue_detail = IssueFlatSerializer(source="issue", read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
class Meta:
model = PageBlock
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"page",
]
class PageBlockLiteSerializer(BaseSerializer):
class Meta:
model = PageBlock
fields = "__all__"
class PageSerializer(BaseSerializer):
is_favorite = serializers.BooleanField(read_only=True)
label_details = LabelLiteSerializer(read_only=True, source="labels", many=True)
labels_list = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=Label.objects.all()),
write_only=True,
required=False,
)
blocks = PageBlockLiteSerializer(read_only=True, many=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
class Meta:
model = Page
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"owned_by",
]
def create(self, validated_data):
labels = validated_data.pop("labels_list", None)
project_id = self.context["project_id"]
owned_by_id = self.context["owned_by_id"]
page = Page.objects.create(
**validated_data, project_id=project_id, owned_by_id=owned_by_id
)
if labels is not None:
PageLabel.objects.bulk_create(
[
PageLabel(
label=label,
page=page,
project_id=project_id,
workspace_id=page.workspace_id,
created_by_id=page.created_by_id,
updated_by_id=page.updated_by_id,
)
for label in labels
],
batch_size=10,
)
return page
def update(self, instance, validated_data):
labels = validated_data.pop("labels_list", None)
if labels is not None:
PageLabel.objects.filter(page=instance).delete()
PageLabel.objects.bulk_create(
[
PageLabel(
label=label,
page=instance,
project_id=instance.project_id,
workspace_id=instance.workspace_id,
created_by_id=instance.created_by_id,
updated_by_id=instance.updated_by_id,
)
for label in labels
],
batch_size=10,
)
return super().update(instance, validated_data)
class PageFavoriteSerializer(BaseSerializer):
page_detail = PageSerializer(source="page", read_only=True)
class Meta:
model = PageFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"user",
]

View File

@@ -1,57 +0,0 @@
from rest_framework.serializers import (
ModelSerializer,
Serializer,
CharField,
SerializerMethodField,
)
from rest_framework.authtoken.models import Token
from rest_framework_simplejwt.tokens import RefreshToken
from plane.db.models import User
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = "__all__"
extra_kwargs = {"password": {"write_only": True}}
class ChangePasswordSerializer(Serializer):
model = User
"""
Serializer for password change endpoint.
"""
old_password = CharField(required=True)
new_password = CharField(required=True)
class ResetPasswordSerializer(Serializer):
model = User
"""
Serializer for password change endpoint.
"""
new_password = CharField(required=True)
confirm_password = CharField(required=True)
class TokenSerializer(ModelSerializer):
user = UserSerializer()
access_token = SerializerMethodField()
refresh_token = SerializerMethodField()
def get_access_token(self, obj):
refresh_token = RefreshToken.for_user(obj.user)
return str(refresh_token.access_token)
def get_refresh_token(self, obj):
refresh_token = RefreshToken.for_user(obj.user)
return str(refresh_token)
class Meta:
model = Token
fields = "__all__"

View File

@@ -6,17 +6,22 @@ from rest_framework import serializers
# Module imports
from .base import BaseSerializer
from plane.api.serializers.workspace import WorkSpaceSerializer
from plane.api.serializers.user import UserLiteSerializer
from plane.api.serializers.workspace import WorkSpaceSerializer, WorkspaceLiteSerializer
from plane.api.serializers.user import UserLiteSerializer, UserAdminLiteSerializer
from plane.db.models import (
Project,
ProjectMember,
ProjectMemberInvite,
ProjectIdentifier,
ProjectFavorite,
ProjectDeployBoard,
ProjectPublicMember,
)
class ProjectSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
class Meta:
model = Project
fields = "__all__"
@@ -44,7 +49,6 @@ class ProjectSerializer(BaseSerializer):
return project
def update(self, instance, validated_data):
identifier = validated_data.get("identifier", "").strip().upper()
# If identifier is not passed update the project and return
@@ -56,12 +60,15 @@ class ProjectSerializer(BaseSerializer):
project_identifier = ProjectIdentifier.objects.filter(
name=identifier, workspace_id=instance.workspace_id
).first()
if project_identifier is None:
project = super().update(instance, validated_data)
_ = ProjectIdentifier.objects.update(name=identifier, project=project)
project_identifier = ProjectIdentifier.objects.filter(
project=project
).first()
if project_identifier is not None:
project_identifier.name = identifier
project_identifier.save()
return project
# If found check if the project_id to be updated and identifier project id is same
if project_identifier.project_id == instance.id:
# If same pass update
@@ -72,11 +79,33 @@ class ProjectSerializer(BaseSerializer):
raise serializers.ValidationError(detail="Project Identifier is already taken")
class ProjectDetailSerializer(BaseSerializer):
class ProjectLiteSerializer(BaseSerializer):
class Meta:
model = Project
fields = [
"id",
"identifier",
"name",
"cover_image",
"icon_prop",
"emoji",
"description",
]
read_only_fields = fields
class ProjectDetailSerializer(BaseSerializer):
workspace = WorkSpaceSerializer(read_only=True)
default_assignee = UserLiteSerializer(read_only=True)
project_lead = UserLiteSerializer(read_only=True)
is_favorite = serializers.BooleanField(read_only=True)
total_members = serializers.IntegerField(read_only=True)
total_cycles = serializers.IntegerField(read_only=True)
total_modules = serializers.IntegerField(read_only=True)
is_member = serializers.BooleanField(read_only=True)
sort_order = serializers.FloatField(read_only=True)
member_role = serializers.IntegerField(read_only=True)
is_deployed = serializers.BooleanField(read_only=True)
class Meta:
model = Project
@@ -84,9 +113,8 @@ class ProjectDetailSerializer(BaseSerializer):
class ProjectMemberSerializer(BaseSerializer):
workspace = WorkSpaceSerializer(read_only=True)
project = ProjectSerializer(read_only=True)
workspace = WorkspaceLiteSerializer(read_only=True)
project = ProjectLiteSerializer(read_only=True)
member = UserLiteSerializer(read_only=True)
class Meta:
@@ -94,10 +122,19 @@ class ProjectMemberSerializer(BaseSerializer):
fields = "__all__"
class ProjectMemberInviteSerializer(BaseSerializer):
class ProjectMemberAdminSerializer(BaseSerializer):
workspace = WorkspaceLiteSerializer(read_only=True)
project = ProjectLiteSerializer(read_only=True)
member = UserAdminLiteSerializer(read_only=True)
project = ProjectSerializer(read_only=True)
workspace = WorkSpaceSerializer(read_only=True)
class Meta:
model = ProjectMember
fields = "__all__"
class ProjectMemberInviteSerializer(BaseSerializer):
project = ProjectLiteSerializer(read_only=True)
workspace = WorkspaceLiteSerializer(read_only=True)
class Meta:
model = ProjectMemberInvite
@@ -108,3 +145,50 @@ class ProjectIdentifierSerializer(BaseSerializer):
class Meta:
model = ProjectIdentifier
fields = "__all__"
class ProjectFavoriteSerializer(BaseSerializer):
project_detail = ProjectLiteSerializer(source="project", read_only=True)
class Meta:
model = ProjectFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"user",
]
class ProjectMemberLiteSerializer(BaseSerializer):
member = UserLiteSerializer(read_only=True)
is_subscribed = serializers.BooleanField(read_only=True)
class Meta:
model = ProjectMember
fields = ["member", "id", "is_subscribed"]
read_only_fields = fields
class ProjectDeployBoardSerializer(BaseSerializer):
project_details = ProjectLiteSerializer(read_only=True, source="project")
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
class Meta:
model = ProjectDeployBoard
fields = "__all__"
read_only_fields = [
"workspace",
"project", "anchor",
]
class ProjectPublicMemberSerializer(BaseSerializer):
class Meta:
model = ProjectPublicMember
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"member",
]

View File

@@ -1,14 +0,0 @@
# Module imports
from .base import BaseSerializer
from plane.db.models import Shortcut
class ShortCutSerializer(BaseSerializer):
class Meta:
model = Shortcut
fields = "__all__"
read_only_fields = [
"workspace",
"project",
]

View File

@@ -1,10 +1,15 @@
# Module imports
from .base import BaseSerializer
from .workspace import WorkspaceLiteSerializer
from .project import ProjectLiteSerializer
from plane.db.models import State
class StateSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(read_only=True, source="workspace")
project_detail = ProjectLiteSerializer(read_only=True, source="project")
class Meta:
model = State
fields = "__all__"
@@ -12,3 +17,15 @@ class StateSerializer(BaseSerializer):
"workspace",
"project",
]
class StateLiteSerializer(BaseSerializer):
class Meta:
model = State
fields = [
"id",
"name",
"color",
"group",
]
read_only_fields = fields

View File

@@ -1,3 +1,6 @@
# Third party imports
from rest_framework import serializers
# Module import
from .base import BaseSerializer
from plane.db.models import User
@@ -21,9 +24,14 @@ class UserSerializer(BaseSerializer):
"last_login_uagent",
"token_updated_at",
"is_onboarded",
"is_bot",
]
extra_kwargs = {"password": {"write_only": True}}
# If the user has already filled first name or last name then he is onboarded
def get_is_onboarded(self, obj):
return bool(obj.first_name) or bool(obj.last_name)
class UserLiteSerializer(BaseSerializer):
class Meta:
@@ -32,9 +40,50 @@ class UserLiteSerializer(BaseSerializer):
"id",
"first_name",
"last_name",
"email",
"avatar",
"is_bot",
"display_name",
]
read_only_fields = [
"id",
"is_bot",
]
class UserAdminLiteSerializer(BaseSerializer):
class Meta:
model = User
fields = [
"id",
"first_name",
"last_name",
"avatar",
"is_bot",
"display_name",
"email",
]
read_only_fields = [
"id",
"is_bot",
]
class ChangePasswordSerializer(serializers.Serializer):
model = User
"""
Serializer for password change endpoint.
"""
old_password = serializers.CharField(required=True)
new_password = serializers.CharField(required=True)
class ResetPasswordSerializer(serializers.Serializer):
model = User
"""
Serializer for password change endpoint.
"""
new_password = serializers.CharField(required=True)
confirm_password = serializers.CharField(required=True)

View File

@@ -1,14 +1,83 @@
# Third party imports
from rest_framework import serializers
# Module imports
from .base import BaseSerializer
from plane.db.models import View
from .workspace import WorkspaceLiteSerializer
from .project import ProjectLiteSerializer
from plane.db.models import GlobalView, IssueView, IssueViewFavorite
from plane.utils.issue_filters import issue_filters
class ViewSerializer(BaseSerializer):
class GlobalViewSerializer(BaseSerializer):
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
class Meta:
model = View
model = GlobalView
fields = "__all__"
read_only_fields = [
"workspace",
"query",
]
def create(self, validated_data):
query_params = validated_data.get("query_data", {})
if bool(query_params):
validated_data["query"] = issue_filters(query_params, "POST")
else:
validated_data["query"] = dict()
return GlobalView.objects.create(**validated_data)
def update(self, instance, validated_data):
query_params = validated_data.get("query_data", {})
if bool(query_params):
validated_data["query"] = issue_filters(query_params, "POST")
else:
validated_data["query"] = dict()
validated_data["query"] = issue_filters(query_params, "PATCH")
return super().update(instance, validated_data)
class IssueViewSerializer(BaseSerializer):
is_favorite = serializers.BooleanField(read_only=True)
project_detail = ProjectLiteSerializer(source="project", read_only=True)
workspace_detail = WorkspaceLiteSerializer(source="workspace", read_only=True)
class Meta:
model = IssueView
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"query",
]
def create(self, validated_data):
query_params = validated_data.get("query_data", {})
if bool(query_params):
validated_data["query"] = issue_filters(query_params, "POST")
else:
validated_data["query"] = dict()
return IssueView.objects.create(**validated_data)
def update(self, instance, validated_data):
query_params = validated_data.get("query_data", {})
if bool(query_params):
validated_data["query"] = issue_filters(query_params, "POST")
else:
validated_data["query"] = dict()
validated_data["query"] = issue_filters(query_params, "PATCH")
return super().update(instance, validated_data)
class IssueViewFavoriteSerializer(BaseSerializer):
view_detail = IssueViewSerializer(source="issue_view", read_only=True)
class Meta:
model = IssueViewFavorite
fields = "__all__"
read_only_fields = [
"workspace",
"project",
"user",
]

View File

@@ -3,16 +3,23 @@ from rest_framework import serializers
# Module imports
from .base import BaseSerializer
from .user import UserLiteSerializer
from .user import UserLiteSerializer, UserAdminLiteSerializer
from plane.db.models import User, Workspace, WorkspaceMember, Team, TeamMember
from plane.db.models import Workspace, WorkspaceMember, Team, WorkspaceMemberInvite
from plane.db.models import (
User,
Workspace,
WorkspaceMember,
Team,
TeamMember,
WorkspaceMemberInvite,
WorkspaceTheme,
)
class WorkSpaceSerializer(BaseSerializer):
owner = UserLiteSerializer(read_only=True)
total_members = serializers.IntegerField(read_only=True)
total_issues = serializers.IntegerField(read_only=True)
class Meta:
model = Workspace
@@ -26,11 +33,30 @@ class WorkSpaceSerializer(BaseSerializer):
"owner",
]
class WorkspaceLiteSerializer(BaseSerializer):
class Meta:
model = Workspace
fields = [
"name",
"slug",
"id",
]
read_only_fields = fields
class WorkSpaceMemberSerializer(BaseSerializer):
member = UserLiteSerializer(read_only=True)
workspace = WorkSpaceSerializer(read_only=True)
workspace = WorkspaceLiteSerializer(read_only=True)
class Meta:
model = WorkspaceMember
fields = "__all__"
class WorkspaceMemberAdminSerializer(BaseSerializer):
member = UserAdminLiteSerializer(read_only=True)
workspace = WorkspaceLiteSerializer(read_only=True)
class Meta:
model = WorkspaceMember
@@ -38,8 +64,9 @@ class WorkSpaceMemberSerializer(BaseSerializer):
class WorkSpaceMemberInviteSerializer(BaseSerializer):
workspace = WorkSpaceSerializer(read_only=True)
total_members = serializers.IntegerField(read_only=True)
created_by_detail = UserLiteSerializer(read_only=True, source="created_by")
class Meta:
model = WorkspaceMemberInvite
@@ -47,7 +74,6 @@ class WorkSpaceMemberInviteSerializer(BaseSerializer):
class TeamSerializer(BaseSerializer):
members_detail = UserLiteSerializer(read_only=True, source="members", many=True)
members = serializers.ListField(
child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()),
@@ -93,3 +119,13 @@ class TeamSerializer(BaseSerializer):
return super().update(instance, validated_data)
else:
return super().update(instance, validated_data)
class WorkspaceThemeSerializer(BaseSerializer):
class Meta:
model = WorkspaceTheme
fields = "__all__"
read_only_fields = [
"workspace",
"actor",
]

File diff suppressed because it is too large Load Diff

View File

@@ -11,10 +11,18 @@ from .project import (
ProjectJoinEndpoint,
ProjectUserViewsEndpoint,
ProjectMemberUserEndpoint,
ProjectFavoritesViewSet,
ProjectDeployBoardViewSet,
ProjectDeployBoardPublicSettingsEndpoint,
ProjectMemberEndpoint,
WorkspaceProjectDeployBoardEndpoint,
LeaveProjectEndpoint,
)
from .people import (
from .user import (
UserEndpoint,
UpdateUserOnBoardedEndpoint,
UpdateUserTourCompletedEndpoint,
UserActivityEndpoint,
)
from .oauth import OauthEndpoint
@@ -35,23 +43,53 @@ from .workspace import (
UserLastProjectWithWorkspaceEndpoint,
WorkspaceMemberUserEndpoint,
WorkspaceMemberUserViewsEndpoint,
UserActivityGraphEndpoint,
UserIssueCompletedGraphEndpoint,
UserWorkspaceDashboardEndpoint,
WorkspaceThemeViewSet,
WorkspaceUserProfileStatsEndpoint,
WorkspaceUserActivityEndpoint,
WorkspaceUserProfileEndpoint,
WorkspaceUserProfileIssuesEndpoint,
WorkspaceLabelsEndpoint,
WorkspaceMembersEndpoint,
LeaveWorkspaceEndpoint,
)
from .state import StateViewSet
from .shortcut import ShortCutViewSet
from .view import ViewViewSet
from .cycle import CycleViewSet, CycleIssueViewSet
from .asset import FileAssetEndpoint
from .view import GlobalViewViewSet, GlobalViewIssuesViewSet, IssueViewViewSet, ViewIssuesEndpoint, IssueViewFavoriteViewSet
from .cycle import (
CycleViewSet,
CycleIssueViewSet,
CycleDateCheckEndpoint,
CycleFavoriteViewSet,
TransferCycleIssueEndpoint,
)
from .asset import FileAssetEndpoint, UserAssetsEndpoint
from .issue import (
IssueViewSet,
WorkSpaceIssuesEndpoint,
IssueActivityEndpoint,
IssueCommentViewSet,
TimeLineIssueViewSet,
IssuePropertyViewSet,
LabelViewSet,
BulkDeleteIssuesEndpoint,
UserWorkSpaceIssues,
SubIssuesEndpoint,
IssueLinkViewSet,
BulkCreateIssueLabelsEndpoint,
IssueAttachmentEndpoint,
IssueArchiveViewSet,
IssueSubscriberViewSet,
IssueCommentPublicViewSet,
CommentReactionViewSet,
IssueReactionViewSet,
IssueReactionPublicViewSet,
CommentReactionPublicViewSet,
IssueVotePublicViewSet,
IssueRelationViewSet,
IssueRetrievePublicEndpoint,
ProjectIssuesPublicEndpoint,
IssueDraftViewSet,
)
from .auth_extended import (
@@ -71,6 +109,64 @@ from .authentication import (
MagicSignInGenerateEndpoint,
)
from .module import ModuleViewSet, ModuleIssueViewSet
from .module import (
ModuleViewSet,
ModuleIssueViewSet,
ModuleLinkViewSet,
ModuleFavoriteViewSet,
)
from .api_token import ApiTokenEndpoint
from .api_token import ApiTokenEndpoint
from .integration import (
WorkspaceIntegrationViewSet,
IntegrationViewSet,
GithubIssueSyncViewSet,
GithubRepositorySyncViewSet,
GithubCommentSyncViewSet,
GithubRepositoriesEndpoint,
BulkCreateGithubIssueSyncEndpoint,
SlackProjectSyncViewSet,
)
from .importer import (
ServiceIssueImportSummaryEndpoint,
ImportServiceEndpoint,
UpdateServiceImportStatusEndpoint,
BulkImportIssuesEndpoint,
BulkImportModulesEndpoint,
)
from .page import (
PageViewSet,
PageBlockViewSet,
PageFavoriteViewSet,
CreateIssueFromPageBlockEndpoint,
)
from .search import GlobalSearchEndpoint, IssueSearchEndpoint
from .gpt import GPTIntegrationEndpoint
from .estimate import (
ProjectEstimatePointEndpoint,
BulkEstimatePointEndpoint,
)
from .release import ReleaseNotesEndpoint
from .inbox import InboxViewSet, InboxIssueViewSet, InboxIssuePublicViewSet
from .analytic import (
AnalyticsEndpoint,
AnalyticViewViewset,
SavedAnalyticEndpoint,
ExportAnalyticsEndpoint,
DefaultAnalyticsEndpoint,
)
from .notification import NotificationViewSet, UnreadNotificationEndpoint, MarkAllReadNotificationViewSet
from .exporter import ExportIssuesEndpoint

View File

@@ -0,0 +1,297 @@
# Django imports
from django.db.models import (
Count,
Sum,
F,
Q
)
from django.db.models.functions import ExtractMonth
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from sentry_sdk import capture_exception
# Module imports
from plane.api.views import BaseAPIView, BaseViewSet
from plane.api.permissions import WorkSpaceAdminPermission
from plane.db.models import Issue, AnalyticView, Workspace, State, Label
from plane.api.serializers import AnalyticViewSerializer
from plane.utils.analytics_plot import build_graph_plot
from plane.bgtasks.analytic_plot_export import analytic_export_task
from plane.utils.issue_filters import issue_filters
class AnalyticsEndpoint(BaseAPIView):
permission_classes = [
WorkSpaceAdminPermission,
]
def get(self, request, slug):
try:
x_axis = request.GET.get("x_axis", False)
y_axis = request.GET.get("y_axis", False)
if not x_axis or not y_axis:
return Response(
{"error": "x-axis and y-axis dimensions are required"},
status=status.HTTP_400_BAD_REQUEST,
)
segment = request.GET.get("segment", False)
filters = issue_filters(request.GET, "GET")
queryset = Issue.issue_objects.filter(workspace__slug=slug, **filters)
total_issues = queryset.count()
distribution = build_graph_plot(
queryset=queryset, x_axis=x_axis, y_axis=y_axis, segment=segment
)
colors = dict()
if x_axis in ["state__name", "state__group"] or segment in [
"state__name",
"state__group",
]:
if x_axis in ["state__name", "state__group"]:
key = "name" if x_axis == "state__name" else "group"
else:
key = "name" if segment == "state__name" else "group"
colors = (
State.objects.filter(
~Q(name="Triage"),
workspace__slug=slug, project_id__in=filters.get("project__in")
).values(key, "color")
if filters.get("project__in", False)
else State.objects.filter(~Q(name="Triage"), workspace__slug=slug).values(key, "color")
)
if x_axis in ["labels__name"] or segment in ["labels__name"]:
colors = (
Label.objects.filter(
workspace__slug=slug, project_id__in=filters.get("project__in")
).values("name", "color")
if filters.get("project__in", False)
else Label.objects.filter(workspace__slug=slug).values(
"name", "color"
)
)
assignee_details = {}
if x_axis in ["assignees__id"] or segment in ["assignees__id"]:
assignee_details = (
Issue.issue_objects.filter(workspace__slug=slug, **filters, assignees__avatar__isnull=False)
.order_by("assignees__id")
.distinct("assignees__id")
.values("assignees__avatar", "assignees__display_name", "assignees__first_name", "assignees__last_name", "assignees__id")
)
return Response(
{
"total": total_issues,
"distribution": distribution,
"extras": {"colors": colors, "assignee_details": assignee_details},
},
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class AnalyticViewViewset(BaseViewSet):
permission_classes = [
WorkSpaceAdminPermission,
]
model = AnalyticView
serializer_class = AnalyticViewSerializer
def perform_create(self, serializer):
workspace = Workspace.objects.get(slug=self.kwargs.get("slug"))
serializer.save(workspace_id=workspace.id)
def get_queryset(self):
return self.filter_queryset(
super().get_queryset().filter(workspace__slug=self.kwargs.get("slug"))
)
class SavedAnalyticEndpoint(BaseAPIView):
permission_classes = [
WorkSpaceAdminPermission,
]
def get(self, request, slug, analytic_id):
try:
analytic_view = AnalyticView.objects.get(
pk=analytic_id, workspace__slug=slug
)
filter = analytic_view.query
queryset = Issue.issue_objects.filter(**filter)
x_axis = analytic_view.query_dict.get("x_axis", False)
y_axis = analytic_view.query_dict.get("y_axis", False)
if not x_axis or not y_axis:
return Response(
{"error": "x-axis and y-axis dimensions are required"},
status=status.HTTP_400_BAD_REQUEST,
)
segment = request.GET.get("segment", False)
distribution = build_graph_plot(
queryset=queryset, x_axis=x_axis, y_axis=y_axis, segment=segment
)
total_issues = queryset.count()
return Response(
{"total": total_issues, "distribution": distribution},
status=status.HTTP_200_OK,
)
except AnalyticView.DoesNotExist:
return Response(
{"error": "Analytic View Does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class ExportAnalyticsEndpoint(BaseAPIView):
permission_classes = [
WorkSpaceAdminPermission,
]
def post(self, request, slug):
try:
x_axis = request.data.get("x_axis", False)
y_axis = request.data.get("y_axis", False)
if not x_axis or not y_axis:
return Response(
{"error": "x-axis and y-axis dimensions are required"},
status=status.HTTP_400_BAD_REQUEST,
)
analytic_export_task.delay(
email=request.user.email, data=request.data, slug=slug
)
return Response(
{
"message": f"Once the export is ready it will be emailed to you at {str(request.user.email)}"
},
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class DefaultAnalyticsEndpoint(BaseAPIView):
permission_classes = [
WorkSpaceAdminPermission,
]
def get(self, request, slug):
try:
filters = issue_filters(request.GET, "GET")
queryset = Issue.issue_objects.filter(workspace__slug=slug, **filters)
total_issues = queryset.count()
total_issues_classified = (
queryset.annotate(state_group=F("state__group"))
.values("state_group")
.annotate(state_count=Count("state_group"))
.order_by("state_group")
)
open_issues = queryset.filter(
state__group__in=["backlog", "unstarted", "started"]
).count()
open_issues_classified = (
queryset.filter(state__group__in=["backlog", "unstarted", "started"])
.annotate(state_group=F("state__group"))
.values("state_group")
.annotate(state_count=Count("state_group"))
.order_by("state_group")
)
issue_completed_month_wise = (
queryset.filter(completed_at__isnull=False)
.annotate(month=ExtractMonth("completed_at"))
.values("month")
.annotate(count=Count("*"))
.order_by("month")
)
most_issue_created_user = (
queryset.exclude(created_by=None)
.values("created_by__first_name", "created_by__last_name", "created_by__avatar", "created_by__display_name", "created_by__id")
.annotate(count=Count("id"))
.order_by("-count")
)[:5]
most_issue_closed_user = (
queryset.filter(completed_at__isnull=False, assignees__isnull=False)
.values("assignees__first_name", "assignees__last_name", "assignees__avatar", "assignees__display_name", "assignees__id")
.annotate(count=Count("id"))
.order_by("-count")
)[:5]
pending_issue_user = (
queryset.filter(completed_at__isnull=True)
.values("assignees__first_name", "assignees__last_name", "assignees__avatar", "assignees__display_name", "assignees__id")
.annotate(count=Count("id"))
.order_by("-count")
)
open_estimate_sum = (
queryset.filter(
state__group__in=["backlog", "unstarted", "started"]
).aggregate(open_estimate_sum=Sum("estimate_point"))
)["open_estimate_sum"]
print(open_estimate_sum)
total_estimate_sum = queryset.aggregate(
total_estimate_sum=Sum("estimate_point")
)["total_estimate_sum"]
return Response(
{
"total_issues": total_issues,
"total_issues_classified": total_issues_classified,
"open_issues": open_issues,
"open_issues_classified": open_issues_classified,
"issue_completed_month_wise": issue_completed_month_wise,
"most_issue_created_user": most_issue_created_user,
"most_issue_closed_user": most_issue_closed_user,
"pending_issue_user": pending_issue_user,
"open_estimate_sum": open_estimate_sum,
"total_estimate_sum": total_estimate_sum,
},
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -15,16 +15,24 @@ from plane.api.serializers import APITokenSerializer
class ApiTokenEndpoint(BaseAPIView):
def post(self, request):
try:
label = request.data.get("label", str(uuid4().hex))
workspace = request.data.get("workspace", False)
if not workspace:
return Response(
{"error": "Workspace is required"}, status=status.HTTP_200_OK
)
api_token = APIToken.objects.create(
label=label,
user=request.user,
label=label, user=request.user, workspace_id=workspace
)
serializer = APITokenSerializer(api_token)
return Response(serializer.data, status=status.HTTP_201_CREATED)
# Token will be only vissible while creating
return Response(
{"api_token": serializer.data, "token": api_token.token},
status=status.HTTP_201_CREATED,
)
except Exception as e:
capture_exception(e)

View File

@@ -3,38 +3,99 @@ from rest_framework import status
from rest_framework.response import Response
from rest_framework.parsers import MultiPartParser, FormParser
from sentry_sdk import capture_exception
from django.conf import settings
# Module imports
from .base import BaseAPIView
from plane.db.models import FileAsset
from plane.db.models import FileAsset, Workspace
from plane.api.serializers import FileAssetSerializer
class FileAssetEndpoint(BaseAPIView):
parser_classes = (MultiPartParser, FormParser)
"""
A viewset for viewing and editing task instances.
"""
def get(self, request, slug):
files = FileAsset.objects.filter(workspace__slug=slug)
serializer = FileAssetSerializer(files, context={"request": request}, many=True)
return Response(serializer.data)
def get(self, request, workspace_id, asset_key):
try:
asset_key = str(workspace_id) + "/" + asset_key
files = FileAsset.objects.filter(asset=asset_key)
if files.exists():
serializer = FileAssetSerializer(files, context={"request": request}, many=True)
return Response({"data": serializer.data, "status": True}, status=status.HTTP_200_OK)
else:
return Response({"error": "Asset key does not exist", "status": False}, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def post(self, request, slug):
try:
serializer = FileAssetSerializer(data=request.data)
if serializer.is_valid():
# Get the workspace
workspace = Workspace.objects.get(slug=slug)
serializer.save(workspace_id=workspace.id)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Workspace.DoesNotExist:
return Response({"error": "Workspace does not exist"}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
if request.user.last_workspace_id is None:
return Response(
{"error": "Workspace id is required"},
status=status.HTTP_400_BAD_REQUEST,
)
def delete(self, request, workspace_id, asset_key):
try:
asset_key = str(workspace_id) + "/" + asset_key
file_asset = FileAsset.objects.get(asset=asset_key)
# Delete the file from storage
file_asset.asset.delete(save=False)
# Delete the file object
file_asset.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except FileAsset.DoesNotExist:
return Response(
{"error": "File Asset doesn't exist"}, status=status.HTTP_404_NOT_FOUND
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
serializer.save(workspace_id=request.user.last_workspace_id)
class UserAssetsEndpoint(BaseAPIView):
parser_classes = (MultiPartParser, FormParser)
def get(self, request, asset_key):
try:
files = FileAsset.objects.filter(asset=asset_key, created_by=request.user)
if files.exists():
serializer = FileAssetSerializer(files, context={"request": request})
return Response({"data": serializer.data, "status": True}, status=status.HTTP_200_OK)
else:
return Response({"error": "Asset key does not exist", "status": False}, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def post(self, request):
try:
serializer = FileAssetSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
@@ -43,3 +104,22 @@ class FileAssetEndpoint(BaseAPIView):
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def delete(self, request, asset_key):
try:
file_asset = FileAsset.objects.get(asset=asset_key, created_by=request.user)
# Delete the file from storage
file_asset.asset.delete(save=False)
# Delete the file object
file_asset.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except FileAsset.DoesNotExist:
return Response(
{"error": "File Asset doesn't exist"}, status=status.HTTP_404_NOT_FOUND
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -22,7 +22,7 @@ from sentry_sdk import capture_exception
## Module imports
from . import BaseAPIView
from plane.api.serializers.people import (
from plane.api.serializers import (
ChangePasswordSerializer,
ResetPasswordSerializer,
)
@@ -84,7 +84,7 @@ class ForgotPasswordEndpoint(BaseAPIView):
)
return Response(
{"messgae": "Check your email to reset your password"},
{"message": "Check your email to reset your password"},
status=status.HTTP_200_OK,
)
return Response(

View File

@@ -3,12 +3,14 @@ import uuid
import random
import string
import json
import requests
# Django imports
from django.utils import timezone
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.conf import settings
from django.contrib.auth.hashers import make_password
# Third party imports
from rest_framework.response import Response
@@ -35,11 +37,17 @@ def get_tokens_for_user(user):
class SignUpEndpoint(BaseAPIView):
permission_classes = (AllowAny,)
def post(self, request):
try:
if not settings.ENABLE_SIGNUP:
return Response(
{
"error": "New account creation is disabled. Please contact your site administrator"
},
status=status.HTTP_400_BAD_REQUEST,
)
email = request.data.get("email", False)
password = request.data.get("password", False)
@@ -61,15 +69,14 @@ class SignUpEndpoint(BaseAPIView):
status=status.HTTP_400_BAD_REQUEST,
)
user = User.objects.filter(email=email).first()
if user is not None:
# Check if the user already exists
if User.objects.filter(email=email).exists():
return Response(
{"error": "Email ID is already taken"},
{"error": "User with this email already exists"},
status=status.HTTP_400_BAD_REQUEST,
)
user = User.objects.create(email=email)
user = User.objects.create(email=email, username=uuid.uuid4().hex)
user.set_password(password)
# settings last actives for the user
@@ -90,14 +97,34 @@ class SignUpEndpoint(BaseAPIView):
"user": serialized_user,
}
# Send Analytics
if settings.ANALYTICS_BASE_API:
_ = requests.post(
settings.ANALYTICS_BASE_API,
headers={
"Content-Type": "application/json",
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
},
json={
"event_id": uuid.uuid4().hex,
"event_data": {
"medium": "email",
},
"user": {"email": email, "id": str(user.id)},
"device_ctx": {
"ip": request.META.get("REMOTE_ADDR"),
"user_agent": request.META.get("HTTP_USER_AGENT"),
},
"event_type": "SIGN_UP",
},
)
return Response(data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{
"error": "Something went wrong. Please try again later or contact the support team."
},
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
@@ -127,8 +154,17 @@ class SignInEndpoint(BaseAPIView):
status=status.HTTP_400_BAD_REQUEST,
)
user = User.objects.get(email=email)
user = User.objects.filter(email=email).first()
if user is None:
return Response(
{
"error": "Sorry, we could not find a user with the provided credentials. Please try again."
},
status=status.HTTP_403_FORBIDDEN,
)
# Sign up Process
if not user.check_password(password):
return Response(
{
@@ -155,7 +191,27 @@ class SignInEndpoint(BaseAPIView):
user.save()
access_token, refresh_token = get_tokens_for_user(user)
# Send Analytics
if settings.ANALYTICS_BASE_API:
_ = requests.post(
settings.ANALYTICS_BASE_API,
headers={
"Content-Type": "application/json",
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
},
json={
"event_id": uuid.uuid4().hex,
"event_data": {
"medium": "email",
},
"user": {"email": email, "id": str(user.id)},
"device_ctx": {
"ip": request.META.get("REMOTE_ADDR"),
"user_agent": request.META.get("HTTP_USER_AGENT"),
},
"event_type": "SIGN_IN",
},
)
data = {
"access_token": access_token,
"refresh_token": refresh_token,
@@ -164,13 +220,6 @@ class SignInEndpoint(BaseAPIView):
return Response(data, status=status.HTTP_200_OK)
except User.DoesNotExist:
return Response(
{
"error": "Sorry, we could not find a user with the provided credentials. Please try again."
},
status=status.HTTP_403_FORBIDDEN,
)
except Exception as e:
capture_exception(e)
return Response(
@@ -216,14 +265,12 @@ class SignOutEndpoint(BaseAPIView):
class MagicSignInGenerateEndpoint(BaseAPIView):
permission_classes = [
AllowAny,
]
def post(self, request):
try:
email = request.data.get("email", False)
if not email:
@@ -232,6 +279,8 @@ class MagicSignInGenerateEndpoint(BaseAPIView):
status=status.HTTP_400_BAD_REQUEST,
)
# Clean up
email = email.strip().lower()
validate_email(email)
## Generate a random token
@@ -269,7 +318,6 @@ class MagicSignInGenerateEndpoint(BaseAPIView):
ri.set(key, json.dumps(value), ex=expiry)
else:
value = {"current_attempt": 0, "email": email, "token": token}
expiry = 600
@@ -293,16 +341,14 @@ class MagicSignInGenerateEndpoint(BaseAPIView):
class MagicSignInEndpoint(BaseAPIView):
permission_classes = [
AllowAny,
]
def post(self, request):
try:
user_token = request.data.get("token", "").strip().lower()
key = request.data.get("key", False)
user_token = request.data.get("token", "").strip()
key = request.data.get("key", False).strip().lower()
if not key or user_token == "":
return Response(
@@ -313,20 +359,67 @@ class MagicSignInEndpoint(BaseAPIView):
ri = redis_instance()
if ri.exists(key):
data = json.loads(ri.get(key))
token = data["token"]
email = data["email"]
if str(token) == str(user_token):
if User.objects.filter(email=email).exists():
user = User.objects.get(email=email)
# Send event to Jitsu for tracking
if settings.ANALYTICS_BASE_API:
_ = requests.post(
settings.ANALYTICS_BASE_API,
headers={
"Content-Type": "application/json",
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
},
json={
"event_id": uuid.uuid4().hex,
"event_data": {
"medium": "code",
},
"user": {"email": email, "id": str(user.id)},
"device_ctx": {
"ip": request.META.get("REMOTE_ADDR"),
"user_agent": request.META.get(
"HTTP_USER_AGENT"
),
},
"event_type": "SIGN_IN",
},
)
else:
user = User.objects.create(
email=email, username=uuid.uuid4().hex
email=email,
username=uuid.uuid4().hex,
password=make_password(uuid.uuid4().hex),
is_password_autoset=True,
)
# Send event to Jitsu for tracking
if settings.ANALYTICS_BASE_API:
_ = requests.post(
settings.ANALYTICS_BASE_API,
headers={
"Content-Type": "application/json",
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
},
json={
"event_id": uuid.uuid4().hex,
"event_data": {
"medium": "code",
},
"user": {"email": email, "id": str(user.id)},
"device_ctx": {
"ip": request.META.get("REMOTE_ADDR"),
"user_agent": request.META.get(
"HTTP_USER_AGENT"
),
},
"event_type": "SIGN_UP",
},
)
user.last_active = timezone.now()
user.last_login_time = timezone.now()

View File

@@ -1,24 +1,41 @@
# Python imports
import zoneinfo
# Django imports
from django.urls import resolve
from django.conf import settings
from django.utils import timezone
# Third part imports
from rest_framework import status
from rest_framework.viewsets import ModelViewSet
from rest_framework.exceptions import APIException
from rest_framework.views import APIView
from rest_framework.filters import SearchFilter
from rest_framework.permissions import IsAuthenticated
from rest_framework.exceptions import NotFound
from sentry_sdk import capture_exception
from django_filters.rest_framework import DjangoFilterBackend
# Module imports
from plane.db.models import Workspace, Project
from plane.utils.paginator import BasePaginator
class BaseViewSet(ModelViewSet, BasePaginator):
class TimezoneMixin:
"""
This enables timezone conversion according
to the user set timezone
"""
def initial(self, request, *args, **kwargs):
super().initial(request, *args, **kwargs)
if request.user.is_authenticated:
timezone.activate(zoneinfo.ZoneInfo(request.user.user_timezone))
else:
timezone.deactivate()
class BaseViewSet(TimezoneMixin, ModelViewSet, BasePaginator):
model = None
@@ -39,7 +56,7 @@ class BaseViewSet(ModelViewSet, BasePaginator):
try:
return self.model.objects.all()
except Exception as e:
print(e)
capture_exception(e)
raise APIException("Please check the view", status.HTTP_400_BAD_REQUEST)
def dispatch(self, request, *args, **kwargs):
@@ -67,7 +84,7 @@ class BaseViewSet(ModelViewSet, BasePaginator):
return self.kwargs.get("pk", None)
class BaseAPIView(APIView, BasePaginator):
class BaseAPIView(TimezoneMixin, APIView, BasePaginator):
permission_classes = [
IsAuthenticated,

View File

@@ -1,5 +1,23 @@
# Python imports
import json
# Django imports
from django.db.models import OuterRef, Func, F
from django.db import IntegrityError
from django.db.models import (
OuterRef,
Func,
F,
Q,
Exists,
OuterRef,
Count,
Prefetch,
Sum,
)
from django.core import serializers
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.decorators.gzip import gzip_page
# Third party imports
from rest_framework.response import Response
@@ -7,14 +25,32 @@ from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from . import BaseViewSet
from plane.api.serializers import CycleSerializer, CycleIssueSerializer
from . import BaseViewSet, BaseAPIView
from plane.api.serializers import (
CycleSerializer,
CycleIssueSerializer,
CycleFavoriteSerializer,
IssueStateSerializer,
CycleWriteSerializer,
)
from plane.api.permissions import ProjectEntityPermission
from plane.db.models import Cycle, CycleIssue, Issue
from plane.db.models import (
User,
Cycle,
CycleIssue,
Issue,
CycleFavorite,
IssueLink,
IssueAttachment,
Label,
)
from plane.bgtasks.issue_activites_task import issue_activity
from plane.utils.grouper import group_results
from plane.utils.issue_filters import issue_filters
from plane.utils.analytics_plot import burndown_plot
class CycleViewSet(BaseViewSet):
serializer_class = CycleSerializer
model = Cycle
permission_classes = [
@@ -26,7 +62,36 @@ class CycleViewSet(BaseViewSet):
project_id=self.kwargs.get("project_id"), owned_by=self.request.user
)
def perform_destroy(self, instance):
cycle_issues = list(
CycleIssue.objects.filter(cycle_id=self.kwargs.get("pk")).values_list(
"issue", flat=True
)
)
issue_activity.delay(
type="cycle.activity.deleted",
requested_data=json.dumps(
{
"cycle_id": str(self.kwargs.get("pk")),
"issues": [str(issue_id) for issue_id in cycle_issues],
}
),
actor_id=str(self.request.user.id),
issue_id=str(self.kwargs.get("pk", None)),
project_id=str(self.kwargs.get("project_id", None)),
current_instance=None,
epoch=int(timezone.now().timestamp())
)
return super().perform_destroy(instance)
def get_queryset(self):
subquery = CycleFavorite.objects.filter(
user=self.request.user,
cycle_id=OuterRef("pk"),
project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"),
)
return self.filter_queryset(
super()
.get_queryset()
@@ -36,12 +101,450 @@ class CycleViewSet(BaseViewSet):
.select_related("project")
.select_related("workspace")
.select_related("owned_by")
.annotate(is_favorite=Exists(subquery))
.annotate(
total_issues=Count(
"issue_cycle",
filter=Q(
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(
completed_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(
issue_cycle__issue__state__group="completed",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(
cancelled_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(
issue_cycle__issue__state__group="cancelled",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(
started_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(
issue_cycle__issue__state__group="started",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(
unstarted_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(
issue_cycle__issue__state__group="unstarted",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(
backlog_issues=Count(
"issue_cycle__issue__state__group",
filter=Q(
issue_cycle__issue__state__group="backlog",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(total_estimates=Sum("issue_cycle__issue__estimate_point"))
.annotate(
completed_estimates=Sum(
"issue_cycle__issue__estimate_point",
filter=Q(
issue_cycle__issue__state__group="completed",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.annotate(
started_estimates=Sum(
"issue_cycle__issue__estimate_point",
filter=Q(
issue_cycle__issue__state__group="started",
issue_cycle__issue__archived_at__isnull=True,
issue_cycle__issue__is_draft=False,
),
)
)
.prefetch_related(
Prefetch(
"issue_cycle__issue__assignees",
queryset=User.objects.only("avatar", "first_name", "id").distinct(),
)
)
.prefetch_related(
Prefetch(
"issue_cycle__issue__labels",
queryset=Label.objects.only("name", "color", "id").distinct(),
)
)
.order_by("-is_favorite", "name")
.distinct()
)
def list(self, request, slug, project_id):
try:
queryset = self.get_queryset()
cycle_view = request.GET.get("cycle_view", "all")
order_by = request.GET.get("order_by", "sort_order")
queryset = queryset.order_by(order_by)
# All Cycles
if cycle_view == "all":
return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK
)
# Current Cycle
if cycle_view == "current":
queryset = queryset.filter(
start_date__lte=timezone.now(),
end_date__gte=timezone.now(),
)
data = CycleSerializer(queryset, many=True).data
if len(data):
assignee_distribution = (
Issue.objects.filter(
issue_cycle__cycle_id=data[0]["id"],
workspace__slug=slug,
project_id=project_id,
)
.annotate(display_name=F("assignees__display_name"))
.annotate(assignee_id=F("assignees__id"))
.annotate(avatar=F("assignees__avatar"))
.values("display_name", "assignee_id", "avatar")
.annotate(
total_issues=Count(
"assignee_id",
filter=Q(archived_at__isnull=True, is_draft=False),
),
)
.annotate(
completed_issues=Count(
"assignee_id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"assignee_id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("display_name")
)
label_distribution = (
Issue.objects.filter(
issue_cycle__cycle_id=data[0]["id"],
workspace__slug=slug,
project_id=project_id,
)
.annotate(label_name=F("labels__name"))
.annotate(color=F("labels__color"))
.annotate(label_id=F("labels__id"))
.values("label_name", "color", "label_id")
.annotate(
total_issues=Count(
"label_id",
filter=Q(archived_at__isnull=True, is_draft=False),
)
)
.annotate(
completed_issues=Count(
"label_id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"label_id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("label_name")
)
data[0]["distribution"] = {
"assignees": assignee_distribution,
"labels": label_distribution,
"completion_chart": {},
}
if data[0]["start_date"] and data[0]["end_date"]:
data[0]["distribution"]["completion_chart"] = burndown_plot(
queryset=queryset.first(),
slug=slug,
project_id=project_id,
cycle_id=data[0]["id"],
)
return Response(data, status=status.HTTP_200_OK)
# Upcoming Cycles
if cycle_view == "upcoming":
queryset = queryset.filter(start_date__gt=timezone.now())
return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK
)
# Completed Cycles
if cycle_view == "completed":
queryset = queryset.filter(end_date__lt=timezone.now())
return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK
)
# Draft Cycles
if cycle_view == "draft":
queryset = queryset.filter(
end_date=None,
start_date=None,
)
return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK
)
# Incomplete Cycles
if cycle_view == "incomplete":
queryset = queryset.filter(
Q(end_date__gte=timezone.now().date()) | Q(end_date__isnull=True),
)
return Response(
CycleSerializer(queryset, many=True).data, status=status.HTTP_200_OK
)
return Response(
{"error": "No matching view found"}, status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def create(self, request, slug, project_id):
try:
if (
request.data.get("start_date", None) is None
and request.data.get("end_date", None) is None
) or (
request.data.get("start_date", None) is not None
and request.data.get("end_date", None) is not None
):
serializer = CycleSerializer(data=request.data)
if serializer.is_valid():
serializer.save(
project_id=project_id,
owned_by=request.user,
)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
return Response(
{
"error": "Both start date and end date are either required or are to be null"
},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def partial_update(self, request, slug, project_id, pk):
try:
cycle = Cycle.objects.get(
workspace__slug=slug, project_id=project_id, pk=pk
)
request_data = request.data
if cycle.end_date is not None and cycle.end_date < timezone.now().date():
if "sort_order" in request_data:
# Can only change sort order
request_data = {
"sort_order": request_data.get("sort_order", cycle.sort_order)
}
else:
return Response(
{
"error": "The Cycle has already been completed so it cannot be edited"
},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = CycleWriteSerializer(cycle, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Cycle.DoesNotExist:
return Response(
{"error": "Cycle does not exist"}, status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def retrieve(self, request, slug, project_id, pk):
try:
queryset = self.get_queryset().get(pk=pk)
# Assignee Distribution
assignee_distribution = (
Issue.objects.filter(
issue_cycle__cycle_id=pk,
workspace__slug=slug,
project_id=project_id,
)
.annotate(first_name=F("assignees__first_name"))
.annotate(last_name=F("assignees__last_name"))
.annotate(assignee_id=F("assignees__id"))
.annotate(avatar=F("assignees__avatar"))
.annotate(display_name=F("assignees__display_name"))
.values(
"first_name", "last_name", "assignee_id", "avatar", "display_name"
)
.annotate(
total_issues=Count(
"assignee_id",
filter=Q(archived_at__isnull=True, is_draft=False),
),
)
.annotate(
completed_issues=Count(
"assignee_id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"assignee_id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("first_name", "last_name")
)
# Label Distribution
label_distribution = (
Issue.objects.filter(
issue_cycle__cycle_id=pk,
workspace__slug=slug,
project_id=project_id,
)
.annotate(label_name=F("labels__name"))
.annotate(color=F("labels__color"))
.annotate(label_id=F("labels__id"))
.values("label_name", "color", "label_id")
.annotate(
total_issues=Count(
"label_id",
filter=Q(archived_at__isnull=True, is_draft=False),
),
)
.annotate(
completed_issues=Count(
"label_id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"label_id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("label_name")
)
data = CycleSerializer(queryset).data
data["distribution"] = {
"assignees": assignee_distribution,
"labels": label_distribution,
"completion_chart": {},
}
if queryset.start_date and queryset.end_date:
data["distribution"]["completion_chart"] = burndown_plot(
queryset=queryset, slug=slug, project_id=project_id, cycle_id=pk
)
return Response(
data,
status=status.HTTP_200_OK,
)
except Cycle.DoesNotExist:
return Response(
{"error": "Cycle Does not exists"}, status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class CycleIssueViewSet(BaseViewSet):
serializer_class = CycleIssueSerializer
model = CycleIssue
@@ -49,18 +552,40 @@ class CycleIssueViewSet(BaseViewSet):
ProjectEntityPermission,
]
filterset_fields = [
"issue__labels__id",
"issue__assignees__id",
]
def perform_create(self, serializer):
serializer.save(
project_id=self.kwargs.get("project_id"),
cycle_id=self.kwargs.get("cycle_id"),
)
def perform_destroy(self, instance):
issue_activity.delay(
type="cycle.activity.deleted",
requested_data=json.dumps(
{
"cycle_id": str(self.kwargs.get("cycle_id")),
"issues": [str(instance.issue_id)],
}
),
actor_id=str(self.request.user.id),
issue_id=str(self.kwargs.get("pk", None)),
project_id=str(self.kwargs.get("project_id", None)),
current_instance=None,
epoch=int(timezone.now().timestamp())
)
return super().perform_destroy(instance)
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.annotate(
sub_issues_count=Issue.objects.filter(parent=OuterRef("issue_id"))
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("issue_id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
@@ -77,9 +602,75 @@ class CycleIssueViewSet(BaseViewSet):
.distinct()
)
@method_decorator(gzip_page)
def list(self, request, slug, project_id, cycle_id):
try:
order_by = request.GET.get("order_by", "created_at")
group_by = request.GET.get("group_by", False)
sub_group_by = request.GET.get("sub_group_by", False)
filters = issue_filters(request.query_params, "GET")
issues = (
Issue.issue_objects.filter(issue_cycle__cycle_id=cycle_id)
.annotate(
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(bridge_id=F("issue_cycle__id"))
.filter(project_id=project_id)
.filter(workspace__slug=slug)
.select_related("project")
.select_related("workspace")
.select_related("state")
.select_related("parent")
.prefetch_related("assignees")
.prefetch_related("labels")
.order_by(order_by)
.filter(**filters)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
)
issues_data = IssueStateSerializer(issues, many=True).data
if sub_group_by and sub_group_by == group_by:
return Response(
{"error": "Group by and sub group by cannot be same"},
status=status.HTTP_400_BAD_REQUEST,
)
if group_by:
return Response(
group_results(issues_data, group_by, sub_group_by),
status=status.HTTP_200_OK,
)
return Response(
issues_data,
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def create(self, request, slug, project_id, cycle_id):
try:
issues = request.data.get("issues", [])
if not len(issues):
@@ -91,29 +682,84 @@ class CycleIssueViewSet(BaseViewSet):
workspace__slug=slug, project_id=project_id, pk=cycle_id
)
issues = Issue.objects.filter(
pk__in=issues, workspace__slug=slug, project_id=project_id
)
if cycle.end_date is not None and cycle.end_date < timezone.now().date():
return Response(
{
"error": "The Cycle has already been completed so no new issues can be added"
},
status=status.HTTP_400_BAD_REQUEST,
)
# Delete old records in order to maintain the database integrity
CycleIssue.objects.filter(issue_id__in=issues).delete()
# Get all CycleIssues already created
cycle_issues = list(CycleIssue.objects.filter(issue_id__in=issues))
update_cycle_issue_activity = []
record_to_create = []
records_to_update = []
for issue in issues:
cycle_issue = [
cycle_issue
for cycle_issue in cycle_issues
if str(cycle_issue.issue_id) in issues
]
# Update only when cycle changes
if len(cycle_issue):
if cycle_issue[0].cycle_id != cycle_id:
update_cycle_issue_activity.append(
{
"old_cycle_id": str(cycle_issue[0].cycle_id),
"new_cycle_id": str(cycle_id),
"issue_id": str(cycle_issue[0].issue_id),
}
)
cycle_issue[0].cycle_id = cycle_id
records_to_update.append(cycle_issue[0])
else:
record_to_create.append(
CycleIssue(
project_id=project_id,
workspace=cycle.workspace,
created_by=request.user,
updated_by=request.user,
cycle=cycle,
issue_id=issue,
)
)
CycleIssue.objects.bulk_create(
[
CycleIssue(
project_id=project_id,
workspace=cycle.workspace,
created_by=request.user,
updated_by=request.user,
cycle=cycle,
issue=issue,
)
for issue in issues
],
record_to_create,
batch_size=10,
ignore_conflicts=True,
)
return Response({"message": "Success"}, status=status.HTTP_200_OK)
CycleIssue.objects.bulk_update(
records_to_update,
["cycle"],
batch_size=10,
)
# Capture Issue Activity
issue_activity.delay(
type="cycle.activity.created",
requested_data=json.dumps({"cycles_list": issues}),
actor_id=str(self.request.user.id),
issue_id=str(self.kwargs.get("pk", None)),
project_id=str(self.kwargs.get("project_id", None)),
current_instance=json.dumps(
{
"updated_cycle_issues": update_cycle_issue_activity,
"created_cycle_issues": serializers.serialize(
"json", record_to_create
),
}
),
epoch=int(timezone.now().timestamp())
)
# Return all Cycle Issues
return Response(
CycleIssueSerializer(self.get_queryset(), many=True).data,
status=status.HTTP_200_OK,
)
except Cycle.DoesNotExist:
return Response(
@@ -125,3 +771,168 @@ class CycleIssueViewSet(BaseViewSet):
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class CycleDateCheckEndpoint(BaseAPIView):
permission_classes = [
ProjectEntityPermission,
]
def post(self, request, slug, project_id):
try:
start_date = request.data.get("start_date", False)
end_date = request.data.get("end_date", False)
cycle_id = request.data.get("cycle_id")
if not start_date or not end_date:
return Response(
{"error": "Start date and end date both are required"},
status=status.HTTP_400_BAD_REQUEST,
)
cycles = Cycle.objects.filter(
Q(workspace__slug=slug)
& Q(project_id=project_id)
& (
Q(start_date__lte=start_date, end_date__gte=start_date)
| Q(start_date__lte=end_date, end_date__gte=end_date)
| Q(start_date__gte=start_date, end_date__lte=end_date)
)
).exclude(pk=cycle_id)
if cycles.exists():
return Response(
{
"error": "You have a cycle already on the given dates, if you want to create your draft cycle you can do that by removing dates",
"status": False,
}
)
else:
return Response({"status": True}, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class CycleFavoriteViewSet(BaseViewSet):
serializer_class = CycleFavoriteSerializer
model = CycleFavorite
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(user=self.request.user)
.select_related("cycle", "cycle__owned_by")
)
def create(self, request, slug, project_id):
try:
serializer = CycleFavoriteSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user, project_id=project_id)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except IntegrityError as e:
if "already exists" in str(e):
return Response(
{"error": "The cycle is already added to favorites"},
status=status.HTTP_410_GONE,
)
else:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, cycle_id):
try:
cycle_favorite = CycleFavorite.objects.get(
project=project_id,
user=request.user,
workspace__slug=slug,
cycle_id=cycle_id,
)
cycle_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except CycleFavorite.DoesNotExist:
return Response(
{"error": "Cycle is not in favorites"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class TransferCycleIssueEndpoint(BaseAPIView):
permission_classes = [
ProjectEntityPermission,
]
def post(self, request, slug, project_id, cycle_id):
try:
new_cycle_id = request.data.get("new_cycle_id", False)
if not new_cycle_id:
return Response(
{"error": "New Cycle Id is required"},
status=status.HTTP_400_BAD_REQUEST,
)
new_cycle = Cycle.objects.get(
workspace__slug=slug, project_id=project_id, pk=new_cycle_id
)
if (
new_cycle.end_date is not None
and new_cycle.end_date < timezone.now().date()
):
return Response(
{
"error": "The cycle where the issues are transferred is already completed"
},
status=status.HTTP_400_BAD_REQUEST,
)
cycle_issues = CycleIssue.objects.filter(
cycle_id=cycle_id,
project_id=project_id,
workspace__slug=slug,
issue__state__group__in=["backlog", "unstarted", "started"],
)
updated_cycles = []
for cycle_issue in cycle_issues:
cycle_issue.cycle_id = new_cycle_id
updated_cycles.append(cycle_issue)
cycle_issues = CycleIssue.objects.bulk_update(
updated_cycles, ["cycle_id"], batch_size=100
)
return Response({"message": "Success"}, status=status.HTTP_200_OK)
except Cycle.DoesNotExist:
return Response(
{"error": "New Cycle Does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,253 @@
# Django imports
from django.db import IntegrityError
# Third party imports
from rest_framework.response import Response
from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from .base import BaseViewSet, BaseAPIView
from plane.api.permissions import ProjectEntityPermission
from plane.db.models import Project, Estimate, EstimatePoint
from plane.api.serializers import (
EstimateSerializer,
EstimatePointSerializer,
EstimateReadSerializer,
)
class ProjectEstimatePointEndpoint(BaseAPIView):
permission_classes = [
ProjectEntityPermission,
]
def get(self, request, slug, project_id):
try:
project = Project.objects.get(workspace__slug=slug, pk=project_id)
if project.estimate_id is not None:
estimate_points = EstimatePoint.objects.filter(
estimate_id=project.estimate_id,
project_id=project_id,
workspace__slug=slug,
)
serializer = EstimatePointSerializer(estimate_points, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response([], status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class BulkEstimatePointEndpoint(BaseViewSet):
permission_classes = [
ProjectEntityPermission,
]
model = Estimate
serializer_class = EstimateSerializer
def list(self, request, slug, project_id):
try:
estimates = Estimate.objects.filter(
workspace__slug=slug, project_id=project_id
).prefetch_related("points").select_related("workspace", "project")
serializer = EstimateReadSerializer(estimates, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def create(self, request, slug, project_id):
try:
if not request.data.get("estimate", False):
return Response(
{"error": "Estimate is required"},
status=status.HTTP_400_BAD_REQUEST,
)
estimate_points = request.data.get("estimate_points", [])
if not len(estimate_points) or len(estimate_points) > 8:
return Response(
{"error": "Estimate points are required"},
status=status.HTTP_400_BAD_REQUEST,
)
estimate_serializer = EstimateSerializer(data=request.data.get("estimate"))
if not estimate_serializer.is_valid():
return Response(
estimate_serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
try:
estimate = estimate_serializer.save(project_id=project_id)
except IntegrityError:
return Response(
{"errror": "Estimate with the name already exists"},
status=status.HTTP_400_BAD_REQUEST,
)
estimate_points = EstimatePoint.objects.bulk_create(
[
EstimatePoint(
estimate=estimate,
key=estimate_point.get("key", 0),
value=estimate_point.get("value", ""),
description=estimate_point.get("description", ""),
project_id=project_id,
workspace_id=estimate.workspace_id,
created_by=request.user,
updated_by=request.user,
)
for estimate_point in estimate_points
],
batch_size=10,
ignore_conflicts=True,
)
estimate_point_serializer = EstimatePointSerializer(
estimate_points, many=True
)
return Response(
{
"estimate": estimate_serializer.data,
"estimate_points": estimate_point_serializer.data,
},
status=status.HTTP_200_OK,
)
except Estimate.DoesNotExist:
return Response(
{"error": "Estimate does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def retrieve(self, request, slug, project_id, estimate_id):
try:
estimate = Estimate.objects.get(
pk=estimate_id, workspace__slug=slug, project_id=project_id
)
serializer = EstimateReadSerializer(estimate)
return Response(
serializer.data,
status=status.HTTP_200_OK,
)
except Estimate.DoesNotExist:
return Response(
{"error": "Estimate does not exist"}, status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def partial_update(self, request, slug, project_id, estimate_id):
try:
if not request.data.get("estimate", False):
return Response(
{"error": "Estimate is required"},
status=status.HTTP_400_BAD_REQUEST,
)
if not len(request.data.get("estimate_points", [])):
return Response(
{"error": "Estimate points are required"},
status=status.HTTP_400_BAD_REQUEST,
)
estimate = Estimate.objects.get(pk=estimate_id)
estimate_serializer = EstimateSerializer(
estimate, data=request.data.get("estimate"), partial=True
)
if not estimate_serializer.is_valid():
return Response(
estimate_serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
try:
estimate = estimate_serializer.save()
except IntegrityError:
return Response(
{"errror": "Estimate with the name already exists"},
status=status.HTTP_400_BAD_REQUEST,
)
estimate_points_data = request.data.get("estimate_points", [])
estimate_points = EstimatePoint.objects.filter(
pk__in=[
estimate_point.get("id") for estimate_point in estimate_points_data
],
workspace__slug=slug,
project_id=project_id,
estimate_id=estimate_id,
)
updated_estimate_points = []
for estimate_point in estimate_points:
# Find the data for that estimate point
estimate_point_data = [
point
for point in estimate_points_data
if point.get("id") == str(estimate_point.id)
]
if len(estimate_point_data):
estimate_point.value = estimate_point_data[0].get(
"value", estimate_point.value
)
updated_estimate_points.append(estimate_point)
try:
EstimatePoint.objects.bulk_update(
updated_estimate_points, ["value"], batch_size=10,
)
except IntegrityError as e:
return Response(
{"error": "Values need to be unique for each key"},
status=status.HTTP_400_BAD_REQUEST,
)
estimate_point_serializer = EstimatePointSerializer(estimate_points, many=True)
return Response(
{
"estimate": estimate_serializer.data,
"estimate_points": estimate_point_serializer.data,
},
status=status.HTTP_200_OK,
)
except Estimate.DoesNotExist:
return Response(
{"error": "Estimate does not exist"}, status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, estimate_id):
try:
estimate = Estimate.objects.get(
pk=estimate_id, workspace__slug=slug, project_id=project_id
)
estimate.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,100 @@
# Third Party imports
from rest_framework.response import Response
from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from . import BaseAPIView
from plane.api.permissions import WorkSpaceAdminPermission
from plane.bgtasks.export_task import issue_export_task
from plane.db.models import Project, ExporterHistory, Workspace
from plane.api.serializers import ExporterHistorySerializer
class ExportIssuesEndpoint(BaseAPIView):
permission_classes = [
WorkSpaceAdminPermission,
]
model = ExporterHistory
serializer_class = ExporterHistorySerializer
def post(self, request, slug):
try:
# Get the workspace
workspace = Workspace.objects.get(slug=slug)
provider = request.data.get("provider", False)
multiple = request.data.get("multiple", False)
project_ids = request.data.get("project", [])
if provider in ["csv", "xlsx", "json"]:
if not project_ids:
project_ids = Project.objects.filter(
workspace__slug=slug
).values_list("id", flat=True)
project_ids = [str(project_id) for project_id in project_ids]
exporter = ExporterHistory.objects.create(
workspace=workspace,
project=project_ids,
initiated_by=request.user,
provider=provider,
)
issue_export_task.delay(
provider=exporter.provider,
workspace_id=workspace.id,
project_ids=project_ids,
token_id=exporter.token,
multiple=multiple,
slug=slug,
)
return Response(
{
"message": f"Once the export is ready you will be able to download it"
},
status=status.HTTP_200_OK,
)
else:
return Response(
{"error": f"Provider '{provider}' not found."},
status=status.HTTP_400_BAD_REQUEST,
)
except Workspace.DoesNotExist:
return Response(
{"error": "Workspace does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def get(self, request, slug):
try:
exporter_history = ExporterHistory.objects.filter(
workspace__slug=slug
).select_related("workspace","initiated_by")
if request.GET.get("per_page", False) and request.GET.get("cursor", False):
return self.paginate(
request=request,
queryset=exporter_history,
on_results=lambda exporter_history: ExporterHistorySerializer(
exporter_history, many=True
).data,
)
else:
return Response(
{"error": "per_page and cursor are required"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,75 @@
# Python imports
import requests
# Third party imports
from rest_framework.response import Response
from rest_framework import status
import openai
from sentry_sdk import capture_exception
# Django imports
from django.conf import settings
# Module imports
from .base import BaseAPIView
from plane.api.permissions import ProjectEntityPermission
from plane.db.models import Workspace, Project
from plane.api.serializers import ProjectLiteSerializer, WorkspaceLiteSerializer
class GPTIntegrationEndpoint(BaseAPIView):
permission_classes = [
ProjectEntityPermission,
]
def post(self, request, slug, project_id):
try:
if not settings.OPENAI_API_KEY or not settings.GPT_ENGINE:
return Response(
{"error": "OpenAI API key and engine is required"},
status=status.HTTP_400_BAD_REQUEST,
)
prompt = request.data.get("prompt", False)
task = request.data.get("task", False)
if not task:
return Response(
{"error": "Task is required"}, status=status.HTTP_400_BAD_REQUEST
)
final_text = task + "\n" + prompt
openai.api_key = settings.OPENAI_API_KEY
response = openai.ChatCompletion.create(
model=settings.GPT_ENGINE,
messages=[{"role": "user", "content": final_text}],
temperature=0.7,
max_tokens=1024,
)
workspace = Workspace.objects.get(slug=slug)
project = Project.objects.get(pk=project_id)
text = response.choices[0].message.content.strip()
text_html = text.replace("\n", "<br/>")
return Response(
{
"response": text,
"response_html": text_html,
"project_detail": ProjectLiteSerializer(project).data,
"workspace_detail": WorkspaceLiteSerializer(workspace).data,
},
status=status.HTTP_200_OK,
)
except (Workspace.DoesNotExist, Project.DoesNotExist) as e:
return Response(
{"error": "Workspace or Project Does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,602 @@
# Python imports
import uuid
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from sentry_sdk import capture_exception
# Django imports
from django.db.models import Max, Q
# Module imports
from plane.api.views import BaseAPIView
from plane.db.models import (
WorkspaceIntegration,
Importer,
APIToken,
Project,
State,
IssueSequence,
Issue,
IssueActivity,
IssueComment,
IssueLink,
IssueLabel,
Workspace,
IssueAssignee,
Module,
ModuleLink,
ModuleIssue,
Label,
)
from plane.api.serializers import (
ImporterSerializer,
IssueFlatSerializer,
ModuleSerializer,
)
from plane.utils.integrations.github import get_github_repo_details
from plane.utils.importers.jira import jira_project_issue_summary
from plane.bgtasks.importer_task import service_importer
from plane.utils.html_processor import strip_tags
class ServiceIssueImportSummaryEndpoint(BaseAPIView):
def get(self, request, slug, service):
try:
if service == "github":
owner = request.GET.get("owner", False)
repo = request.GET.get("repo", False)
if not owner or not repo:
return Response(
{"error": "Owner and repo are required"},
status=status.HTTP_400_BAD_REQUEST,
)
workspace_integration = WorkspaceIntegration.objects.get(
integration__provider="github", workspace__slug=slug
)
access_tokens_url = workspace_integration.metadata.get(
"access_tokens_url", False
)
if not access_tokens_url:
return Response(
{
"error": "There was an error during the installation of the GitHub app. To resolve this issue, we recommend reinstalling the GitHub app."
},
status=status.HTTP_400_BAD_REQUEST,
)
issue_count, labels, collaborators = get_github_repo_details(
access_tokens_url, owner, repo
)
return Response(
{
"issue_count": issue_count,
"labels": labels,
"collaborators": collaborators,
},
status=status.HTTP_200_OK,
)
if service == "jira":
# Check for all the keys
params = {
"project_key": "Project key is required",
"api_token": "API token is required",
"email": "Email is required",
"cloud_hostname": "Cloud hostname is required",
}
for key, error_message in params.items():
if not request.GET.get(key, False):
return Response(
{"error": error_message}, status=status.HTTP_400_BAD_REQUEST
)
project_key = request.GET.get("project_key", "")
api_token = request.GET.get("api_token", "")
email = request.GET.get("email", "")
cloud_hostname = request.GET.get("cloud_hostname", "")
response = jira_project_issue_summary(
email, api_token, project_key, cloud_hostname
)
if "error" in response:
return Response(response, status=status.HTTP_400_BAD_REQUEST)
else:
return Response(
response,
status=status.HTTP_200_OK,
)
return Response(
{"error": "Service not supported yet"},
status=status.HTTP_400_BAD_REQUEST,
)
except WorkspaceIntegration.DoesNotExist:
return Response(
{"error": "Requested integration was not installed in the workspace"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class ImportServiceEndpoint(BaseAPIView):
def post(self, request, slug, service):
try:
project_id = request.data.get("project_id", False)
if not project_id:
return Response(
{"error": "Project ID is required"},
status=status.HTTP_400_BAD_REQUEST,
)
workspace = Workspace.objects.get(slug=slug)
if service == "github":
data = request.data.get("data", False)
metadata = request.data.get("metadata", False)
config = request.data.get("config", False)
if not data or not metadata or not config:
return Response(
{"error": "Data, config and metadata are required"},
status=status.HTTP_400_BAD_REQUEST,
)
api_token = APIToken.objects.filter(
user=request.user, workspace=workspace
).first()
if api_token is None:
api_token = APIToken.objects.create(
user=request.user,
label="Importer",
workspace=workspace,
)
importer = Importer.objects.create(
service=service,
project_id=project_id,
status="queued",
initiated_by=request.user,
data=data,
metadata=metadata,
token=api_token,
config=config,
created_by=request.user,
updated_by=request.user,
)
service_importer.delay(service, importer.id)
serializer = ImporterSerializer(importer)
return Response(serializer.data, status=status.HTTP_201_CREATED)
if service == "jira":
data = request.data.get("data", False)
metadata = request.data.get("metadata", False)
config = request.data.get("config", False)
if not data or not metadata:
return Response(
{"error": "Data, config and metadata are required"},
status=status.HTTP_400_BAD_REQUEST,
)
api_token = APIToken.objects.filter(
user=request.user, workspace=workspace
).first()
if api_token is None:
api_token = APIToken.objects.create(
user=request.user,
label="Importer",
workspace=workspace,
)
importer = Importer.objects.create(
service=service,
project_id=project_id,
status="queued",
initiated_by=request.user,
data=data,
metadata=metadata,
token=api_token,
config=config,
created_by=request.user,
updated_by=request.user,
)
service_importer.delay(service, importer.id)
serializer = ImporterSerializer(importer)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(
{"error": "Servivce not supported yet"},
status=status.HTTP_400_BAD_REQUEST,
)
except (
Workspace.DoesNotExist,
WorkspaceIntegration.DoesNotExist,
Project.DoesNotExist,
) as e:
return Response(
{"error": "Workspace Integration or Project does not exist"},
status=status.HTTP_404_NOT_FOUND,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def get(self, request, slug):
try:
imports = (
Importer.objects.filter(workspace__slug=slug)
.order_by("-created_at")
.select_related("initiated_by", "project", "workspace")
)
serializer = ImporterSerializer(imports, many=True)
return Response(serializer.data)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def delete(self, request, slug, service, pk):
try:
importer = Importer.objects.get(
pk=pk, service=service, workspace__slug=slug
)
if importer.imported_data is not None:
# Delete all imported Issues
imported_issues = importer.imported_data.get("issues", [])
Issue.issue_objects.filter(id__in=imported_issues).delete()
# Delete all imported Labels
imported_labels = importer.imported_data.get("labels", [])
Label.objects.filter(id__in=imported_labels).delete()
if importer.service == "jira":
imported_modules = importer.imported_data.get("modules", [])
Module.objects.filter(id__in=imported_modules).delete()
importer.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def patch(self, request, slug, service, pk):
try:
importer = Importer.objects.get(
pk=pk, service=service, workspace__slug=slug
)
serializer = ImporterSerializer(importer, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Importer.DoesNotExist:
return Response(
{"error": "Importer Does not exists"}, status=status.HTTP_404_NOT_FOUND
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class UpdateServiceImportStatusEndpoint(BaseAPIView):
def post(self, request, slug, project_id, service, importer_id):
try:
importer = Importer.objects.get(
pk=importer_id,
workspace__slug=slug,
project_id=project_id,
service=service,
)
importer.status = request.data.get("status", "processing")
importer.save()
return Response(status.HTTP_200_OK)
except Importer.DoesNotExist:
return Response(
{"error": "Importer does not exist"}, status=status.HTTP_404_NOT_FOUND
)
class BulkImportIssuesEndpoint(BaseAPIView):
def post(self, request, slug, project_id, service):
try:
# Get the project
project = Project.objects.get(pk=project_id, workspace__slug=slug)
# Get the default state
default_state = State.objects.filter(
~Q(name="Triage"), project_id=project_id, default=True
).first()
# if there is no default state assign any random state
if default_state is None:
default_state = State.objects.filter(
~Q(name="Triage"), project_id=project_id
).first()
# Get the maximum sequence_id
last_id = IssueSequence.objects.filter(project_id=project_id).aggregate(
largest=Max("sequence")
)["largest"]
last_id = 1 if last_id is None else last_id + 1
# Get the maximum sort order
largest_sort_order = Issue.objects.filter(
project_id=project_id, state=default_state
).aggregate(largest=Max("sort_order"))["largest"]
largest_sort_order = (
65535 if largest_sort_order is None else largest_sort_order + 10000
)
# Get the issues_data
issues_data = request.data.get("issues_data", [])
if not len(issues_data):
return Response(
{"error": "Issue data is required"},
status=status.HTTP_400_BAD_REQUEST,
)
# Issues
bulk_issues = []
for issue_data in issues_data:
bulk_issues.append(
Issue(
project_id=project_id,
workspace_id=project.workspace_id,
state_id=issue_data.get("state")
if issue_data.get("state", False)
else default_state.id,
name=issue_data.get("name", "Issue Created through Bulk"),
description_html=issue_data.get("description_html", "<p></p>"),
description_stripped=(
None
if (
issue_data.get("description_html") == ""
or issue_data.get("description_html") is None
)
else strip_tags(issue_data.get("description_html"))
),
sequence_id=last_id,
sort_order=largest_sort_order,
start_date=issue_data.get("start_date", None),
target_date=issue_data.get("target_date", None),
priority=issue_data.get("priority", "none"),
created_by=request.user,
)
)
largest_sort_order = largest_sort_order + 10000
last_id = last_id + 1
issues = Issue.objects.bulk_create(
bulk_issues,
batch_size=100,
ignore_conflicts=True,
)
# Sequences
_ = IssueSequence.objects.bulk_create(
[
IssueSequence(
issue=issue,
sequence=issue.sequence_id,
project_id=project_id,
workspace_id=project.workspace_id,
)
for issue in issues
],
batch_size=100,
)
# Attach Labels
bulk_issue_labels = []
for issue, issue_data in zip(issues, issues_data):
labels_list = issue_data.get("labels_list", [])
bulk_issue_labels = bulk_issue_labels + [
IssueLabel(
issue=issue,
label_id=label_id,
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
)
for label_id in labels_list
]
_ = IssueLabel.objects.bulk_create(
bulk_issue_labels, batch_size=100, ignore_conflicts=True
)
# Attach Assignees
bulk_issue_assignees = []
for issue, issue_data in zip(issues, issues_data):
assignees_list = issue_data.get("assignees_list", [])
bulk_issue_assignees = bulk_issue_assignees + [
IssueAssignee(
issue=issue,
assignee_id=assignee_id,
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
)
for assignee_id in assignees_list
]
_ = IssueAssignee.objects.bulk_create(
bulk_issue_assignees, batch_size=100, ignore_conflicts=True
)
# Track the issue activities
IssueActivity.objects.bulk_create(
[
IssueActivity(
issue=issue,
actor=request.user,
project_id=project_id,
workspace_id=project.workspace_id,
comment=f"imported the issue from {service}",
verb="created",
created_by=request.user,
)
for issue in issues
],
batch_size=100,
)
# Create Comments
bulk_issue_comments = []
for issue, issue_data in zip(issues, issues_data):
comments_list = issue_data.get("comments_list", [])
bulk_issue_comments = bulk_issue_comments + [
IssueComment(
issue=issue,
comment_html=comment.get("comment_html", "<p></p>"),
actor=request.user,
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
)
for comment in comments_list
]
_ = IssueComment.objects.bulk_create(bulk_issue_comments, batch_size=100)
# Attach Links
_ = IssueLink.objects.bulk_create(
[
IssueLink(
issue=issue,
url=issue_data.get("link", {}).get("url", "https://github.com"),
title=issue_data.get("link", {}).get("title", "Original Issue"),
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
)
for issue, issue_data in zip(issues, issues_data)
]
)
return Response(
{"issues": IssueFlatSerializer(issues, many=True).data},
status=status.HTTP_201_CREATED,
)
except Project.DoesNotExist:
return Response(
{"error": "Project Does not exist"}, status=status.HTTP_404_NOT_FOUND
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class BulkImportModulesEndpoint(BaseAPIView):
def post(self, request, slug, project_id, service):
try:
modules_data = request.data.get("modules_data", [])
project = Project.objects.get(pk=project_id, workspace__slug=slug)
modules = Module.objects.bulk_create(
[
Module(
name=module.get("name", uuid.uuid4().hex),
description=module.get("description", ""),
start_date=module.get("start_date", None),
target_date=module.get("target_date", None),
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
)
for module in modules_data
],
batch_size=100,
ignore_conflicts=True,
)
modules = Module.objects.filter(id__in=[module.id for module in modules])
if len(modules) == len(modules_data):
_ = ModuleLink.objects.bulk_create(
[
ModuleLink(
module=module,
url=module_data.get("link", {}).get(
"url", "https://plane.so"
),
title=module_data.get("link", {}).get(
"title", "Original Issue"
),
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
)
for module, module_data in zip(modules, modules_data)
],
batch_size=100,
ignore_conflicts=True,
)
bulk_module_issues = []
for module, module_data in zip(modules, modules_data):
module_issues_list = module_data.get("module_issues_list", [])
bulk_module_issues = bulk_module_issues + [
ModuleIssue(
issue_id=issue,
module=module,
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
)
for issue in module_issues_list
]
_ = ModuleIssue.objects.bulk_create(
bulk_module_issues, batch_size=100, ignore_conflicts=True
)
serializer = ModuleSerializer(modules, many=True)
return Response(
{"modules": serializer.data}, status=status.HTTP_201_CREATED
)
else:
return Response(
{"message": "Modules created but issues could not be imported"},
status=status.HTTP_200_OK,
)
except Project.DoesNotExist:
return Response(
{"error": "Project does not exist"}, status=status.HTTP_404_NOT_FOUND
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,654 @@
# Python imports
import json
# Django import
from django.utils import timezone
from django.db.models import Q, Count, OuterRef, Func, F, Prefetch
from django.core.serializers.json import DjangoJSONEncoder
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from sentry_sdk import capture_exception
# Module imports
from .base import BaseViewSet
from plane.api.permissions import ProjectBasePermission, ProjectLitePermission
from plane.db.models import (
Inbox,
InboxIssue,
Issue,
State,
IssueLink,
IssueAttachment,
ProjectMember,
ProjectDeployBoard,
)
from plane.api.serializers import (
IssueSerializer,
InboxSerializer,
InboxIssueSerializer,
IssueCreateSerializer,
IssueStateInboxSerializer,
)
from plane.utils.issue_filters import issue_filters
from plane.bgtasks.issue_activites_task import issue_activity
class InboxViewSet(BaseViewSet):
permission_classes = [
ProjectBasePermission,
]
serializer_class = InboxSerializer
model = Inbox
def get_queryset(self):
return (
super()
.get_queryset()
.filter(
workspace__slug=self.kwargs.get("slug"),
project_id=self.kwargs.get("project_id"),
)
.annotate(
pending_issue_count=Count(
"issue_inbox",
filter=Q(issue_inbox__status=-2),
)
)
.select_related("workspace", "project")
)
def perform_create(self, serializer):
serializer.save(project_id=self.kwargs.get("project_id"))
def destroy(self, request, slug, project_id, pk):
try:
inbox = Inbox.objects.get(
workspace__slug=slug, project_id=project_id, pk=pk
)
# Handle default inbox delete
if inbox.is_default:
return Response(
{"error": "You cannot delete the default inbox"},
status=status.HTTP_400_BAD_REQUEST,
)
inbox.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wronf please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class InboxIssueViewSet(BaseViewSet):
permission_classes = [
ProjectLitePermission,
]
serializer_class = InboxIssueSerializer
model = InboxIssue
filterset_fields = [
"status",
]
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(
Q(snoozed_till__gte=timezone.now()) | Q(snoozed_till__isnull=True),
workspace__slug=self.kwargs.get("slug"),
project_id=self.kwargs.get("project_id"),
inbox_id=self.kwargs.get("inbox_id"),
)
.select_related("issue", "workspace", "project")
)
def list(self, request, slug, project_id, inbox_id):
try:
filters = issue_filters(request.query_params, "GET")
issues = (
Issue.objects.filter(
issue_inbox__inbox_id=inbox_id,
workspace__slug=slug,
project_id=project_id,
)
.filter(**filters)
.annotate(bridge_id=F("issue_inbox__id"))
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels")
.order_by("issue_inbox__snoozed_till", "issue_inbox__status")
.annotate(
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.prefetch_related(
Prefetch(
"issue_inbox",
queryset=InboxIssue.objects.only(
"status", "duplicate_to", "snoozed_till", "source"
),
)
)
)
issues_data = IssueStateInboxSerializer(issues, many=True).data
return Response(
issues_data,
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def create(self, request, slug, project_id, inbox_id):
try:
if not request.data.get("issue", {}).get("name", False):
return Response(
{"error": "Name is required"}, status=status.HTTP_400_BAD_REQUEST
)
# Check for valid priority
if not request.data.get("issue", {}).get("priority", "none") in [
"low",
"medium",
"high",
"urgent",
"none",
]:
return Response(
{"error": "Invalid priority"}, status=status.HTTP_400_BAD_REQUEST
)
# Create or get state
state, _ = State.objects.get_or_create(
name="Triage",
group="backlog",
description="Default state for managing all Inbox Issues",
project_id=project_id,
color="#ff7700",
)
# create an issue
issue = Issue.objects.create(
name=request.data.get("issue", {}).get("name"),
description=request.data.get("issue", {}).get("description", {}),
description_html=request.data.get("issue", {}).get(
"description_html", "<p></p>"
),
priority=request.data.get("issue", {}).get("priority", "low"),
project_id=project_id,
state=state,
)
# Create an Issue Activity
issue_activity.delay(
type="issue.activity.created",
requested_data=json.dumps(request.data, cls=DjangoJSONEncoder),
actor_id=str(request.user.id),
issue_id=str(issue.id),
project_id=str(project_id),
current_instance=None,
epoch=int(timezone.now().timestamp())
)
# create an inbox issue
InboxIssue.objects.create(
inbox_id=inbox_id,
project_id=project_id,
issue=issue,
source=request.data.get("source", "in-app"),
)
serializer = IssueStateInboxSerializer(issue)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def partial_update(self, request, slug, project_id, inbox_id, pk):
try:
inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
)
# Get the project member
project_member = ProjectMember.objects.get(workspace__slug=slug, project_id=project_id, member=request.user)
# Only project members admins and created_by users can access this endpoint
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(request.user.id):
return Response({"error": "You cannot edit inbox issues"}, status=status.HTTP_400_BAD_REQUEST)
# Get issue data
issue_data = request.data.pop("issue", False)
if bool(issue_data):
issue = Issue.objects.get(
pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id
)
# Only allow guests and viewers to edit name and description
if project_member.role <= 10:
# viewers and guests since only viewers and guests
issue_data = {
"name": issue_data.get("name", issue.name),
"description_html": issue_data.get("description_html", issue.description_html),
"description": issue_data.get("description", issue.description)
}
issue_serializer = IssueCreateSerializer(
issue, data=issue_data, partial=True
)
if issue_serializer.is_valid():
current_instance = issue
# Log all the updates
requested_data = json.dumps(issue_data, cls=DjangoJSONEncoder)
if issue is not None:
issue_activity.delay(
type="issue.activity.updated",
requested_data=requested_data,
actor_id=str(request.user.id),
issue_id=str(issue.id),
project_id=str(project_id),
current_instance=json.dumps(
IssueSerializer(current_instance).data,
cls=DjangoJSONEncoder,
),
epoch=int(timezone.now().timestamp())
)
issue_serializer.save()
else:
return Response(
issue_serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
# Only project admins and members can edit inbox issue attributes
if project_member.role > 10:
serializer = InboxIssueSerializer(
inbox_issue, data=request.data, partial=True
)
if serializer.is_valid():
serializer.save()
# Update the issue state if the issue is rejected or marked as duplicate
if serializer.data["status"] in [-1, 2]:
issue = Issue.objects.get(
pk=inbox_issue.issue_id,
workspace__slug=slug,
project_id=project_id,
)
state = State.objects.filter(
group="cancelled", workspace__slug=slug, project_id=project_id
).first()
if state is not None:
issue.state = state
issue.save()
# Update the issue state if it is accepted
if serializer.data["status"] in [1]:
issue = Issue.objects.get(
pk=inbox_issue.issue_id,
workspace__slug=slug,
project_id=project_id,
)
# Update the issue state only if it is in triage state
if issue.state.name == "Triage":
# Move to default state
state = State.objects.filter(
workspace__slug=slug, project_id=project_id, default=True
).first()
if state is not None:
issue.state = state
issue.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
else:
return Response(InboxIssueSerializer(inbox_issue).data, status=status.HTTP_200_OK)
except InboxIssue.DoesNotExist:
return Response(
{"error": "Inbox Issue does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def retrieve(self, request, slug, project_id, inbox_id, pk):
try:
inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
)
issue = Issue.objects.get(
pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id
)
serializer = IssueStateInboxSerializer(issue)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, inbox_id, pk):
try:
inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
)
# Get the project member
project_member = ProjectMember.objects.get(workspace__slug=slug, project_id=project_id, member=request.user)
if project_member.role <= 10 and str(inbox_issue.created_by_id) != str(request.user.id):
return Response({"error": "You cannot delete inbox issue"}, status=status.HTTP_400_BAD_REQUEST)
# Check the issue status
if inbox_issue.status in [-2, -1, 0, 2]:
# Delete the issue also
Issue.objects.filter(workspace__slug=slug, project_id=project_id, pk=inbox_issue.issue_id).delete()
inbox_issue.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except InboxIssue.DoesNotExist:
return Response({"error": "Inbox Issue does not exists"}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class InboxIssuePublicViewSet(BaseViewSet):
serializer_class = InboxIssueSerializer
model = InboxIssue
filterset_fields = [
"status",
]
def get_queryset(self):
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=self.kwargs.get("slug"), project_id=self.kwargs.get("project_id"))
if project_deploy_board is not None:
return self.filter_queryset(
super()
.get_queryset()
.filter(
Q(snoozed_till__gte=timezone.now()) | Q(snoozed_till__isnull=True),
project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"),
inbox_id=self.kwargs.get("inbox_id"),
)
.select_related("issue", "workspace", "project")
)
else:
return InboxIssue.objects.none()
def list(self, request, slug, project_id, inbox_id):
try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id)
if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST)
filters = issue_filters(request.query_params, "GET")
issues = (
Issue.objects.filter(
issue_inbox__inbox_id=inbox_id,
workspace__slug=slug,
project_id=project_id,
)
.filter(**filters)
.annotate(bridge_id=F("issue_inbox__id"))
.select_related("workspace", "project", "state", "parent")
.prefetch_related("assignees", "labels")
.order_by("issue_inbox__snoozed_till", "issue_inbox__status")
.annotate(
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.prefetch_related(
Prefetch(
"issue_inbox",
queryset=InboxIssue.objects.only(
"status", "duplicate_to", "snoozed_till", "source"
),
)
)
)
issues_data = IssueStateInboxSerializer(issues, many=True).data
return Response(
issues_data,
status=status.HTTP_200_OK,
)
except ProjectDeployBoard.DoesNotExist:
return Response({"error": "Project Deploy Board does not exist"}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def create(self, request, slug, project_id, inbox_id):
try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id)
if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST)
if not request.data.get("issue", {}).get("name", False):
return Response(
{"error": "Name is required"}, status=status.HTTP_400_BAD_REQUEST
)
# Check for valid priority
if not request.data.get("issue", {}).get("priority", "none") in [
"low",
"medium",
"high",
"urgent",
"none",
]:
return Response(
{"error": "Invalid priority"}, status=status.HTTP_400_BAD_REQUEST
)
# Create or get state
state, _ = State.objects.get_or_create(
name="Triage",
group="backlog",
description="Default state for managing all Inbox Issues",
project_id=project_id,
color="#ff7700",
)
# create an issue
issue = Issue.objects.create(
name=request.data.get("issue", {}).get("name"),
description=request.data.get("issue", {}).get("description", {}),
description_html=request.data.get("issue", {}).get(
"description_html", "<p></p>"
),
priority=request.data.get("issue", {}).get("priority", "low"),
project_id=project_id,
state=state,
)
# Create an Issue Activity
issue_activity.delay(
type="issue.activity.created",
requested_data=json.dumps(request.data, cls=DjangoJSONEncoder),
actor_id=str(request.user.id),
issue_id=str(issue.id),
project_id=str(project_id),
current_instance=None,
epoch=int(timezone.now().timestamp())
)
# create an inbox issue
InboxIssue.objects.create(
inbox_id=inbox_id,
project_id=project_id,
issue=issue,
source=request.data.get("source", "in-app"),
)
serializer = IssueStateInboxSerializer(issue)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def partial_update(self, request, slug, project_id, inbox_id, pk):
try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id)
if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST)
inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
)
# Get the project member
if str(inbox_issue.created_by_id) != str(request.user.id):
return Response({"error": "You cannot edit inbox issues"}, status=status.HTTP_400_BAD_REQUEST)
# Get issue data
issue_data = request.data.pop("issue", False)
issue = Issue.objects.get(
pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id
)
# viewers and guests since only viewers and guests
issue_data = {
"name": issue_data.get("name", issue.name),
"description_html": issue_data.get("description_html", issue.description_html),
"description": issue_data.get("description", issue.description)
}
issue_serializer = IssueCreateSerializer(
issue, data=issue_data, partial=True
)
if issue_serializer.is_valid():
current_instance = issue
# Log all the updates
requested_data = json.dumps(issue_data, cls=DjangoJSONEncoder)
if issue is not None:
issue_activity.delay(
type="issue.activity.updated",
requested_data=requested_data,
actor_id=str(request.user.id),
issue_id=str(issue.id),
project_id=str(project_id),
current_instance=json.dumps(
IssueSerializer(current_instance).data,
cls=DjangoJSONEncoder,
),
epoch=int(timezone.now().timestamp())
)
issue_serializer.save()
return Response(issue_serializer.data, status=status.HTTP_200_OK)
return Response(issue_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except InboxIssue.DoesNotExist:
return Response(
{"error": "Inbox Issue does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def retrieve(self, request, slug, project_id, inbox_id, pk):
try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id)
if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST)
inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
)
issue = Issue.objects.get(
pk=inbox_issue.issue_id, workspace__slug=slug, project_id=project_id
)
serializer = IssueStateInboxSerializer(issue)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, inbox_id, pk):
try:
project_deploy_board = ProjectDeployBoard.objects.get(workspace__slug=slug, project_id=project_id)
if project_deploy_board.inbox is None:
return Response({"error": "Inbox is not enabled for this Project Board"}, status=status.HTTP_400_BAD_REQUEST)
inbox_issue = InboxIssue.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id, inbox_id=inbox_id
)
if str(inbox_issue.created_by_id) != str(request.user.id):
return Response({"error": "You cannot delete inbox issue"}, status=status.HTTP_400_BAD_REQUEST)
inbox_issue.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except InboxIssue.DoesNotExist:
return Response({"error": "Inbox Issue does not exists"}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,9 @@
from .base import IntegrationViewSet, WorkspaceIntegrationViewSet
from .github import (
GithubRepositorySyncViewSet,
GithubIssueSyncViewSet,
BulkCreateGithubIssueSyncEndpoint,
GithubCommentSyncViewSet,
GithubRepositoriesEndpoint,
)
from .slack import SlackProjectSyncViewSet

View File

@@ -0,0 +1,229 @@
# Python improts
import uuid
# Django imports
from django.db import IntegrityError
from django.contrib.auth.hashers import make_password
# Third party imports
from rest_framework.response import Response
from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from plane.api.views import BaseViewSet
from plane.db.models import (
Integration,
WorkspaceIntegration,
Workspace,
User,
WorkspaceMember,
APIToken,
)
from plane.api.serializers import IntegrationSerializer, WorkspaceIntegrationSerializer
from plane.utils.integrations.github import (
get_github_metadata,
delete_github_installation,
)
from plane.api.permissions import WorkSpaceAdminPermission
class IntegrationViewSet(BaseViewSet):
serializer_class = IntegrationSerializer
model = Integration
def create(self, request):
try:
serializer = IntegrationSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def partial_update(self, request, pk):
try:
integration = Integration.objects.get(pk=pk)
if integration.verified:
return Response(
{"error": "Verified integrations cannot be updated"},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = IntegrationSerializer(
integration, data=request.data, partial=True
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Integration.DoesNotExist:
return Response(
{"error": "Integration Does not exist"},
status=status.HTTP_404_NOT_FOUND,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, pk):
try:
integration = Integration.objects.get(pk=pk)
if integration.verified:
return Response(
{"error": "Verified integrations cannot be updated"},
status=status.HTTP_400_BAD_REQUEST,
)
integration.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except Integration.DoesNotExist:
return Response(
{"error": "Integration Does not exist"},
status=status.HTTP_404_NOT_FOUND,
)
class WorkspaceIntegrationViewSet(BaseViewSet):
serializer_class = WorkspaceIntegrationSerializer
model = WorkspaceIntegration
permission_classes = [
WorkSpaceAdminPermission,
]
def get_queryset(self):
return (
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.select_related("integration")
)
def create(self, request, slug, provider):
try:
workspace = Workspace.objects.get(slug=slug)
integration = Integration.objects.get(provider=provider)
config = {}
if provider == "github":
installation_id = request.data.get("installation_id", None)
if not installation_id:
return Response(
{"error": "Installation ID is required"},
status=status.HTTP_400_BAD_REQUEST,
)
metadata = get_github_metadata(installation_id)
config = {"installation_id": installation_id}
if provider == "slack":
metadata = request.data.get("metadata", {})
access_token = metadata.get("access_token", False)
team_id = metadata.get("team", {}).get("id", False)
if not metadata or not access_token or not team_id:
return Response(
{"error": "Access token and team id is required"},
status=status.HTTP_400_BAD_REQUEST,
)
config = {"team_id": team_id, "access_token": access_token}
# Create a bot user
bot_user = User.objects.create(
email=f"{uuid.uuid4().hex}@plane.so",
username=uuid.uuid4().hex,
password=make_password(uuid.uuid4().hex),
is_password_autoset=True,
is_bot=True,
first_name=integration.title,
avatar=integration.avatar_url
if integration.avatar_url is not None
else "",
)
# Create an API Token for the bot user
api_token = APIToken.objects.create(
user=bot_user,
user_type=1, # bot user
workspace=workspace,
)
workspace_integration = WorkspaceIntegration.objects.create(
workspace=workspace,
integration=integration,
actor=bot_user,
api_token=api_token,
metadata=metadata,
config=config,
)
# Add bot user as a member of workspace
_ = WorkspaceMember.objects.create(
workspace=workspace_integration.workspace,
member=bot_user,
role=20,
)
return Response(
WorkspaceIntegrationSerializer(workspace_integration).data,
status=status.HTTP_201_CREATED,
)
except IntegrityError as e:
if "already exists" in str(e):
return Response(
{"error": "Integration is already active in the workspace"},
status=status.HTTP_410_GONE,
)
else:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
except (Workspace.DoesNotExist, Integration.DoesNotExist) as e:
capture_exception(e)
return Response(
{"error": "Workspace or Integration not found"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, pk):
try:
workspace_integration = WorkspaceIntegration.objects.get(
pk=pk, workspace__slug=slug
)
if workspace_integration.integration.provider == "github":
installation_id = workspace_integration.config.get(
"installation_id", False
)
if installation_id:
delete_github_installation(installation_id=installation_id)
workspace_integration.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except WorkspaceIntegration.DoesNotExist:
return Response(
{"error": "Workspace Integration Does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,231 @@
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from sentry_sdk import capture_exception
# Module imports
from plane.api.views import BaseViewSet, BaseAPIView
from plane.db.models import (
GithubIssueSync,
GithubRepositorySync,
GithubRepository,
WorkspaceIntegration,
ProjectMember,
Label,
GithubCommentSync,
Project,
)
from plane.api.serializers import (
GithubIssueSyncSerializer,
GithubRepositorySyncSerializer,
GithubCommentSyncSerializer,
)
from plane.utils.integrations.github import get_github_repos
from plane.api.permissions import ProjectBasePermission, ProjectEntityPermission
class GithubRepositoriesEndpoint(BaseAPIView):
permission_classes = [
ProjectBasePermission,
]
def get(self, request, slug, workspace_integration_id):
try:
page = request.GET.get("page", 1)
workspace_integration = WorkspaceIntegration.objects.get(
workspace__slug=slug, pk=workspace_integration_id
)
if workspace_integration.integration.provider != "github":
return Response(
{"error": "Not a github integration"},
status=status.HTTP_400_BAD_REQUEST,
)
access_tokens_url = workspace_integration.metadata["access_tokens_url"]
repositories_url = (
workspace_integration.metadata["repositories_url"]
+ f"?per_page=100&page={page}"
)
repositories = get_github_repos(access_tokens_url, repositories_url)
return Response(repositories, status=status.HTTP_200_OK)
except WorkspaceIntegration.DoesNotExist:
return Response(
{"error": "Workspace Integration Does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
class GithubRepositorySyncViewSet(BaseViewSet):
permission_classes = [
ProjectBasePermission,
]
serializer_class = GithubRepositorySyncSerializer
model = GithubRepositorySync
def perform_create(self, serializer):
serializer.save(project_id=self.kwargs.get("project_id"))
def get_queryset(self):
return (
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(project_id=self.kwargs.get("project_id"))
)
def create(self, request, slug, project_id, workspace_integration_id):
try:
name = request.data.get("name", False)
url = request.data.get("url", False)
config = request.data.get("config", {})
repository_id = request.data.get("repository_id", False)
owner = request.data.get("owner", False)
if not name or not url or not repository_id or not owner:
return Response(
{"error": "Name, url, repository_id and owner are required"},
status=status.HTTP_400_BAD_REQUEST,
)
# Get the workspace integration
workspace_integration = WorkspaceIntegration.objects.get(
pk=workspace_integration_id
)
# Delete the old repository object
GithubRepositorySync.objects.filter(
project_id=project_id, workspace__slug=slug
).delete()
GithubRepository.objects.filter(
project_id=project_id, workspace__slug=slug
).delete()
# Create repository
repo = GithubRepository.objects.create(
name=name,
url=url,
config=config,
repository_id=repository_id,
owner=owner,
project_id=project_id,
)
# Create a Label for github
label = Label.objects.filter(
name="GitHub",
project_id=project_id,
).first()
if label is None:
label = Label.objects.create(
name="GitHub",
project_id=project_id,
description="Label to sync Plane issues with GitHub issues",
color="#003773",
)
# Create repo sync
repo_sync = GithubRepositorySync.objects.create(
repository=repo,
workspace_integration=workspace_integration,
actor=workspace_integration.actor,
credentials=request.data.get("credentials", {}),
project_id=project_id,
label=label,
)
# Add bot as a member in the project
_ = ProjectMember.objects.get_or_create(
member=workspace_integration.actor, role=20, project_id=project_id
)
# Return Response
return Response(
GithubRepositorySyncSerializer(repo_sync).data,
status=status.HTTP_201_CREATED,
)
except WorkspaceIntegration.DoesNotExist:
return Response(
{"error": "Workspace Integration does not exist"},
status=status.HTTP_404_NOT_FOUND,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class GithubIssueSyncViewSet(BaseViewSet):
permission_classes = [
ProjectEntityPermission,
]
serializer_class = GithubIssueSyncSerializer
model = GithubIssueSync
def perform_create(self, serializer):
serializer.save(
project_id=self.kwargs.get("project_id"),
repository_sync_id=self.kwargs.get("repo_sync_id"),
)
class BulkCreateGithubIssueSyncEndpoint(BaseAPIView):
def post(self, request, slug, project_id, repo_sync_id):
try:
project = Project.objects.get(pk=project_id, workspace__slug=slug)
github_issue_syncs = request.data.get("github_issue_syncs", [])
github_issue_syncs = GithubIssueSync.objects.bulk_create(
[
GithubIssueSync(
issue_id=github_issue_sync.get("issue"),
repo_issue_id=github_issue_sync.get("repo_issue_id"),
issue_url=github_issue_sync.get("issue_url"),
github_issue_id=github_issue_sync.get("github_issue_id"),
repository_sync_id=repo_sync_id,
project_id=project_id,
workspace_id=project.workspace_id,
created_by=request.user,
updated_by=request.user,
)
for github_issue_sync in github_issue_syncs
],
batch_size=100,
ignore_conflicts=True,
)
serializer = GithubIssueSyncSerializer(github_issue_syncs, many=True)
return Response(serializer.data, status=status.HTTP_201_CREATED)
except Project.DoesNotExist:
return Response(
{"error": "Project does not exist"},
status=status.HTTP_404_NOT_FOUND,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class GithubCommentSyncViewSet(BaseViewSet):
permission_classes = [
ProjectEntityPermission,
]
serializer_class = GithubCommentSyncSerializer
model = GithubCommentSync
def perform_create(self, serializer):
serializer.save(
project_id=self.kwargs.get("project_id"),
issue_sync_id=self.kwargs.get("issue_sync_id"),
)

View File

@@ -0,0 +1,73 @@
# Django import
from django.db import IntegrityError
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from sentry_sdk import capture_exception
# Module imports
from plane.api.views import BaseViewSet, BaseAPIView
from plane.db.models import SlackProjectSync, WorkspaceIntegration, ProjectMember
from plane.api.serializers import SlackProjectSyncSerializer
from plane.api.permissions import ProjectBasePermission, ProjectEntityPermission
class SlackProjectSyncViewSet(BaseViewSet):
permission_classes = [
ProjectBasePermission,
]
serializer_class = SlackProjectSyncSerializer
model = SlackProjectSync
def get_queryset(self):
return (
super()
.get_queryset()
.filter(
workspace__slug=self.kwargs.get("slug"),
project_id=self.kwargs.get("project_id"),
)
.filter(project__project_projectmember__member=self.request.user)
)
def create(self, request, slug, project_id, workspace_integration_id):
try:
serializer = SlackProjectSyncSerializer(data=request.data)
workspace_integration = WorkspaceIntegration.objects.get(
workspace__slug=slug, pk=workspace_integration_id
)
if serializer.is_valid():
serializer.save(
project_id=project_id,
workspace_integration_id=workspace_integration_id,
)
workspace_integration = WorkspaceIntegration.objects.get(
pk=workspace_integration_id, workspace__slug=slug
)
_ = ProjectMember.objects.get_or_create(
member=workspace_integration.actor, role=20, project_id=project_id
)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except IntegrityError:
return Response(
{"error": "Slack is already enabled for the project"},
status=status.HTTP_400_BAD_REQUEST,
)
except WorkspaceIntegration.DoesNotExist:
return Response(
{"error": "Workspace Integration does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
print(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,13 @@
# Python imports
import json
# Django Imports
from django.utils import timezone
from django.db import IntegrityError
from django.db.models import Prefetch, F, OuterRef, Func
from django.db.models import Prefetch, F, OuterRef, Func, Exists, Count, Q
from django.core import serializers
from django.utils.decorators import method_decorator
from django.views.decorators.gzip import gzip_page
# Third party imports
from rest_framework.response import Response
@@ -13,6 +20,9 @@ from plane.api.serializers import (
ModuleWriteSerializer,
ModuleSerializer,
ModuleIssueSerializer,
ModuleLinkSerializer,
ModuleFavoriteSerializer,
IssueStateSerializer,
)
from plane.api.permissions import ProjectEntityPermission
from plane.db.models import (
@@ -21,11 +31,17 @@ from plane.db.models import (
Project,
Issue,
ModuleLink,
ModuleFavorite,
IssueLink,
IssueAttachment,
)
from plane.bgtasks.issue_activites_task import issue_activity
from plane.utils.grouper import group_results
from plane.utils.issue_filters import issue_filters
from plane.utils.analytics_plot import burndown_plot
class ModuleViewSet(BaseViewSet):
model = Module
permission_classes = [
ProjectEntityPermission,
@@ -39,31 +55,115 @@ class ModuleViewSet(BaseViewSet):
)
def get_queryset(self):
order_by = self.request.GET.get("order_by", "sort_order")
subquery = ModuleFavorite.objects.filter(
user=self.request.user,
module_id=OuterRef("pk"),
project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"),
)
return (
super()
.get_queryset()
.filter(project_id=self.kwargs.get("project_id"))
.filter(workspace__slug=self.kwargs.get("slug"))
.annotate(is_favorite=Exists(subquery))
.select_related("project")
.select_related("workspace")
.select_related("lead")
.prefetch_related("members")
.prefetch_related(
Prefetch(
"issue_module",
queryset=ModuleIssue.objects.select_related(
"module", "issue", "issue__state", "issue__project"
).prefetch_related("issue__assignees", "issue__labels"),
)
)
.prefetch_related(
Prefetch(
"link_module",
queryset=ModuleLink.objects.select_related("module", "created_by"),
)
)
.annotate(
total_issues=Count(
"issue_module",
filter=Q(
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
),
)
.annotate(
completed_issues=Count(
"issue_module__issue__state__group",
filter=Q(
issue_module__issue__state__group="completed",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
)
)
.annotate(
cancelled_issues=Count(
"issue_module__issue__state__group",
filter=Q(
issue_module__issue__state__group="cancelled",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
)
)
.annotate(
started_issues=Count(
"issue_module__issue__state__group",
filter=Q(
issue_module__issue__state__group="started",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
)
)
.annotate(
unstarted_issues=Count(
"issue_module__issue__state__group",
filter=Q(
issue_module__issue__state__group="unstarted",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
)
)
.annotate(
backlog_issues=Count(
"issue_module__issue__state__group",
filter=Q(
issue_module__issue__state__group="backlog",
issue_module__issue__archived_at__isnull=True,
issue_module__issue__is_draft=False,
),
)
)
.order_by(order_by, "name")
)
def perform_destroy(self, instance):
module_issues = list(
ModuleIssue.objects.filter(module_id=self.kwargs.get("pk")).values_list(
"issue", flat=True
)
)
issue_activity.delay(
type="module.activity.deleted",
requested_data=json.dumps(
{
"module_id": str(self.kwargs.get("pk")),
"issues": [str(issue_id) for issue_id in module_issues],
}
),
actor_id=str(self.request.user.id),
issue_id=str(self.kwargs.get("pk", None)),
project_id=str(self.kwargs.get("project_id", None)),
current_instance=None,
epoch=int(timezone.now().timestamp())
)
return super().perform_destroy(instance)
def create(self, request, slug, project_id):
try:
project = Project.objects.get(workspace__slug=slug, pk=project_id)
@@ -93,15 +193,130 @@ class ModuleViewSet(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST,
)
def retrieve(self, request, slug, project_id, pk):
try:
queryset = self.get_queryset().get(pk=pk)
assignee_distribution = (
Issue.objects.filter(
issue_module__module_id=pk,
workspace__slug=slug,
project_id=project_id,
)
.annotate(first_name=F("assignees__first_name"))
.annotate(last_name=F("assignees__last_name"))
.annotate(assignee_id=F("assignees__id"))
.annotate(display_name=F("assignees__display_name"))
.annotate(avatar=F("assignees__avatar"))
.values(
"first_name", "last_name", "assignee_id", "avatar", "display_name"
)
.annotate(
total_issues=Count(
"assignee_id",
filter=Q(
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
completed_issues=Count(
"assignee_id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"assignee_id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("first_name", "last_name")
)
label_distribution = (
Issue.objects.filter(
issue_module__module_id=pk,
workspace__slug=slug,
project_id=project_id,
)
.annotate(label_name=F("labels__name"))
.annotate(color=F("labels__color"))
.annotate(label_id=F("labels__id"))
.values("label_name", "color", "label_id")
.annotate(
total_issues=Count(
"label_id",
filter=Q(
archived_at__isnull=True,
is_draft=False,
),
),
)
.annotate(
completed_issues=Count(
"label_id",
filter=Q(
completed_at__isnull=False,
archived_at__isnull=True,
is_draft=False,
),
)
)
.annotate(
pending_issues=Count(
"label_id",
filter=Q(
completed_at__isnull=True,
archived_at__isnull=True,
is_draft=False,
),
)
)
.order_by("label_name")
)
data = ModuleSerializer(queryset).data
data["distribution"] = {
"assignees": assignee_distribution,
"labels": label_distribution,
"completion_chart": {},
}
if queryset.start_date and queryset.target_date:
data["distribution"]["completion_chart"] = burndown_plot(
queryset=queryset, slug=slug, project_id=project_id, module_id=pk
)
return Response(
data,
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class ModuleIssueViewSet(BaseViewSet):
serializer_class = ModuleIssueSerializer
model = ModuleIssue
filterset_fields = [
"issue__id",
"workspace__id",
"issue__labels__id",
"issue__assignees__id",
]
permission_classes = [
@@ -114,12 +329,29 @@ class ModuleIssueViewSet(BaseViewSet):
module_id=self.kwargs.get("module_id"),
)
def perform_destroy(self, instance):
issue_activity.delay(
type="module.activity.deleted",
requested_data=json.dumps(
{
"module_id": str(self.kwargs.get("module_id")),
"issues": [str(instance.issue_id)],
}
),
actor_id=str(self.request.user.id),
issue_id=str(self.kwargs.get("pk", None)),
project_id=str(self.kwargs.get("project_id", None)),
current_instance=None,
epoch=int(timezone.now().timestamp())
)
return super().perform_destroy(instance)
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.annotate(
sub_issues_count=Issue.objects.filter(parent=OuterRef("issue"))
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("issue"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
@@ -137,6 +369,73 @@ class ModuleIssueViewSet(BaseViewSet):
.distinct()
)
@method_decorator(gzip_page)
def list(self, request, slug, project_id, module_id):
try:
order_by = request.GET.get("order_by", "created_at")
group_by = request.GET.get("group_by", False)
sub_group_by = request.GET.get("sub_group_by", False)
filters = issue_filters(request.query_params, "GET")
issues = (
Issue.issue_objects.filter(issue_module__module_id=module_id)
.annotate(
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(bridge_id=F("issue_module__id"))
.filter(project_id=project_id)
.filter(workspace__slug=slug)
.select_related("project")
.select_related("workspace")
.select_related("state")
.select_related("parent")
.prefetch_related("assignees")
.prefetch_related("labels")
.order_by(order_by)
.filter(**filters)
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
)
issues_data = IssueStateSerializer(issues, many=True).data
if sub_group_by and sub_group_by == group_by:
return Response(
{"error": "Group by and sub group by cannot be same"},
status=status.HTTP_400_BAD_REQUEST,
)
if group_by:
return Response(
group_results(issues_data, group_by, sub_group_by),
status=status.HTTP_200_OK,
)
return Response(
issues_data,
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def create(self, request, slug, project_id, module_id):
try:
issues = request.data.get("issues", [])
@@ -148,29 +447,76 @@ class ModuleIssueViewSet(BaseViewSet):
workspace__slug=slug, project_id=project_id, pk=module_id
)
issues = Issue.objects.filter(
pk__in=issues, workspace__slug=slug, project_id=project_id
)
module_issues = list(ModuleIssue.objects.filter(issue_id__in=issues))
# Delete old records in order to maintain the database integrity
ModuleIssue.objects.filter(issue_id__in=issues).delete()
update_module_issue_activity = []
records_to_update = []
record_to_create = []
for issue in issues:
module_issue = [
module_issue
for module_issue in module_issues
if str(module_issue.issue_id) in issues
]
if len(module_issue):
if module_issue[0].module_id != module_id:
update_module_issue_activity.append(
{
"old_module_id": str(module_issue[0].module_id),
"new_module_id": str(module_id),
"issue_id": str(module_issue[0].issue_id),
}
)
module_issue[0].module_id = module_id
records_to_update.append(module_issue[0])
else:
record_to_create.append(
ModuleIssue(
module=module,
issue_id=issue,
project_id=project_id,
workspace=module.workspace,
created_by=request.user,
updated_by=request.user,
)
)
ModuleIssue.objects.bulk_create(
[
ModuleIssue(
module=module,
issue=issue,
project_id=project_id,
workspace=module.workspace,
created_by=request.user,
updated_by=request.user,
)
for issue in issues
],
record_to_create,
batch_size=10,
ignore_conflicts=True,
)
return Response({"message": "Success"}, status=status.HTTP_200_OK)
ModuleIssue.objects.bulk_update(
records_to_update,
["module"],
batch_size=10,
)
# Capture Issue Activity
issue_activity.delay(
type="module.activity.created",
requested_data=json.dumps({"modules_list": issues}),
actor_id=str(self.request.user.id),
issue_id=str(self.kwargs.get("pk", None)),
project_id=str(self.kwargs.get("project_id", None)),
current_instance=json.dumps(
{
"updated_module_issues": update_module_issue_activity,
"created_module_issues": serializers.serialize(
"json", record_to_create
),
}
),
epoch=int(timezone.now().timestamp())
)
return Response(
ModuleIssueSerializer(self.get_queryset(), many=True).data,
status=status.HTTP_200_OK,
)
except Module.DoesNotExist:
return Response(
{"error": "Module Does not exists"}, status=status.HTTP_400_BAD_REQUEST
@@ -181,3 +527,92 @@ class ModuleIssueViewSet(BaseViewSet):
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class ModuleLinkViewSet(BaseViewSet):
permission_classes = [
ProjectEntityPermission,
]
model = ModuleLink
serializer_class = ModuleLinkSerializer
def perform_create(self, serializer):
serializer.save(
project_id=self.kwargs.get("project_id"),
module_id=self.kwargs.get("module_id"),
)
def get_queryset(self):
return (
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(project_id=self.kwargs.get("project_id"))
.filter(module_id=self.kwargs.get("module_id"))
.filter(project__project_projectmember__member=self.request.user)
.order_by("-created_at")
.distinct()
)
class ModuleFavoriteViewSet(BaseViewSet):
serializer_class = ModuleFavoriteSerializer
model = ModuleFavorite
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(user=self.request.user)
.select_related("module")
)
def create(self, request, slug, project_id):
try:
serializer = ModuleFavoriteSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user, project_id=project_id)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except IntegrityError as e:
if "already exists" in str(e):
return Response(
{"error": "The module is already added to favorites"},
status=status.HTTP_410_GONE,
)
else:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, module_id):
try:
module_favorite = ModuleFavorite.objects.get(
project=project_id,
user=request.user,
workspace__slug=slug,
module_id=module_id,
)
module_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except ModuleFavorite.DoesNotExist:
return Response(
{"error": "Module is not in favorites"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,363 @@
# Django imports
from django.db.models import Q
from django.utils import timezone
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from sentry_sdk import capture_exception
from plane.utils.paginator import BasePaginator
# Module imports
from .base import BaseViewSet, BaseAPIView
from plane.db.models import (
Notification,
IssueAssignee,
IssueSubscriber,
Issue,
WorkspaceMember,
)
from plane.api.serializers import NotificationSerializer
class NotificationViewSet(BaseViewSet, BasePaginator):
model = Notification
serializer_class = NotificationSerializer
def get_queryset(self):
return (
super()
.get_queryset()
.filter(
workspace__slug=self.kwargs.get("slug"),
receiver_id=self.request.user.id,
)
.select_related("workspace", "project," "triggered_by", "receiver")
)
def list(self, request, slug):
try:
snoozed = request.GET.get("snoozed", "false")
archived = request.GET.get("archived", "false")
read = request.GET.get("read", "true")
# Filter type
type = request.GET.get("type", "all")
notifications = (
Notification.objects.filter(
workspace__slug=slug, receiver_id=request.user.id
)
.select_related("workspace", "project", "triggered_by", "receiver")
.order_by("snoozed_till", "-created_at")
)
# Filter for snoozed notifications
if snoozed == "false":
notifications = notifications.filter(
Q(snoozed_till__gte=timezone.now()) | Q(snoozed_till__isnull=True),
)
if snoozed == "true":
notifications = notifications.filter(
Q(snoozed_till__lt=timezone.now()) | Q(snoozed_till__isnull=False)
)
if read == "false":
notifications = notifications.filter(read_at__isnull=True)
# Filter for archived or unarchive
if archived == "false":
notifications = notifications.filter(archived_at__isnull=True)
if archived == "true":
notifications = notifications.filter(archived_at__isnull=False)
# Subscribed issues
if type == "watching":
issue_ids = IssueSubscriber.objects.filter(
workspace__slug=slug, subscriber_id=request.user.id
).values_list("issue_id", flat=True)
notifications = notifications.filter(entity_identifier__in=issue_ids)
# Assigned Issues
if type == "assigned":
issue_ids = IssueAssignee.objects.filter(
workspace__slug=slug, assignee_id=request.user.id
).values_list("issue_id", flat=True)
notifications = notifications.filter(entity_identifier__in=issue_ids)
# Created issues
if type == "created":
if WorkspaceMember.objects.filter(
workspace__slug=slug, member=request.user, role__lt=15
).exists():
notifications = Notification.objects.none()
else:
issue_ids = Issue.objects.filter(
workspace__slug=slug, created_by=request.user
).values_list("pk", flat=True)
notifications = notifications.filter(
entity_identifier__in=issue_ids
)
# Pagination
if request.GET.get("per_page", False) and request.GET.get("cursor", False):
return self.paginate(
request=request,
queryset=(notifications),
on_results=lambda notifications: NotificationSerializer(
notifications, many=True
).data,
)
serializer = NotificationSerializer(notifications, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def partial_update(self, request, slug, pk):
try:
notification = Notification.objects.get(
workspace__slug=slug, pk=pk, receiver=request.user
)
# Only read_at and snoozed_till can be updated
notification_data = {
"snoozed_till": request.data.get("snoozed_till", None),
}
serializer = NotificationSerializer(
notification, data=notification_data, partial=True
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Notification.DoesNotExist:
return Response(
{"error": "Notification does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def mark_read(self, request, slug, pk):
try:
notification = Notification.objects.get(
receiver=request.user, workspace__slug=slug, pk=pk
)
notification.read_at = timezone.now()
notification.save()
serializer = NotificationSerializer(notification)
return Response(serializer.data, status=status.HTTP_200_OK)
except Notification.DoesNotExist:
return Response(
{"error": "Notification does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def mark_unread(self, request, slug, pk):
try:
notification = Notification.objects.get(
receiver=request.user, workspace__slug=slug, pk=pk
)
notification.read_at = None
notification.save()
serializer = NotificationSerializer(notification)
return Response(serializer.data, status=status.HTTP_200_OK)
except Notification.DoesNotExist:
return Response(
{"error": "Notification does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def archive(self, request, slug, pk):
try:
notification = Notification.objects.get(
receiver=request.user, workspace__slug=slug, pk=pk
)
notification.archived_at = timezone.now()
notification.save()
serializer = NotificationSerializer(notification)
return Response(serializer.data, status=status.HTTP_200_OK)
except Notification.DoesNotExist:
return Response(
{"error": "Notification does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def unarchive(self, request, slug, pk):
try:
notification = Notification.objects.get(
receiver=request.user, workspace__slug=slug, pk=pk
)
notification.archived_at = None
notification.save()
serializer = NotificationSerializer(notification)
return Response(serializer.data, status=status.HTTP_200_OK)
except Notification.DoesNotExist:
return Response(
{"error": "Notification does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class UnreadNotificationEndpoint(BaseAPIView):
def get(self, request, slug):
try:
# Watching Issues Count
watching_issues_count = Notification.objects.filter(
workspace__slug=slug,
receiver_id=request.user.id,
read_at__isnull=True,
archived_at__isnull=True,
entity_identifier__in=IssueSubscriber.objects.filter(
workspace__slug=slug, subscriber_id=request.user.id
).values_list("issue_id", flat=True),
).count()
# My Issues Count
my_issues_count = Notification.objects.filter(
workspace__slug=slug,
receiver_id=request.user.id,
read_at__isnull=True,
archived_at__isnull=True,
entity_identifier__in=IssueAssignee.objects.filter(
workspace__slug=slug, assignee_id=request.user.id
).values_list("issue_id", flat=True),
).count()
# Created Issues Count
created_issues_count = Notification.objects.filter(
workspace__slug=slug,
receiver_id=request.user.id,
read_at__isnull=True,
archived_at__isnull=True,
entity_identifier__in=Issue.objects.filter(
workspace__slug=slug, created_by=request.user
).values_list("pk", flat=True),
).count()
return Response(
{
"watching_issues": watching_issues_count,
"my_issues": my_issues_count,
"created_issues": created_issues_count,
},
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class MarkAllReadNotificationViewSet(BaseViewSet):
def create(self, request, slug):
try:
snoozed = request.data.get("snoozed", False)
archived = request.data.get("archived", False)
type = request.data.get("type", "all")
notifications = (
Notification.objects.filter(
workspace__slug=slug,
receiver_id=request.user.id,
read_at__isnull=True,
)
.select_related("workspace", "project", "triggered_by", "receiver")
.order_by("snoozed_till", "-created_at")
)
# Filter for snoozed notifications
if snoozed:
notifications = notifications.filter(
Q(snoozed_till__lt=timezone.now()) | Q(snoozed_till__isnull=False)
)
else:
notifications = notifications.filter(
Q(snoozed_till__gte=timezone.now()) | Q(snoozed_till__isnull=True),
)
# Filter for archived or unarchive
if archived:
notifications = notifications.filter(archived_at__isnull=False)
else:
notifications = notifications.filter(archived_at__isnull=True)
# Subscribed issues
if type == "watching":
issue_ids = IssueSubscriber.objects.filter(
workspace__slug=slug, subscriber_id=request.user.id
).values_list("issue_id", flat=True)
notifications = notifications.filter(entity_identifier__in=issue_ids)
# Assigned Issues
if type == "assigned":
issue_ids = IssueAssignee.objects.filter(
workspace__slug=slug, assignee_id=request.user.id
).values_list("issue_id", flat=True)
notifications = notifications.filter(entity_identifier__in=issue_ids)
# Created issues
if type == "created":
if WorkspaceMember.objects.filter(
workspace__slug=slug, member=request.user, role__lt=15
).exists():
notifications = Notification.objects.none()
else:
issue_ids = Issue.objects.filter(
workspace__slug=slug, created_by=request.user
).values_list("pk", flat=True)
notifications = notifications.filter(
entity_identifier__in=issue_ids
)
updated_notifications = []
for notification in notifications:
notification.read_at = timezone.now()
updated_notifications.append(notification)
Notification.objects.bulk_update(
updated_notifications, ["read_at"], batch_size=100
)
return Response({"message": "Successful"}, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -5,6 +5,7 @@ import os
# Django imports
from django.utils import timezone
from django.conf import settings
# Third Party modules
from rest_framework.response import Response
@@ -13,7 +14,7 @@ from rest_framework.permissions import AllowAny
from rest_framework.views import APIView
from rest_framework_simplejwt.tokens import RefreshToken
from rest_framework import status
from sentry_sdk import capture_exception
# sso authentication
from google.oauth2 import id_token
from google.auth.transport import requests as google_auth_request
@@ -34,7 +35,6 @@ def get_tokens_for_user(user):
def validate_google_token(token, client_id):
try:
id_info = id_token.verify_oauth2_token(
token, google_auth_request.Request(), client_id
)
@@ -48,7 +48,7 @@ def validate_google_token(token, client_id):
}
return data
except Exception as e:
print(e)
capture_exception(e)
raise exceptions.AuthenticationFailed("Error with Google connection.")
@@ -106,9 +106,19 @@ def get_user_data(access_token: str) -> dict:
resp = requests.get(url=url, headers=headers)
userData = resp.json()
user_data = resp.json()
return userData
response = requests.get(
url="https://api.github.com/user/emails", headers=headers
).json()
[
user_data.update({"email": item.get("email")})
for item in response
if item.get("primary") is True
]
return user_data
class OauthEndpoint(BaseAPIView):
@@ -116,7 +126,6 @@ class OauthEndpoint(BaseAPIView):
def post(self, request):
try:
medium = request.data.get("medium", False)
id_token = request.data.get("credential", False)
client_id = request.data.get("clientId", False)
@@ -138,7 +147,6 @@ class OauthEndpoint(BaseAPIView):
email = data.get("email", None)
if email == None:
return Response(
{
"error": "Something went wrong. Please try again later or contact the support team."
@@ -153,7 +161,6 @@ class OauthEndpoint(BaseAPIView):
mobile_number = uuid.uuid4().hex
email_verified = True
else:
return Response(
{
"error": "Something went wrong. Please try again later or contact the support team."
@@ -198,7 +205,26 @@ class OauthEndpoint(BaseAPIView):
"last_login_at": timezone.now(),
},
)
if settings.ANALYTICS_BASE_API:
_ = requests.post(
settings.ANALYTICS_BASE_API,
headers={
"Content-Type": "application/json",
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
},
json={
"event_id": uuid.uuid4().hex,
"event_data": {
"medium": f"oauth-{medium}",
},
"user": {"email": email, "id": str(user.id)},
"device_ctx": {
"ip": request.META.get("REMOTE_ADDR"),
"user_agent": request.META.get("HTTP_USER_AGENT"),
},
"event_type": "SIGN_IN",
},
)
return Response(data, status=status.HTTP_200_OK)
except User.DoesNotExist:
@@ -247,6 +273,26 @@ class OauthEndpoint(BaseAPIView):
"user": serialized_user,
"permissions": [],
}
if settings.ANALYTICS_BASE_API:
_ = requests.post(
settings.ANALYTICS_BASE_API,
headers={
"Content-Type": "application/json",
"X-Auth-Token": settings.ANALYTICS_SECRET_KEY,
},
json={
"event_id": uuid.uuid4().hex,
"event_data": {
"medium": f"oauth-{medium}",
},
"user": {"email": email, "id": str(user.id)},
"device_ctx": {
"ip": request.META.get("REMOTE_ADDR"),
"user_agent": request.META.get("HTTP_USER_AGENT"),
},
"event_type": "SIGN_UP",
},
)
SocialLoginConnection.objects.update_or_create(
medium=medium,
@@ -259,8 +305,7 @@ class OauthEndpoint(BaseAPIView):
)
return Response(data, status=status.HTTP_201_CREATED)
except Exception as e:
print(e)
capture_exception(e)
return Response(
{
"error": "Something went wrong. Please try again later or contact the support team."

View File

@@ -0,0 +1,321 @@
# Python imports
from datetime import timedelta, datetime, date
# Django imports
from django.db import IntegrityError
from django.db.models import Exists, OuterRef, Q, Prefetch
from django.utils import timezone
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from sentry_sdk import capture_exception
# Module imports
from .base import BaseViewSet, BaseAPIView
from plane.api.permissions import ProjectEntityPermission
from plane.db.models import (
Page,
PageBlock,
PageFavorite,
Issue,
IssueAssignee,
IssueActivity,
)
from plane.api.serializers import (
PageSerializer,
PageBlockSerializer,
PageFavoriteSerializer,
IssueLiteSerializer,
)
class PageViewSet(BaseViewSet):
serializer_class = PageSerializer
model = Page
permission_classes = [
ProjectEntityPermission,
]
search_fields = [
"name",
]
def get_queryset(self):
subquery = PageFavorite.objects.filter(
user=self.request.user,
page_id=OuterRef("pk"),
project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"),
)
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(project_id=self.kwargs.get("project_id"))
.filter(project__project_projectmember__member=self.request.user)
.filter(Q(owned_by=self.request.user) | Q(access=0))
.select_related("project")
.select_related("workspace")
.select_related("owned_by")
.annotate(is_favorite=Exists(subquery))
.order_by(self.request.GET.get("order_by", "-created_at"))
.prefetch_related("labels")
.order_by("name", "-is_favorite")
.prefetch_related(
Prefetch(
"blocks",
queryset=PageBlock.objects.select_related(
"page", "issue", "workspace", "project"
),
)
)
.distinct()
)
def perform_create(self, serializer):
serializer.save(
project_id=self.kwargs.get("project_id"), owned_by=self.request.user
)
def create(self, request, slug, project_id):
try:
serializer = PageSerializer(
data=request.data,
context={"project_id": project_id, "owned_by_id": request.user.id},
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def partial_update(self, request, slug, project_id, pk):
try:
page = Page.objects.get(pk=pk, workspace__slug=slug, project_id=project_id)
# Only update access if the page owner is the requesting user
if (
page.access != request.data.get("access", page.access)
and page.owned_by_id != request.user.id
):
return Response(
{
"error": "Access cannot be updated since this page is owned by someone else"
},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = PageSerializer(page, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Page.DoesNotExist:
return Response(
{"error": "Page Does not exist"}, status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def list(self, request, slug, project_id):
try:
queryset = self.get_queryset()
page_view = request.GET.get("page_view", False)
if not page_view:
return Response({"error": "Page View parameter is required"}, status=status.HTTP_400_BAD_REQUEST)
# All Pages
if page_view == "all":
return Response(PageSerializer(queryset, many=True).data, status=status.HTTP_200_OK)
# Recent pages
if page_view == "recent":
current_time = date.today()
day_before = current_time - timedelta(days=1)
todays_pages = queryset.filter(updated_at__date=date.today())
yesterdays_pages = queryset.filter(updated_at__date=day_before)
earlier_this_week = queryset.filter( updated_at__date__range=(
(timezone.now() - timedelta(days=7)),
(timezone.now() - timedelta(days=2)),
))
return Response(
{
"today": PageSerializer(todays_pages, many=True).data,
"yesterday": PageSerializer(yesterdays_pages, many=True).data,
"earlier_this_week": PageSerializer(earlier_this_week, many=True).data,
},
status=status.HTTP_200_OK,
)
# Favorite Pages
if page_view == "favorite":
queryset = queryset.filter(is_favorite=True)
return Response(PageSerializer(queryset, many=True).data, status=status.HTTP_200_OK)
# My pages
if page_view == "created_by_me":
queryset = queryset.filter(owned_by=request.user)
return Response(PageSerializer(queryset, many=True).data, status=status.HTTP_200_OK)
# Created by other Pages
if page_view == "created_by_other":
queryset = queryset.filter(~Q(owned_by=request.user), access=0)
return Response(PageSerializer(queryset, many=True).data, status=status.HTTP_200_OK)
return Response({"error": "No matching view found"}, status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
capture_exception(e)
return Response({"error": "Something went wrong please try again later"}, status=status.HTTP_400_BAD_REQUEST)
class PageBlockViewSet(BaseViewSet):
serializer_class = PageBlockSerializer
model = PageBlock
permission_classes = [
ProjectEntityPermission,
]
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(project_id=self.kwargs.get("project_id"))
.filter(page_id=self.kwargs.get("page_id"))
.filter(project__project_projectmember__member=self.request.user)
.select_related("project")
.select_related("workspace")
.select_related("page")
.select_related("issue")
.order_by("sort_order")
.distinct()
)
def perform_create(self, serializer):
serializer.save(
project_id=self.kwargs.get("project_id"),
page_id=self.kwargs.get("page_id"),
)
class PageFavoriteViewSet(BaseViewSet):
permission_classes = [
ProjectEntityPermission,
]
serializer_class = PageFavoriteSerializer
model = PageFavorite
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(user=self.request.user)
.select_related("page", "page__owned_by")
)
def create(self, request, slug, project_id):
try:
serializer = PageFavoriteSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user, project_id=project_id)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except IntegrityError as e:
if "already exists" in str(e):
return Response(
{"error": "The page is already added to favorites"},
status=status.HTTP_410_GONE,
)
else:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, page_id):
try:
page_favorite = PageFavorite.objects.get(
project=project_id,
user=request.user,
workspace__slug=slug,
page_id=page_id,
)
page_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except PageFavorite.DoesNotExist:
return Response(
{"error": "Page is not in favorites"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class CreateIssueFromPageBlockEndpoint(BaseAPIView):
permission_classes = [
ProjectEntityPermission,
]
def post(self, request, slug, project_id, page_id, page_block_id):
try:
page_block = PageBlock.objects.get(
pk=page_block_id,
workspace__slug=slug,
project_id=project_id,
page_id=page_id,
)
issue = Issue.objects.create(
name=page_block.name,
project_id=project_id,
description=page_block.description,
description_html=page_block.description_html,
description_stripped=page_block.description_stripped,
)
_ = IssueAssignee.objects.create(
issue=issue, assignee=request.user, project_id=project_id
)
_ = IssueActivity.objects.create(
issue=issue,
actor=request.user,
project_id=project_id,
comment=f"created the issue from {page_block.name} block",
verb="created",
)
page_block.issue = issue
page_block.save()
return Response(IssueLiteSerializer(issue).data, status=status.HTTP_200_OK)
except PageBlock.DoesNotExist:
return Response(
{"error": "Page Block does not exist"}, status=status.HTTP_404_NOT_FOUND
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -1,51 +0,0 @@
# Third party imports
from rest_framework.response import Response
from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from plane.api.serializers import (
UserSerializer,
)
from plane.api.views.base import BaseViewSet, BaseAPIView
from plane.db.models import User, Workspace
class UserEndpoint(BaseViewSet):
serializer_class = UserSerializer
model = User
def get_object(self):
return self.request.user
def retrieve(self, request):
try:
workspace = Workspace.objects.get(pk=request.user.last_workspace_id)
return Response(
{"user": UserSerializer(request.user).data, "slug": workspace.slug}
)
except Workspace.DoesNotExist:
return Response({"user": UserSerializer(request.user).data, "slug": None})
except Exception as e:
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class UpdateUserOnBoardedEndpoint(BaseAPIView):
def patch(self, request):
try:
user = User.objects.get(pk=request.user.id)
user.is_onboarded = request.data.get("is_onboarded", False)
user.save()
return Response(
{"message": "Updated successfully"}, status=status.HTTP_200_OK
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -5,7 +5,15 @@ from datetime import datetime
# Django imports
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from django.db.models import Q
from django.db.models import (
Q,
Exists,
OuterRef,
Func,
F,
Func,
Subquery,
)
from django.core.validators import validate_email
from django.conf import settings
@@ -13,6 +21,7 @@ from django.conf import settings
from rest_framework.response import Response
from rest_framework import status
from rest_framework import serializers
from rest_framework.permissions import AllowAny
from sentry_sdk import capture_exception
# Module imports
@@ -22,9 +31,18 @@ from plane.api.serializers import (
ProjectMemberSerializer,
ProjectDetailSerializer,
ProjectMemberInviteSerializer,
ProjectFavoriteSerializer,
IssueLiteSerializer,
ProjectDeployBoardSerializer,
ProjectMemberAdminSerializer,
)
from plane.api.permissions import ProjectBasePermission
from plane.api.permissions import (
ProjectBasePermission,
ProjectEntityPermission,
ProjectMemberPermission,
ProjectLitePermission,
)
from plane.db.models import (
Project,
@@ -35,16 +53,21 @@ from plane.db.models import (
WorkspaceMember,
State,
TeamMember,
ProjectFavorite,
ProjectIdentifier,
Module,
Cycle,
CycleFavorite,
ModuleFavorite,
PageFavorite,
IssueViewFavorite,
Page,
IssueAssignee,
ModuleMember,
Inbox,
ProjectDeployBoard,
)
from plane.db.models import (
Project,
ProjectMember,
Workspace,
ProjectMemberInvite,
User,
ProjectIdentifier,
)
from plane.bgtasks.project_invitation_task import project_invitation
@@ -62,6 +85,12 @@ class ProjectViewSet(BaseViewSet):
return ProjectDetailSerializer
def get_queryset(self):
subquery = ProjectFavorite.objects.filter(
user=self.request.user,
project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"),
)
return self.filter_queryset(
super()
.get_queryset()
@@ -70,12 +99,108 @@ class ProjectViewSet(BaseViewSet):
.select_related(
"workspace", "workspace__owner", "default_assignee", "project_lead"
)
.annotate(is_favorite=Exists(subquery))
.annotate(
is_member=Exists(
ProjectMember.objects.filter(
member=self.request.user,
project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"),
)
)
)
.annotate(
total_members=ProjectMember.objects.filter(
project_id=OuterRef("id"), member__is_bot=False
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
total_cycles=Cycle.objects.filter(project_id=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
total_modules=Module.objects.filter(project_id=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
member_role=ProjectMember.objects.filter(
project_id=OuterRef("pk"),
member_id=self.request.user.id,
).values("role")
)
.annotate(
is_deployed=Exists(
ProjectDeployBoard.objects.filter(
project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"),
)
)
)
.distinct()
)
def list(self, request, slug):
try:
is_favorite = request.GET.get("is_favorite", "all")
subquery = ProjectFavorite.objects.filter(
user=self.request.user,
project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"),
)
sort_order_query = ProjectMember.objects.filter(
member=request.user,
project_id=OuterRef("pk"),
workspace__slug=self.kwargs.get("slug"),
).values("sort_order")
projects = (
self.get_queryset()
.annotate(is_favorite=Exists(subquery))
.annotate(sort_order=Subquery(sort_order_query))
.order_by("sort_order", "name")
.annotate(
total_members=ProjectMember.objects.filter(
project_id=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
total_cycles=Cycle.objects.filter(project_id=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
total_modules=Module.objects.filter(project_id=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
)
if is_favorite == "true":
projects = projects.filter(is_favorite=True)
if is_favorite == "false":
projects = projects.filter(is_favorite=False)
return Response(ProjectDetailSerializer(projects, many=True).data)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def create(self, request, slug):
try:
workspace = Workspace.objects.get(slug=slug)
serializer = ProjectSerializer(
@@ -84,40 +209,50 @@ class ProjectViewSet(BaseViewSet):
if serializer.is_valid():
serializer.save()
## Add the user as Administrator to the project
ProjectMember.objects.create(
# Add the user as Administrator to the project
project_member = ProjectMember.objects.create(
project_id=serializer.data["id"], member=request.user, role=20
)
## Default states
if serializer.data["project_lead"] is not None and str(
serializer.data["project_lead"]
) != str(request.user.id):
ProjectMember.objects.create(
project_id=serializer.data["id"],
member_id=serializer.data["project_lead"],
role=20,
)
# Default states
states = [
{
"name": "Backlog",
"color": "#5e6ad2",
"color": "#A3A3A3",
"sequence": 15000,
"group": "backlog",
"default": True,
},
{
"name": "Todo",
"color": "#eb5757",
"color": "#3A3A3A",
"sequence": 25000,
"group": "unstarted",
},
{
"name": "In Progress",
"color": "#26b5ce",
"color": "#F59E0B",
"sequence": 35000,
"group": "started",
},
{
"name": "Done",
"color": "#f2c94c",
"color": "#16A34A",
"sequence": 45000,
"group": "completed",
},
{
"name": "Cancelled",
"color": "#4cb782",
"color": "#EF4444",
"sequence": 55000,
"group": "cancelled",
},
@@ -132,14 +267,21 @@ class ProjectViewSet(BaseViewSet):
sequence=state["sequence"],
workspace=serializer.instance.workspace,
group=state["group"],
default=state.get("default", False),
created_by=request.user,
)
for state in states
]
)
return Response(serializer.data, status=status.HTTP_201_CREATED)
data = serializer.data
# Additional fields of the member
data["sort_order"] = project_member.sort_order
data["member_role"] = project_member.role
data["is_member"] = True
return Response(data, status=status.HTTP_201_CREATED)
return Response(
[serializer.errors[error][0] for error in serializer.errors],
serializer.errors,
status=status.HTTP_400_BAD_REQUEST,
)
except IntegrityError as e:
@@ -148,6 +290,12 @@ class ProjectViewSet(BaseViewSet):
{"name": "The project name is already taken"},
status=status.HTTP_410_GONE,
)
else:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_410_GONE,
)
except Workspace.DoesNotExist as e:
return Response(
{"error": "Workspace does not exist"}, status=status.HTTP_404_NOT_FOUND
@@ -179,6 +327,20 @@ class ProjectViewSet(BaseViewSet):
if serializer.is_valid():
serializer.save()
if serializer.data["inbox_view"]:
Inbox.objects.get_or_create(
name=f"{project.name} Inbox", project=project, is_default=True
)
# Create the triage state in Backlog group
State.objects.get_or_create(
name="Triage",
group="backlog",
description="Default state for managing all Inbox Issues",
project_id=pk,
color="#ff7700",
)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@@ -188,7 +350,7 @@ class ProjectViewSet(BaseViewSet):
{"name": "The project name is already taken"},
status=status.HTTP_410_GONE,
)
except (Project.DoesNotExist or Workspace.DoesNotExist) as e:
except Project.DoesNotExist or Workspace.DoesNotExist as e:
return Response(
{"error": "Project does not exist"}, status=status.HTTP_404_NOT_FOUND
)
@@ -206,14 +368,12 @@ class ProjectViewSet(BaseViewSet):
class InviteProjectEndpoint(BaseAPIView):
permission_classes = [
ProjectBasePermission,
]
def post(self, request, slug, project_id):
try:
email = request.data.get("email", False)
role = request.data.get("role", False)
@@ -226,7 +386,9 @@ class InviteProjectEndpoint(BaseAPIView):
validate_email(email)
# Check if user is already a member of workspace
if ProjectMember.objects.filter(
project_id=project_id, member__email=email
project_id=project_id,
member__email=email,
member__is_bot=False,
).exists():
return Response(
{"error": "User is already member of workspace"},
@@ -287,7 +449,6 @@ class InviteProjectEndpoint(BaseAPIView):
class UserProjectInvitationsViewset(BaseViewSet):
serializer_class = ProjectMemberInviteSerializer
model = ProjectMemberInvite
@@ -301,7 +462,6 @@ class UserProjectInvitationsViewset(BaseViewSet):
def create(self, request):
try:
invitations = request.data.get("invitations")
project_invitations = ProjectMemberInvite.objects.filter(
pk__in=invitations, accepted=True
@@ -313,15 +473,16 @@ class UserProjectInvitationsViewset(BaseViewSet):
workspace=invitation.project.workspace,
member=request.user,
role=invitation.role,
created_by=request.user,
)
for invitation in project_invitations
]
)
## Delete joined project invites
# Delete joined project invites
project_invitations.delete()
return Response(status=status.HTTP_200_OK)
return Response(status=status.HTTP_204_NO_CONTENT)
except Exception as e:
capture_exception(e)
return Response(
@@ -331,15 +492,14 @@ class UserProjectInvitationsViewset(BaseViewSet):
class ProjectMemberViewSet(BaseViewSet):
serializer_class = ProjectMemberSerializer
serializer_class = ProjectMemberAdminSerializer
model = ProjectMember
permission_classes = [
ProjectBasePermission,
]
search_fields = [
"member__email",
"member__display_name",
"member__first_name",
]
@@ -349,60 +509,188 @@ class ProjectMemberViewSet(BaseViewSet):
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(project_id=self.kwargs.get("project_id"))
.filter(member__is_bot=False)
.select_related("project")
.select_related("member")
.select_related("workspace", "workspace__owner")
)
def partial_update(self, request, slug, project_id, pk):
try:
project_member = ProjectMember.objects.get(
pk=pk, workspace__slug=slug, project_id=project_id
)
if request.user.id == project_member.member_id:
return Response(
{"error": "You cannot update your own role"},
status=status.HTTP_400_BAD_REQUEST,
)
# Check while updating user roles
requested_project_member = ProjectMember.objects.get(
project_id=project_id, workspace__slug=slug, member=request.user
)
if (
"role" in request.data
and int(request.data.get("role", project_member.role))
> requested_project_member.role
):
return Response(
{
"error": "You cannot update a role that is higher than your own role"
},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = ProjectMemberSerializer(
project_member, data=request.data, partial=True
)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except ProjectMember.DoesNotExist:
return Response(
{"error": "Project Member does not exist"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, pk):
try:
project_member = ProjectMember.objects.get(
workspace__slug=slug, project_id=project_id, pk=pk
)
# check requesting user role
requesting_project_member = ProjectMember.objects.get(
workspace__slug=slug, member=request.user, project_id=project_id
)
if requesting_project_member.role < project_member.role:
return Response(
{
"error": "You cannot remove a user having role higher than yourself"
},
status=status.HTTP_400_BAD_REQUEST,
)
# Remove all favorites
ProjectFavorite.objects.filter(
workspace__slug=slug, project_id=project_id, user=project_member.member
).delete()
CycleFavorite.objects.filter(
workspace__slug=slug, project_id=project_id, user=project_member.member
).delete()
ModuleFavorite.objects.filter(
workspace__slug=slug, project_id=project_id, user=project_member.member
).delete()
PageFavorite.objects.filter(
workspace__slug=slug, project_id=project_id, user=project_member.member
).delete()
IssueViewFavorite.objects.filter(
workspace__slug=slug, project_id=project_id, user=project_member.member
).delete()
# Also remove issue from issue assigned
IssueAssignee.objects.filter(
workspace__slug=slug,
project_id=project_id,
assignee=project_member.member,
).delete()
# Remove if module member
ModuleMember.objects.filter(
workspace__slug=slug,
project_id=project_id,
member=project_member.member,
).delete()
# Delete owned Pages
Page.objects.filter(
workspace__slug=slug,
project_id=project_id,
owned_by=project_member.member,
).delete()
project_member.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except ProjectMember.DoesNotExist:
return Response(
{"error": "Project Member does not exist"}, status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
capture_exception(e)
return Response({"error": "Something went wrong please try again later"})
class AddMemberToProjectEndpoint(BaseAPIView):
permission_classes = [
ProjectBasePermission,
]
def post(self, request, slug, project_id):
try:
members = request.data.get("members", [])
member_id = request.data.get("member_id", False)
role = request.data.get("role", False)
# get the project
project = Project.objects.get(pk=project_id, workspace__slug=slug)
if not member_id or not role:
if not len(members):
return Response(
{"error": "Member ID and role is required"},
{"error": "Atleast one member is required"},
status=status.HTTP_400_BAD_REQUEST,
)
bulk_project_members = []
# Check if the user is a member in the workspace
if not WorkspaceMember.objects.filter(
workspace__slug=slug, member_id=member_id
).exists():
# TODO: Update this error message - nk
return Response(
{
"error": "User is not a member of the workspace. Invite the user to the workspace to add him to project"
},
status=status.HTTP_400_BAD_REQUEST,
project_members = (
ProjectMember.objects.filter(
workspace__slug=slug,
member_id__in=[member.get("member_id") for member in members],
)
# Check if the user is already member of project
if ProjectMember.objects.filter(
project=project_id, member_id=member_id
).exists():
return Response(
{"error": "User is already a member of the project"},
status=status.HTTP_400_BAD_REQUEST,
)
# Add the user to project
project_member = ProjectMember.objects.create(
project_id=project_id, member_id=member_id, role=role
.values("member_id", "sort_order")
.order_by("sort_order")
)
serializer = ProjectMemberSerializer(project_member)
for member in members:
sort_order = [
project_member.get("sort_order")
for project_member in project_members
if str(project_member.get("member_id"))
== str(member.get("member_id"))
]
bulk_project_members.append(
ProjectMember(
member_id=member.get("member_id"),
role=member.get("role", 10),
project_id=project_id,
workspace_id=project.workspace_id,
sort_order=sort_order[0] - 10000 if len(sort_order) else 65535,
)
)
project_members = ProjectMember.objects.bulk_create(
bulk_project_members,
batch_size=10,
ignore_conflicts=True,
)
serializer = ProjectMemberSerializer(project_members, many=True)
return Response(serializer.data, status=status.HTTP_201_CREATED)
except KeyError:
return Response(
{"error": "Incorrect data sent"}, status=status.HTTP_400_BAD_REQUEST
)
except Project.DoesNotExist:
return Response(
{"error": "Project does not exist"}, status=status.HTTP_400_BAD_REQUEST
)
except IntegrityError:
return Response(
{"error": "User not member of the workspace"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
@@ -412,13 +700,11 @@ class AddMemberToProjectEndpoint(BaseAPIView):
class AddTeamToProjectEndpoint(BaseAPIView):
permission_classes = [
ProjectBasePermission,
]
def post(self, request, slug, project_id):
try:
team_members = TeamMember.objects.filter(
workspace__slug=slug, team__in=request.data.get("teams", [])
@@ -438,6 +724,7 @@ class AddTeamToProjectEndpoint(BaseAPIView):
project_id=project_id,
member_id=member,
workspace=workspace,
created_by=request.user,
)
)
@@ -467,7 +754,6 @@ class AddTeamToProjectEndpoint(BaseAPIView):
class ProjectMemberInvitationsViewset(BaseViewSet):
serializer_class = ProjectMemberInviteSerializer
model = ProjectMemberInvite
@@ -489,7 +775,6 @@ class ProjectMemberInvitationsViewset(BaseViewSet):
class ProjectMemberInviteDetailViewSet(BaseViewSet):
serializer_class = ProjectMemberInviteSerializer
model = ProjectMemberInvite
@@ -509,14 +794,12 @@ class ProjectMemberInviteDetailViewSet(BaseViewSet):
class ProjectIdentifierEndpoint(BaseAPIView):
permission_classes = [
ProjectBasePermission,
]
def get(self, request, slug):
try:
name = request.GET.get("name", "").strip().upper()
if name == "":
@@ -541,7 +824,6 @@ class ProjectIdentifierEndpoint(BaseAPIView):
def delete(self, request, slug):
try:
name = request.data.get("name", "").strip().upper()
if name == "":
@@ -590,6 +872,7 @@ class ProjectJoinEndpoint(BaseAPIView):
if workspace_role >= 15
else (15 if workspace_role == 10 else workspace_role),
workspace=workspace,
created_by=request.user,
)
for project_id in project_ids
],
@@ -616,7 +899,6 @@ class ProjectJoinEndpoint(BaseAPIView):
class ProjectUserViewsEndpoint(BaseAPIView):
def post(self, request, slug, project_id):
try:
project = Project.objects.get(pk=project_id, workspace__slug=slug)
project_member = ProjectMember.objects.filter(
@@ -630,16 +912,19 @@ class ProjectUserViewsEndpoint(BaseAPIView):
view_props = project_member.view_props
default_props = project_member.default_props
preferences = project_member.preferences
sort_order = project_member.sort_order
project_member.view_props = request.data.get("view_props", view_props)
project_member.default_props = request.data.get(
"default_props", default_props
)
project_member.preferences = request.data.get("preferences", preferences)
project_member.sort_order = request.data.get("sort_order", sort_order)
project_member.save()
return Response(status=status.HTTP_200_OK)
return Response(status=status.HTTP_204_NO_CONTENT)
except Project.DoesNotExist:
return Response(
{"error": "The requested resource does not exists"},
@@ -655,7 +940,6 @@ class ProjectUserViewsEndpoint(BaseAPIView):
class ProjectMemberUserEndpoint(BaseAPIView):
def get(self, request, slug, project_id):
try:
project_member = ProjectMember.objects.get(
project_id=project_id, workspace__slug=slug, member=request.user
)
@@ -674,3 +958,254 @@ class ProjectMemberUserEndpoint(BaseAPIView):
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class ProjectFavoritesViewSet(BaseViewSet):
serializer_class = ProjectFavoriteSerializer
model = ProjectFavorite
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(user=self.request.user)
.select_related(
"project", "project__project_lead", "project__default_assignee"
)
.select_related("workspace", "workspace__owner")
)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
def create(self, request, slug):
try:
serializer = ProjectFavoriteSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except IntegrityError as e:
print(str(e))
if "already exists" in str(e):
return Response(
{"error": "The project is already added to favorites"},
status=status.HTTP_410_GONE,
)
else:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_410_GONE,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id):
try:
project_favorite = ProjectFavorite.objects.get(
project=project_id, user=request.user, workspace__slug=slug
)
project_favorite.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except ProjectFavorite.DoesNotExist:
return Response(
{"error": "Project is not in favorites"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class ProjectDeployBoardViewSet(BaseViewSet):
permission_classes = [
ProjectMemberPermission,
]
serializer_class = ProjectDeployBoardSerializer
model = ProjectDeployBoard
def get_queryset(self):
return (
super()
.get_queryset()
.filter(
workspace__slug=self.kwargs.get("slug"),
project_id=self.kwargs.get("project_id"),
)
.select_related("project")
)
def create(self, request, slug, project_id):
try:
comments = request.data.get("comments", False)
reactions = request.data.get("reactions", False)
inbox = request.data.get("inbox", None)
votes = request.data.get("votes", False)
views = request.data.get(
"views",
{
"list": True,
"kanban": True,
"calendar": True,
"gantt": True,
"spreadsheet": True,
},
)
project_deploy_board, _ = ProjectDeployBoard.objects.get_or_create(
anchor=f"{slug}/{project_id}",
project_id=project_id,
)
project_deploy_board.comments = comments
project_deploy_board.reactions = reactions
project_deploy_board.inbox = inbox
project_deploy_board.votes = votes
project_deploy_board.views = views
project_deploy_board.save()
serializer = ProjectDeployBoardSerializer(project_deploy_board)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class ProjectMemberEndpoint(BaseAPIView):
permission_classes = [
ProjectEntityPermission,
]
def get(self, request, slug, project_id):
try:
project_members = ProjectMember.objects.filter(
project_id=project_id,
workspace__slug=slug,
member__is_bot=False,
).select_related("project", "member", "workspace")
serializer = ProjectMemberSerializer(project_members, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class ProjectDeployBoardPublicSettingsEndpoint(BaseAPIView):
permission_classes = [
AllowAny,
]
def get(self, request, slug, project_id):
try:
project_deploy_board = ProjectDeployBoard.objects.get(
workspace__slug=slug, project_id=project_id
)
serializer = ProjectDeployBoardSerializer(project_deploy_board)
return Response(serializer.data, status=status.HTTP_200_OK)
except ProjectDeployBoard.DoesNotExist:
return Response(
{"error": "Project Deploy Board does not exists"},
status=status.HTTP_404_NOT_FOUND,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class WorkspaceProjectDeployBoardEndpoint(BaseAPIView):
permission_classes = [
AllowAny,
]
def get(self, request, slug):
try:
projects = (
Project.objects.filter(workspace__slug=slug)
.annotate(
is_public=Exists(
ProjectDeployBoard.objects.filter(
workspace__slug=slug, project_id=OuterRef("pk")
)
)
)
.filter(is_public=True)
).values(
"id",
"identifier",
"name",
"description",
"emoji",
"icon_prop",
"cover_image",
)
return Response(projects, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class LeaveProjectEndpoint(BaseAPIView):
permission_classes = [
ProjectLitePermission,
]
def delete(self, request, slug, project_id):
try:
project_member = ProjectMember.objects.get(
workspace__slug=slug,
member=request.user,
project_id=project_id,
)
# Only Admin case
if (
project_member.role == 20
and ProjectMember.objects.filter(
workspace__slug=slug,
role=20,
project_id=project_id,
).count()
== 1
):
return Response(
{
"error": "You cannot leave the project since you are the only admin of the project you should delete the project"
},
status=status.HTTP_400_BAD_REQUEST,
)
# Delete the member from workspace
project_member.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except ProjectMember.DoesNotExist:
return Response(
{"error": "Workspace member does not exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,21 @@
# Third party imports
from rest_framework.response import Response
from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from .base import BaseAPIView
from plane.utils.integrations.github import get_release_notes
class ReleaseNotesEndpoint(BaseAPIView):
def get(self, request):
try:
release_notes = get_release_notes()
return Response(release_notes, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -0,0 +1,293 @@
# Python imports
import re
# Django imports
from django.db.models import Q
# Third party imports
from rest_framework import status
from rest_framework.response import Response
from sentry_sdk import capture_exception
# Module imports
from .base import BaseAPIView
from plane.db.models import Workspace, Project, Issue, Cycle, Module, Page, IssueView
from plane.utils.issue_search import search_issues
class GlobalSearchEndpoint(BaseAPIView):
"""Endpoint to search across multiple fields in the workspace and
also show related workspace if found
"""
def filter_workspaces(self, query, slug, project_id, workspace_search):
fields = ["name"]
q = Q()
for field in fields:
q |= Q(**{f"{field}__icontains": query})
return (
Workspace.objects.filter(q, workspace_member__member=self.request.user)
.distinct()
.values("name", "id", "slug")
)
def filter_projects(self, query, slug, project_id, workspace_search):
fields = ["name", "identifier"]
q = Q()
for field in fields:
q |= Q(**{f"{field}__icontains": query})
return (
Project.objects.filter(
q,
Q(project_projectmember__member=self.request.user) | Q(network=2),
workspace__slug=slug,
)
.distinct()
.values("name", "id", "identifier", "workspace__slug")
)
def filter_issues(self, query, slug, project_id, workspace_search):
fields = ["name", "sequence_id", "project__identifier"]
q = Q()
for field in fields:
if field == "sequence_id":
sequences = re.findall(r"\d+\.\d+|\d+", query)
for sequence_id in sequences:
q |= Q(**{"sequence_id": sequence_id})
else:
q |= Q(**{f"{field}__icontains": query})
issues = Issue.issue_objects.filter(
q,
project__project_projectmember__member=self.request.user,
workspace__slug=slug,
)
if workspace_search == "false" and project_id:
issues = issues.filter(project_id=project_id)
return issues.distinct().values(
"name",
"id",
"sequence_id",
"project__identifier",
"project_id",
"workspace__slug",
)
def filter_cycles(self, query, slug, project_id, workspace_search):
fields = ["name"]
q = Q()
for field in fields:
q |= Q(**{f"{field}__icontains": query})
cycles = Cycle.objects.filter(
q,
project__project_projectmember__member=self.request.user,
workspace__slug=slug,
)
if workspace_search == "false" and project_id:
cycles = cycles.filter(project_id=project_id)
return cycles.distinct().values(
"name",
"id",
"project_id",
"project__identifier",
"workspace__slug",
)
def filter_modules(self, query, slug, project_id, workspace_search):
fields = ["name"]
q = Q()
for field in fields:
q |= Q(**{f"{field}__icontains": query})
modules = Module.objects.filter(
q,
project__project_projectmember__member=self.request.user,
workspace__slug=slug,
)
if workspace_search == "false" and project_id:
modules = modules.filter(project_id=project_id)
return modules.distinct().values(
"name",
"id",
"project_id",
"project__identifier",
"workspace__slug",
)
def filter_pages(self, query, slug, project_id, workspace_search):
fields = ["name"]
q = Q()
for field in fields:
q |= Q(**{f"{field}__icontains": query})
pages = Page.objects.filter(
q,
project__project_projectmember__member=self.request.user,
workspace__slug=slug,
)
if workspace_search == "false" and project_id:
pages = pages.filter(project_id=project_id)
return pages.distinct().values(
"name",
"id",
"project_id",
"project__identifier",
"workspace__slug",
)
def filter_views(self, query, slug, project_id, workspace_search):
fields = ["name"]
q = Q()
for field in fields:
q |= Q(**{f"{field}__icontains": query})
issue_views = IssueView.objects.filter(
q,
project__project_projectmember__member=self.request.user,
workspace__slug=slug,
)
if workspace_search == "false" and project_id:
issue_views = issue_views.filter(project_id=project_id)
return issue_views.distinct().values(
"name",
"id",
"project_id",
"project__identifier",
"workspace__slug",
)
def get(self, request, slug):
try:
query = request.query_params.get("search", False)
workspace_search = request.query_params.get("workspace_search", "false")
project_id = request.query_params.get("project_id", False)
if not query:
return Response(
{
"results": {
"workspace": [],
"project": [],
"issue": [],
"cycle": [],
"module": [],
"issue_view": [],
"page": [],
}
},
status=status.HTTP_200_OK,
)
MODELS_MAPPER = {
"workspace": self.filter_workspaces,
"project": self.filter_projects,
"issue": self.filter_issues,
"cycle": self.filter_cycles,
"module": self.filter_modules,
"issue_view": self.filter_views,
"page": self.filter_pages,
}
results = {}
for model in MODELS_MAPPER.keys():
func = MODELS_MAPPER.get(model, None)
results[model] = func(query, slug, project_id, workspace_search)
return Response({"results": results}, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class IssueSearchEndpoint(BaseAPIView):
def get(self, request, slug, project_id):
try:
query = request.query_params.get("search", False)
workspace_search = request.query_params.get("workspace_search", "false")
parent = request.query_params.get("parent", "false")
issue_relation = request.query_params.get("issue_relation", "false")
cycle = request.query_params.get("cycle", "false")
module = request.query_params.get("module", "false")
sub_issue = request.query_params.get("sub_issue", "false")
issue_id = request.query_params.get("issue_id", False)
issues = Issue.issue_objects.filter(
workspace__slug=slug,
project__project_projectmember__member=self.request.user,
)
if workspace_search == "false":
issues = issues.filter(project_id=project_id)
if query:
issues = search_issues(query, issues)
if parent == "true" and issue_id:
issue = Issue.issue_objects.get(pk=issue_id)
issues = issues.filter(
~Q(pk=issue_id), ~Q(pk=issue.parent_id), parent__isnull=True
).exclude(
pk__in=Issue.issue_objects.filter(parent__isnull=False).values_list(
"parent_id", flat=True
)
)
if issue_relation == "true" and issue_id:
issue = Issue.issue_objects.get(pk=issue_id)
issues = issues.filter(
~Q(pk=issue_id),
~Q(issue_related__issue=issue),
~Q(issue_relation__related_issue=issue),
)
if sub_issue == "true" and issue_id:
issue = Issue.issue_objects.get(pk=issue_id)
issues = issues.filter(~Q(pk=issue_id), parent__isnull=True)
if issue.parent:
issues = issues.filter(~Q(pk=issue.parent_id))
if cycle == "true":
issues = issues.exclude(issue_cycle__isnull=False)
if module == "true":
issues = issues.exclude(issue_module__isnull=False)
return Response(
issues.values(
"name",
"id",
"sequence_id",
"project__name",
"project__identifier",
"project_id",
"workspace__slug",
"state__name",
"state__group",
"state__color",
),
status=status.HTTP_200_OK,
)
except Issue.DoesNotExist:
return Response(
{"error": "Issue Does not exist"}, status=status.HTTP_400_BAD_REQUEST
)
except Exception as e:
print(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -1,29 +0,0 @@
# Module imports
from . import BaseViewSet
from plane.api.serializers import ShortCutSerializer
from plane.api.permissions import ProjectEntityPermission
from plane.db.models import Shortcut
class ShortCutViewSet(BaseViewSet):
serializer_class = ShortCutSerializer
model = Shortcut
permission_classes = [
ProjectEntityPermission,
]
def perform_create(self, serializer):
serializer.save(project_id=self.kwargs.get("project_id"))
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(project_id=self.kwargs.get("project_id"))
.filter(project__project_projectmember__member=self.request.user)
.select_related("project")
.select_related("workspace")
.distinct()
)

View File

@@ -1,12 +1,23 @@
# Python imports
from itertools import groupby
# Django imports
from django.db import IntegrityError
from django.db.models import Q
# Third party imports
from rest_framework.response import Response
from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from . import BaseViewSet
from . import BaseViewSet, BaseAPIView
from plane.api.serializers import StateSerializer
from plane.api.permissions import ProjectEntityPermission
from plane.db.models import State
from plane.db.models import State, Issue
class StateViewSet(BaseViewSet):
serializer_class = StateSerializer
model = State
permission_classes = [
@@ -23,7 +34,74 @@ class StateViewSet(BaseViewSet):
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(project_id=self.kwargs.get("project_id"))
.filter(project__project_projectmember__member=self.request.user)
.filter(~Q(name="Triage"))
.select_related("project")
.select_related("workspace")
.distinct()
)
def create(self, request, slug, project_id):
try:
serializer = StateSerializer(data=request.data)
if serializer.is_valid():
serializer.save(project_id=project_id)
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except IntegrityError:
return Response(
{"error": "State with the name already exists"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def list(self, request, slug, project_id):
try:
state_dict = dict()
states = StateSerializer(self.get_queryset(), many=True).data
for key, value in groupby(
sorted(states, key=lambda state: state["group"]),
lambda state: state.get("group"),
):
state_dict[str(key)] = list(value)
return Response(state_dict, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, pk):
try:
state = State.objects.get(
~Q(name="Triage"),
pk=pk, project_id=project_id, workspace__slug=slug,
)
if state.default:
return Response(
{"error": "Default state cannot be deleted"}, status=False
)
# Check for any issues in the state
issue_exist = Issue.issue_objects.filter(state=pk).exists()
if issue_exist:
return Response(
{
"error": "The state is not empty, only empty states can be deleted"
},
status=status.HTTP_400_BAD_REQUEST,
)
state.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except State.DoesNotExist:
return Response({"error": "State does not exists"}, status=status.HTTP_404)

View File

@@ -0,0 +1,158 @@
# Third party imports
from rest_framework.response import Response
from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from plane.api.serializers import (
UserSerializer,
IssueActivitySerializer,
)
from plane.api.views.base import BaseViewSet, BaseAPIView
from plane.db.models import (
User,
Workspace,
WorkspaceMemberInvite,
Issue,
IssueActivity,
WorkspaceMember,
)
from plane.utils.paginator import BasePaginator
class UserEndpoint(BaseViewSet):
serializer_class = UserSerializer
model = User
def get_object(self):
return self.request.user
def retrieve(self, request):
try:
workspace = Workspace.objects.get(
pk=request.user.last_workspace_id, workspace_member__member=request.user
)
workspace_invites = WorkspaceMemberInvite.objects.filter(
email=request.user.email
).count()
assigned_issues = Issue.issue_objects.filter(
assignees__in=[request.user]
).count()
serialized_data = UserSerializer(request.user).data
serialized_data["workspace"] = {
"last_workspace_id": request.user.last_workspace_id,
"last_workspace_slug": workspace.slug,
"fallback_workspace_id": request.user.last_workspace_id,
"fallback_workspace_slug": workspace.slug,
"invites": workspace_invites,
}
serialized_data.setdefault("issues", {})[
"assigned_issues"
] = assigned_issues
return Response(
serialized_data,
status=status.HTTP_200_OK,
)
except Workspace.DoesNotExist:
# This exception will be hit even when the `last_workspace_id` is None
workspace_invites = WorkspaceMemberInvite.objects.filter(
email=request.user.email
).count()
assigned_issues = Issue.issue_objects.filter(
assignees__in=[request.user]
).count()
fallback_workspace = (
Workspace.objects.filter(workspace_member__member=request.user)
.order_by("created_at")
.first()
)
serialized_data = UserSerializer(request.user).data
serialized_data["workspace"] = {
"last_workspace_id": None,
"last_workspace_slug": None,
"fallback_workspace_id": fallback_workspace.id
if fallback_workspace is not None
else None,
"fallback_workspace_slug": fallback_workspace.slug
if fallback_workspace is not None
else None,
"invites": workspace_invites,
}
serialized_data.setdefault("issues", {})[
"assigned_issues"
] = assigned_issues
return Response(
serialized_data,
status=status.HTTP_200_OK,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class UpdateUserOnBoardedEndpoint(BaseAPIView):
def patch(self, request):
try:
user = User.objects.get(pk=request.user.id)
user.is_onboarded = request.data.get("is_onboarded", False)
user.save()
return Response(
{"message": "Updated successfully"}, status=status.HTTP_200_OK
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class UpdateUserTourCompletedEndpoint(BaseAPIView):
def patch(self, request):
try:
user = User.objects.get(pk=request.user.id)
user.is_tour_completed = request.data.get("is_tour_completed", False)
user.save()
return Response(
{"message": "Updated successfully"}, status=status.HTTP_200_OK
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class UserActivityEndpoint(BaseAPIView, BasePaginator):
def get(self, request, slug):
try:
queryset = IssueActivity.objects.filter(
actor=request.user, workspace__slug=slug
).select_related("actor", "workspace", "issue", "project")
return self.paginate(
request=request,
queryset=queryset,
on_results=lambda issue_activities: IssueActivitySerializer(
issue_activities, many=True
).data,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

View File

@@ -1,14 +1,220 @@
# Django imports
from django.db.models import (
Prefetch,
OuterRef,
Func,
F,
Case,
Value,
CharField,
When,
Exists,
Max,
)
from django.utils.decorators import method_decorator
from django.views.decorators.gzip import gzip_page
from django.db import IntegrityError
from django.db.models import Prefetch, OuterRef, Exists
# Third party imports
from rest_framework.response import Response
from rest_framework import status
from sentry_sdk import capture_exception
# Module imports
from . import BaseViewSet
from plane.api.serializers import ViewSerializer
from plane.api.permissions import ProjectEntityPermission
from plane.db.models import View
from . import BaseViewSet, BaseAPIView
from plane.api.serializers import (
GlobalViewSerializer,
IssueViewSerializer,
IssueLiteSerializer,
IssueViewFavoriteSerializer,
)
from plane.api.permissions import WorkspaceEntityPermission, ProjectEntityPermission
from plane.db.models import (
Workspace,
GlobalView,
IssueView,
Issue,
IssueViewFavorite,
IssueReaction,
IssueLink,
IssueAttachment,
)
from plane.utils.issue_filters import issue_filters
from plane.utils.grouper import group_results
class ViewViewSet(BaseViewSet):
class GlobalViewViewSet(BaseViewSet):
serializer_class = GlobalViewSerializer
model = GlobalView
permission_classes = [
WorkspaceEntityPermission,
]
serializer_class = ViewSerializer
model = View
def perform_create(self, serializer):
workspace = Workspace.objects.get(slug=self.kwargs.get("slug"))
serializer.save(workspace_id=workspace.id)
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.select_related("workspace")
.order_by(self.request.GET.get("order_by", "-created_at"))
.distinct()
)
class GlobalViewIssuesViewSet(BaseViewSet):
permission_classes = [
WorkspaceEntityPermission,
]
def get_queryset(self):
return (
Issue.issue_objects.annotate(
sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.filter(workspace__slug=self.kwargs.get("slug"))
.select_related("project")
.select_related("workspace")
.select_related("state")
.select_related("parent")
.prefetch_related("assignees")
.prefetch_related("labels")
.prefetch_related(
Prefetch(
"issue_reactions",
queryset=IssueReaction.objects.select_related("actor"),
)
)
)
@method_decorator(gzip_page)
def list(self, request, slug):
try:
filters = issue_filters(request.query_params, "GET")
# Custom ordering for priority and state
priority_order = ["urgent", "high", "medium", "low", "none"]
state_order = ["backlog", "unstarted", "started", "completed", "cancelled"]
order_by_param = request.GET.get("order_by", "-created_at")
issue_queryset = (
self.get_queryset()
.filter(**filters)
.filter(project__project_projectmember__member=self.request.user)
.annotate(cycle_id=F("issue_cycle__cycle_id"))
.annotate(module_id=F("issue_module__module_id"))
.annotate(
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
.annotate(
attachment_count=IssueAttachment.objects.filter(
issue=OuterRef("id")
)
.order_by()
.annotate(count=Func(F("id"), function="Count"))
.values("count")
)
)
# Priority Ordering
if order_by_param == "priority" or order_by_param == "-priority":
priority_order = (
priority_order
if order_by_param == "priority"
else priority_order[::-1]
)
issue_queryset = issue_queryset.annotate(
priority_order=Case(
*[
When(priority=p, then=Value(i))
for i, p in enumerate(priority_order)
],
output_field=CharField(),
)
).order_by("priority_order")
# State Ordering
elif order_by_param in [
"state__name",
"state__group",
"-state__name",
"-state__group",
]:
state_order = (
state_order
if order_by_param in ["state__name", "state__group"]
else state_order[::-1]
)
issue_queryset = issue_queryset.annotate(
state_order=Case(
*[
When(state__group=state_group, then=Value(i))
for i, state_group in enumerate(state_order)
],
default=Value(len(state_order)),
output_field=CharField(),
)
).order_by("state_order")
# assignee and label ordering
elif order_by_param in [
"labels__name",
"-labels__name",
"assignees__first_name",
"-assignees__first_name",
]:
issue_queryset = issue_queryset.annotate(
max_values=Max(
order_by_param[1::]
if order_by_param.startswith("-")
else order_by_param
)
).order_by(
"-max_values" if order_by_param.startswith("-") else "max_values"
)
else:
issue_queryset = issue_queryset.order_by(order_by_param)
issues = IssueLiteSerializer(issue_queryset, many=True).data
## Grouping the results
group_by = request.GET.get("group_by", False)
sub_group_by = request.GET.get("sub_group_by", False)
if sub_group_by and sub_group_by == group_by:
return Response(
{"error": "Group by and sub group by cannot be same"},
status=status.HTTP_400_BAD_REQUEST,
)
if group_by:
return Response(
group_results(issues, group_by, sub_group_by), status=status.HTTP_200_OK
)
return Response(issues, status=status.HTTP_200_OK)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class IssueViewViewSet(BaseViewSet):
serializer_class = IssueViewSerializer
model = IssueView
permission_classes = [
ProjectEntityPermission,
]
@@ -17,6 +223,12 @@ class ViewViewSet(BaseViewSet):
serializer.save(project_id=self.kwargs.get("project_id"))
def get_queryset(self):
subquery = IssueViewFavorite.objects.filter(
user=self.request.user,
view_id=OuterRef("pk"),
project_id=self.kwargs.get("project_id"),
workspace__slug=self.kwargs.get("slug"),
)
return self.filter_queryset(
super()
.get_queryset()
@@ -25,5 +237,114 @@ class ViewViewSet(BaseViewSet):
.filter(project__project_projectmember__member=self.request.user)
.select_related("project")
.select_related("workspace")
.annotate(is_favorite=Exists(subquery))
.order_by("-is_favorite", "name")
.distinct()
)
class ViewIssuesEndpoint(BaseAPIView):
permission_classes = [
ProjectEntityPermission,
]
def get(self, request, slug, project_id, view_id):
try:
view = IssueView.objects.get(pk=view_id)
queries = view.query
filters = issue_filters(request.query_params, "GET")
issues = (
Issue.issue_objects.filter(
**queries, project_id=project_id, workspace__slug=slug
)
.filter(**filters)
.select_related("project")
.select_related("workspace")
.select_related("state")
.select_related("parent")
.prefetch_related("assignees")
.prefetch_related("labels")
.prefetch_related(
Prefetch(
"issue_reactions",
queryset=IssueReaction.objects.select_related("actor"),
)
)
)
serializer = IssueLiteSerializer(issues, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
except IssueView.DoesNotExist:
return Response(
{"error": "Issue View does not exist"}, status=status.HTTP_404_NOT_FOUND
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
class IssueViewFavoriteViewSet(BaseViewSet):
serializer_class = IssueViewFavoriteSerializer
model = IssueViewFavorite
def get_queryset(self):
return self.filter_queryset(
super()
.get_queryset()
.filter(workspace__slug=self.kwargs.get("slug"))
.filter(user=self.request.user)
.select_related("view")
)
def create(self, request, slug, project_id):
try:
serializer = IssueViewFavoriteSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user, project_id=project_id)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except IntegrityError as e:
if "already exists" in str(e):
return Response(
{"error": "The view is already added to favorites"},
status=status.HTTP_410_GONE,
)
else:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)
def destroy(self, request, slug, project_id, view_id):
try:
view_favourite = IssueViewFavorite.objects.get(
project=project_id,
user=request.user,
workspace__slug=slug,
view_id=view_id,
)
view_favourite.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
except IssueViewFavorite.DoesNotExist:
return Response(
{"error": "View is not in favorites"},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
capture_exception(e)
return Response(
{"error": "Something went wrong please try again later"},
status=status.HTTP_400_BAD_REQUEST,
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,176 @@
# Python imports
import csv
import io
# Django imports
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
# Third party imports
from celery import shared_task
from sentry_sdk import capture_exception
# Module imports
from plane.db.models import Issue
from plane.utils.analytics_plot import build_graph_plot
from plane.utils.issue_filters import issue_filters
row_mapping = {
"state__name": "State",
"state__group": "State Group",
"labels__name": "Label",
"assignees__display_name": "Assignee Name",
"start_date": "Start Date",
"target_date": "Due Date",
"completed_at": "Completed At",
"created_at": "Created At",
"issue_count": "Issue Count",
"priority": "Priority",
"estimate": "Estimate",
}
@shared_task
def analytic_export_task(email, data, slug):
try:
filters = issue_filters(data, "POST")
queryset = Issue.issue_objects.filter(**filters, workspace__slug=slug)
x_axis = data.get("x_axis", False)
y_axis = data.get("y_axis", False)
segment = data.get("segment", False)
distribution = build_graph_plot(
queryset=queryset, x_axis=x_axis, y_axis=y_axis, segment=segment
)
key = "count" if y_axis == "issue_count" else "estimate"
segmented = segment
assignee_details = {}
if x_axis in ["assignees__id"] or segment in ["assignees__id"]:
assignee_details = (
Issue.issue_objects.filter(workspace__slug=slug, **filters, assignees__avatar__isnull=False)
.order_by("assignees__id")
.distinct("assignees__id")
.values("assignees__avatar", "assignees__display_name", "assignees__first_name", "assignees__last_name", "assignees__id")
)
if segment:
segment_zero = []
for item in distribution:
current_dict = distribution.get(item)
for current in current_dict:
segment_zero.append(current.get("segment"))
segment_zero = list(set(segment_zero))
row_zero = (
[
row_mapping.get(x_axis, "X-Axis"),
]
+ [
row_mapping.get(y_axis, "Y-Axis"),
]
+ segment_zero
)
rows = []
for item in distribution:
generated_row = [
item,
]
data = distribution.get(item)
# Add y axis values
generated_row.append(sum(obj.get(key) for obj in data if obj.get(key, None) is not None))
for segment in segment_zero:
value = [x for x in data if x.get("segment") == segment]
if len(value):
generated_row.append(value[0].get(key))
else:
generated_row.append("0")
# x-axis replacement for names
if x_axis in ["assignees__id"]:
assignee = [user for user in assignee_details if str(user.get("assignees__id")) == str(item)]
if len(assignee):
generated_row[0] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
rows.append(tuple(generated_row))
# If segment is ["assignees__display_name"] then replace segment_zero rows with first and last names
if segmented in ["assignees__id"]:
for index, segm in enumerate(row_zero[2:]):
# find the name of the user
assignee = [user for user in assignee_details if str(user.get("assignees__id")) == str(segm)]
if len(assignee):
row_zero[index + 2] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
rows = [tuple(row_zero)] + rows
csv_buffer = io.StringIO()
writer = csv.writer(csv_buffer, delimiter=",", quoting=csv.QUOTE_ALL)
# Write CSV data to the buffer
for row in rows:
writer.writerow(row)
subject = "Your Export is ready"
html_content = render_to_string("emails/exports/analytics.html", {})
text_content = strip_tags(html_content)
csv_buffer.seek(0)
msg = EmailMultiAlternatives(
subject, text_content, settings.EMAIL_FROM, [email]
)
msg.attach(f"{slug}-analytics.csv", csv_buffer.read())
msg.send(fail_silently=False)
else:
row_zero = [
row_mapping.get(x_axis, "X-Axis"),
row_mapping.get(y_axis, "Y-Axis"),
]
rows = []
for item in distribution:
row = [
item,
distribution.get(item)[0].get("count")
if y_axis == "issue_count"
else distribution.get(item)[0].get("estimate "),
]
# x-axis replacement to names
if x_axis in ["assignees__id"]:
assignee = [user for user in assignee_details if str(user.get("assignees__id")) == str(item)]
if len(assignee):
row[0] = str(assignee[0].get("assignees__first_name")) + " " + str(assignee[0].get("assignees__last_name"))
rows.append(tuple(row))
rows = [tuple(row_zero)] + rows
csv_buffer = io.StringIO()
writer = csv.writer(csv_buffer, delimiter=",", quoting=csv.QUOTE_ALL)
# Write CSV data to the buffer
for row in rows:
writer.writerow(row)
subject = "Your Export is ready"
html_content = render_to_string("emails/exports/analytics.html", {})
text_content = strip_tags(html_content)
csv_buffer.seek(0)
msg = EmailMultiAlternatives(
subject, text_content, settings.EMAIL_FROM, [email]
)
msg.attach(f"{slug}-analytics.csv", csv_buffer.read())
msg.send(fail_silently=False)
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@@ -2,23 +2,26 @@
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
# Third party imports
from django_rq import job
from celery import shared_task
from sentry_sdk import capture_exception
# Module imports
from plane.db.models import User
@job("default")
@shared_task
def email_verification(first_name, email, token, current_site):
try:
realtivelink = "/request-email-verification/" + "?token=" + str(token)
abs_url = "http://" + current_site + realtivelink
abs_url = current_site + realtivelink
from_email_string = f"Team Plane <team@mailer.plane.so>"
from_email_string = settings.EMAIL_FROM
subject = f"Verify your Email!"
@@ -36,5 +39,8 @@ def email_verification(first_name, email, token, current_site):
msg.send()
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

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

View File

@@ -0,0 +1,49 @@
# Python imports
import boto3
from datetime import timedelta
# Django imports
from django.conf import settings
from django.utils import timezone
from django.db.models import Q
# Third party imports
from celery import shared_task
from botocore.client import Config
# Module imports
from plane.db.models import ExporterHistory
@shared_task
def delete_old_s3_link():
# Get a list of keys and IDs to process
expired_exporter_history = ExporterHistory.objects.filter(
Q(url__isnull=False) & Q(created_at__lte=timezone.now() - timedelta(days=8))
).values_list("key", "id")
if settings.DOCKERIZED and settings.USE_MINIO:
s3 = boto3.client(
"s3",
endpoint_url=settings.AWS_S3_ENDPOINT_URL,
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
config=Config(signature_version="s3v4"),
)
else:
s3 = boto3.client(
"s3",
region_name=settings.AWS_REGION,
aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY,
config=Config(signature_version="s3v4"),
)
for file_name, exporter_id in expired_exporter_history:
# Delete object from S3
if file_name:
if settings.DOCKERIZED and settings.USE_MINIO:
s3.delete_object(Bucket=settings.AWS_STORAGE_BUCKET_NAME, Key=file_name)
else:
s3.delete_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key=file_name)
ExporterHistory.objects.filter(id=exporter_id).update(url=None)

View File

@@ -2,25 +2,26 @@
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
# Third party imports
from django_rq import job
from celery import shared_task
from sentry_sdk import capture_exception
# Module imports
from plane.db.models import User
@job("default")
@shared_task
def forgot_password(first_name, email, uidb64, token, current_site):
try:
realtivelink = f"/email-verify/?uidb64={uidb64}&token={token}/"
abs_url = "http://" + current_site + realtivelink
realtivelink = f"/reset-password/?uidb64={uidb64}&token={token}"
abs_url = current_site + realtivelink
from_email_string = f"Team Plane <team@mailer.plane.so>"
from_email_string = settings.EMAIL_FROM
subject = f"Verify your Email!"
subject = f"Reset Your Password - Plane"
context = {
"first_name": first_name,
@@ -36,5 +37,8 @@ def forgot_password(first_name, email, uidb64, token, current_site):
msg.send()
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@@ -0,0 +1,182 @@
# Python imports
import json
import requests
import uuid
import jwt
from datetime import datetime
# Django imports
from django.conf import settings
from django.core.serializers.json import DjangoJSONEncoder
from django.contrib.auth.hashers import make_password
# Third Party imports
from celery import shared_task
from sentry_sdk import capture_exception
# Module imports
from plane.api.serializers import ImporterSerializer
from plane.db.models import (
Importer,
WorkspaceMember,
GithubRepositorySync,
GithubRepository,
ProjectMember,
WorkspaceIntegration,
Label,
User,
)
from .workspace_invitation_task import workspace_invitation
from plane.bgtasks.user_welcome_task import send_welcome_slack
@shared_task
def service_importer(service, importer_id):
try:
importer = Importer.objects.get(pk=importer_id)
importer.status = "processing"
importer.save()
users = importer.data.get("users", [])
# Check if we need to import users as well
if len(users):
# For all invited users create the users
new_users = User.objects.bulk_create(
[
User(
email=user.get("email").strip().lower(),
username=uuid.uuid4().hex,
password=make_password(uuid.uuid4().hex),
is_password_autoset=True,
)
for user in users
if user.get("import", False) == "invite"
],
batch_size=10,
ignore_conflicts=True,
)
[
send_welcome_slack.delay(
str(user.id),
True,
f"{user.email} was imported to Plane from {service}",
)
for user in new_users
]
workspace_users = User.objects.filter(
email__in=[
user.get("email").strip().lower()
for user in users
if user.get("import", False) == "invite"
or user.get("import", False) == "map"
]
)
# Add new users to Workspace and project automatically
WorkspaceMember.objects.bulk_create(
[
WorkspaceMember(
member=user,
workspace_id=importer.workspace_id,
created_by=importer.created_by,
)
for user in workspace_users
],
batch_size=100,
ignore_conflicts=True,
)
ProjectMember.objects.bulk_create(
[
ProjectMember(
project_id=importer.project_id,
workspace_id=importer.workspace_id,
member=user,
created_by=importer.created_by,
)
for user in workspace_users
],
batch_size=100,
ignore_conflicts=True,
)
# Check if sync config is on for github importers
if service == "github" and importer.config.get("sync", False):
name = importer.metadata.get("name", False)
url = importer.metadata.get("url", False)
config = importer.metadata.get("config", {})
owner = importer.metadata.get("owner", False)
repository_id = importer.metadata.get("repository_id", False)
workspace_integration = WorkspaceIntegration.objects.get(
workspace_id=importer.workspace_id, integration__provider="github"
)
# Delete the old repository object
GithubRepositorySync.objects.filter(project_id=importer.project_id).delete()
GithubRepository.objects.filter(project_id=importer.project_id).delete()
# Create a Label for github
label = Label.objects.filter(
name="GitHub", project_id=importer.project_id
).first()
if label is None:
label = Label.objects.create(
name="GitHub",
project_id=importer.project_id,
description="Label to sync Plane issues with GitHub issues",
color="#003773",
)
# Create repository
repo = GithubRepository.objects.create(
name=name,
url=url,
config=config,
repository_id=repository_id,
owner=owner,
project_id=importer.project_id,
)
# Create repo sync
repo_sync = GithubRepositorySync.objects.create(
repository=repo,
workspace_integration=workspace_integration,
actor=workspace_integration.actor,
credentials=importer.data.get("credentials", {}),
project_id=importer.project_id,
label=label,
)
# Add bot as a member in the project
_ = ProjectMember.objects.get_or_create(
member=workspace_integration.actor,
role=20,
project_id=importer.project_id,
)
if settings.PROXY_BASE_URL:
headers = {"Content-Type": "application/json"}
import_data_json = json.dumps(
ImporterSerializer(importer).data,
cls=DjangoJSONEncoder,
)
res = requests.post(
f"{settings.PROXY_BASE_URL}/hooks/workspaces/{str(importer.workspace_id)}/projects/{str(importer.project_id)}/importers/{str(service)}/",
json=import_data_json,
headers=headers,
)
return
except Exception as e:
importer = Importer.objects.get(pk=importer_id)
importer.status = "failed"
importer.save()
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,164 @@
# Python imports
import json
from datetime import timedelta
# Django imports
from django.utils import timezone
from django.db.models import Q
from django.conf import settings
# Third party imports
from celery import shared_task
from sentry_sdk import capture_exception
# Module imports
from plane.db.models import Issue, Project, State
from plane.bgtasks.issue_activites_task import issue_activity
@shared_task
def archive_and_close_old_issues():
archive_old_issues()
close_old_issues()
def archive_old_issues():
try:
# Get all the projects whose archive_in is greater than 0
projects = Project.objects.filter(archive_in__gt=0)
for project in projects:
project_id = project.id
archive_in = project.archive_in
# Get all the issues whose updated_at in less that the archive_in month
issues = Issue.issue_objects.filter(
Q(
project=project_id,
archived_at__isnull=True,
updated_at__lte=(timezone.now() - timedelta(days=archive_in * 30)),
state__group__in=["completed", "cancelled"],
),
Q(issue_cycle__isnull=True)
| (
Q(issue_cycle__cycle__end_date__lt=timezone.now().date())
& Q(issue_cycle__isnull=False)
),
Q(issue_module__isnull=True)
| (
Q(issue_module__module__target_date__lt=timezone.now().date())
& Q(issue_module__isnull=False)
),
).filter(
Q(issue_inbox__status=1)
| Q(issue_inbox__status=-1)
| Q(issue_inbox__status=2)
| Q(issue_inbox__isnull=True)
)
# Check if Issues
if issues:
# Set the archive time to current time
archive_at = timezone.now()
issues_to_update = []
for issue in issues:
issue.archived_at = archive_at
issues_to_update.append(issue)
# Bulk Update the issues and log the activity
if issues_to_update:
Issue.objects.bulk_update(
issues_to_update, ["archived_at"], batch_size=100
)
[
issue_activity.delay(
type="issue.activity.updated",
requested_data=json.dumps({"archived_at": str(archive_at)}),
actor_id=str(project.created_by_id),
issue_id=issue.id,
project_id=project_id,
current_instance=None,
subscriber=False,
epoch=int(timezone.now().timestamp())
)
for issue in issues_to_update
]
return
except Exception as e:
if settings.DEBUG:
print(e)
capture_exception(e)
return
def close_old_issues():
try:
# Get all the projects whose close_in is greater than 0
projects = Project.objects.filter(close_in__gt=0).select_related(
"default_state"
)
for project in projects:
project_id = project.id
close_in = project.close_in
# Get all the issues whose updated_at in less that the close_in month
issues = Issue.issue_objects.filter(
Q(
project=project_id,
archived_at__isnull=True,
updated_at__lte=(timezone.now() - timedelta(days=close_in * 30)),
state__group__in=["backlog", "unstarted", "started"],
),
Q(issue_cycle__isnull=True)
| (
Q(issue_cycle__cycle__end_date__lt=timezone.now().date())
& Q(issue_cycle__isnull=False)
),
Q(issue_module__isnull=True)
| (
Q(issue_module__module__target_date__lt=timezone.now().date())
& Q(issue_module__isnull=False)
),
).filter(
Q(issue_inbox__status=1)
| Q(issue_inbox__status=-1)
| Q(issue_inbox__status=2)
| Q(issue_inbox__isnull=True)
)
# Check if Issues
if issues:
if project.default_state is None:
close_state = State.objects.filter(group="cancelled").first()
else:
close_state = project.default_state
issues_to_update = []
for issue in issues:
issue.state = close_state
issues_to_update.append(issue)
# Bulk Update the issues and log the activity
if issues_to_update:
Issue.objects.bulk_update(issues_to_update, ["state"], batch_size=100)
[
issue_activity.delay(
type="issue.activity.updated",
requested_data=json.dumps({"closed_to": str(issue.state_id)}),
actor_id=str(project.created_by_id),
issue_id=issue.id,
project_id=project_id,
current_instance=None,
subscriber=False,
epoch=int(timezone.now().timestamp())
)
for issue in issues_to_update
]
return
except Exception as e:
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@@ -2,20 +2,20 @@
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
# Third party imports
from django_rq import job
from celery import shared_task
from sentry_sdk import capture_exception
@job("default")
@shared_task
def magic_link(email, key, token, current_site):
try:
realtivelink = f"/magic-sign-in/?password={token}&key={key}"
abs_url = "http://" + current_site + realtivelink
abs_url = current_site + realtivelink
from_email_string = f"Team Plane <team@mailer.plane.so>"
from_email_string = settings.EMAIL_FROM
subject = f"Login for Plane"
@@ -30,6 +30,8 @@ def magic_link(email, key, token, current_site):
msg.send()
return
except Exception as e:
print(e)
capture_exception(e)
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
return

View File

@@ -2,29 +2,28 @@
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
# Third party imports
from django_rq import job
from celery import shared_task
from sentry_sdk import capture_exception
# Module imports
from plane.db.models import Project, User, ProjectMemberInvite
@job("default")
@shared_task
def project_invitation(email, project_id, token, current_site):
try:
project = Project.objects.get(pk=project_id)
project_member_invite = ProjectMemberInvite.objects.get(
token=token, email=email
)
relativelink = f"/project-member-invitation/{project_member_invite.id}"
abs_url = "http://" + current_site + relativelink
abs_url = current_site + relativelink
from_email_string = f"Team Plane <team@mailer.plane.so>"
from_email_string = settings.EMAIL_FROM
subject = f"{project.created_by.first_name or project.created_by.email} invited you to join {project.name} on Plane"
@@ -35,7 +34,9 @@ def project_invitation(email, project_id, token, current_site):
"invitation_url": abs_url,
}
html_content = render_to_string("emails/invitations/project_invitation.html", context)
html_content = render_to_string(
"emails/invitations/project_invitation.html", context
)
text_content = strip_tags(html_content)
@@ -49,6 +50,8 @@ def project_invitation(email, project_id, token, current_site):
except (Project.DoesNotExist, ProjectMemberInvite.DoesNotExist) as e:
return
except Exception as e:
print(e)
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@@ -0,0 +1,36 @@
# Django imports
from django.conf import settings
# Third party imports
from celery import shared_task
from sentry_sdk import capture_exception
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
# Module imports
from plane.db.models import User
@shared_task
def send_welcome_slack(user_id, created, message):
try:
instance = User.objects.get(pk=user_id)
if created and not instance.is_bot:
# Send message on slack as well
if settings.SLACK_BOT_TOKEN:
client = WebClient(token=settings.SLACK_BOT_TOKEN)
try:
_ = client.chat_postMessage(
channel="#trackers",
text=message,
)
except SlackApiError as e:
print(f"Got an error: {e.response['error']}")
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

View File

@@ -2,31 +2,32 @@
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
# Third party imports
from django_rq import job
from celery import shared_task
from sentry_sdk import capture_exception
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
# Module imports
from plane.db.models import Workspace, User, WorkspaceMemberInvite
@job("default")
@shared_task
def workspace_invitation(email, workspace_id, token, current_site, invitor):
try:
workspace = Workspace.objects.get(pk=workspace_id)
workspace_member_invite = WorkspaceMemberInvite.objects.get(
token=token, email=email
)
realtivelink = (
f"/workspace-member-invitation/{workspace_member_invite.id}?email={email}"
f"/workspace-member-invitation/?invitation_id={workspace_member_invite.id}&email={email}"
)
abs_url = "http://" + current_site + realtivelink
abs_url = current_site + realtivelink
from_email_string = f"Team Plane <team@mailer.plane.so>"
from_email_string = settings.EMAIL_FROM
subject = f"{invitor or email} invited you to join {workspace.name} on Plane"
@@ -49,9 +50,24 @@ def workspace_invitation(email, workspace_id, token, current_site, invitor):
msg = EmailMultiAlternatives(subject, text_content, from_email_string, [email])
msg.attach_alternative(html_content, "text/html")
msg.send()
# Send message on slack as well
if settings.SLACK_BOT_TOKEN:
client = WebClient(token=settings.SLACK_BOT_TOKEN)
try:
_ = client.chat_postMessage(
channel="#trackers",
text=f"{workspace_member_invite.email} has been invited to {workspace.name} as a {workspace_member_invite.role}",
)
except SlackApiError as e:
print(f"Got an error: {e.response['error']}")
return
except (Workspace.DoesNotExist, WorkspaceMemberInvite.DoesNotExist) as e:
return
except Exception as e:
# Print logs if in DEBUG mode
if settings.DEBUG:
print(e)
capture_exception(e)
return

32
apiserver/plane/celery.py Normal file
View File

@@ -0,0 +1,32 @@
import os
from celery import Celery
from plane.settings.redis import redis_instance
from celery.schedules import crontab
# Set the default Django settings module for the 'celery' program.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "plane.settings.production")
ri = redis_instance()
app = Celery("plane")
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object("django.conf:settings", namespace="CELERY")
app.conf.beat_schedule = {
# Executes every day at 12 AM
"check-every-day-to-archive-and-close": {
"task": "plane.bgtasks.issue_automation_task.archive_and_close_old_issues",
"schedule": crontab(hour=0, minute=0),
},
"check-every-day-to-delete_exporter_history": {
"task": "plane.bgtasks.exporter_expired_task.delete_old_s3_link",
"schedule": crontab(hour=0, minute=0),
},
}
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
app.conf.beat_scheduler = 'django_celery_beat.schedulers.DatabaseScheduler'

View File

@@ -0,0 +1,69 @@
# Generated by Django 3.2.16 on 2023-02-13 19:48
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('db', '0019_auto_20230131_0049'),
]
operations = [
migrations.RenameField(
model_name='label',
old_name='colour',
new_name='color',
),
migrations.AddField(
model_name='apitoken',
name='workspace',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='api_tokens', to='db.workspace'),
),
migrations.AddField(
model_name='issue',
name='completed_at',
field=models.DateTimeField(null=True),
),
migrations.AddField(
model_name='issue',
name='sort_order',
field=models.FloatField(default=65535),
),
migrations.AddField(
model_name='project',
name='cycle_view',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='project',
name='module_view',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='state',
name='default',
field=models.BooleanField(default=False),
),
migrations.AlterField(
model_name='issue',
name='description',
field=models.JSONField(blank=True, default=dict),
),
migrations.AlterField(
model_name='issue',
name='description_html',
field=models.TextField(blank=True, default='<p></p>'),
),
migrations.AlterField(
model_name='issuecomment',
name='comment_html',
field=models.TextField(blank=True, default='<p></p>'),
),
migrations.AlterField(
model_name='issuecomment',
name='comment_json',
field=models.JSONField(blank=True, default=dict),
),
]

View File

@@ -0,0 +1,185 @@
# Generated by Django 3.2.16 on 2023-02-22 19:34
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('db', '0020_auto_20230214_0118'),
]
operations = [
migrations.CreateModel(
name='GithubRepository',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('name', models.CharField(max_length=500)),
('url', models.URLField(null=True)),
('config', models.JSONField(default=dict)),
('repository_id', models.BigIntegerField()),
('owner', models.CharField(max_length=500)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='githubrepository_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_githubrepository', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='githubrepository_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_githubrepository', to='db.workspace')),
],
options={
'verbose_name': 'Repository',
'verbose_name_plural': 'Repositories',
'db_table': 'github_repositories',
'ordering': ('-created_at',),
},
),
migrations.CreateModel(
name='Integration',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('title', models.CharField(max_length=400)),
('provider', models.CharField(max_length=400, unique=True)),
('network', models.PositiveIntegerField(choices=[(1, 'Private'), (2, 'Public')], default=1)),
('description', models.JSONField(default=dict)),
('author', models.CharField(blank=True, max_length=400)),
('webhook_url', models.TextField(blank=True)),
('webhook_secret', models.TextField(blank=True)),
('redirect_url', models.TextField(blank=True)),
('metadata', models.JSONField(default=dict)),
('verified', models.BooleanField(default=False)),
('avatar_url', models.URLField(blank=True, null=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='integration_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='integration_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
],
options={
'verbose_name': 'Integration',
'verbose_name_plural': 'Integrations',
'db_table': 'integrations',
'ordering': ('-created_at',),
},
),
migrations.AlterField(
model_name='issueactivity',
name='issue',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issue_activity', to='db.issue'),
),
migrations.CreateModel(
name='WorkspaceIntegration',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('metadata', models.JSONField(default=dict)),
('config', models.JSONField(default=dict)),
('actor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='integrations', to=settings.AUTH_USER_MODEL)),
('api_token', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='integrations', to='db.apitoken')),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='workspaceintegration_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('integration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='integrated_workspaces', to='db.integration')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='workspaceintegration_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_integrations', to='db.workspace')),
],
options={
'verbose_name': 'Workspace Integration',
'verbose_name_plural': 'Workspace Integrations',
'db_table': 'workspace_integrations',
'ordering': ('-created_at',),
'unique_together': {('workspace', 'integration')},
},
),
migrations.CreateModel(
name='IssueLink',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('title', models.CharField(max_length=255, null=True)),
('url', models.URLField()),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issuelink_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('issue', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='issue_link', to='db.issue')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_issuelink', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issuelink_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_issuelink', to='db.workspace')),
],
options={
'verbose_name': 'Issue Link',
'verbose_name_plural': 'Issue Links',
'db_table': 'issue_links',
'ordering': ('-created_at',),
},
),
migrations.CreateModel(
name='GithubRepositorySync',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('credentials', models.JSONField(default=dict)),
('actor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_syncs', to=settings.AUTH_USER_MODEL)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='githubrepositorysync_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('label', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='repo_syncs', to='db.label')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_githubrepositorysync', to='db.project')),
('repository', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='syncs', to='db.githubrepository')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='githubrepositorysync_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_githubrepositorysync', to='db.workspace')),
('workspace_integration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='github_syncs', to='db.workspaceintegration')),
],
options={
'verbose_name': 'Github Repository Sync',
'verbose_name_plural': 'Github Repository Syncs',
'db_table': 'github_repository_syncs',
'ordering': ('-created_at',),
'unique_together': {('project', 'repository')},
},
),
migrations.CreateModel(
name='GithubIssueSync',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('repo_issue_id', models.BigIntegerField()),
('github_issue_id', models.BigIntegerField()),
('issue_url', models.URLField()),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='githubissuesync_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('issue', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='github_syncs', to='db.issue')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_githubissuesync', to='db.project')),
('repository_sync', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='issue_syncs', to='db.githubrepositorysync')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='githubissuesync_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_githubissuesync', to='db.workspace')),
],
options={
'verbose_name': 'Github Issue Sync',
'verbose_name_plural': 'Github Issue Syncs',
'db_table': 'github_issue_syncs',
'ordering': ('-created_at',),
'unique_together': {('repository_sync', 'issue')},
},
),
migrations.CreateModel(
name='GithubCommentSync',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('repo_comment_id', models.BigIntegerField()),
('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comment_syncs', to='db.issuecomment')),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='githubcommentsync_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('issue_sync', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comment_syncs', to='db.githubissuesync')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_githubcommentsync', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='githubcommentsync_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_githubcommentsync', to='db.workspace')),
],
options={
'verbose_name': 'Github Comment Sync',
'verbose_name_plural': 'Github Comment Syncs',
'db_table': 'github_comment_syncs',
'ordering': ('-created_at',),
'unique_together': {('issue_sync', 'comment')},
},
),
]

View File

@@ -0,0 +1,101 @@
# Generated by Django 3.2.16 on 2023-03-06 21:34
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('db', '0021_auto_20230223_0104'),
]
operations = [
migrations.RemoveField(
model_name='cycle',
name='status',
),
migrations.RemoveField(
model_name='project',
name='slug',
),
migrations.AddField(
model_name='issuelink',
name='metadata',
field=models.JSONField(default=dict),
),
migrations.AddField(
model_name='modulelink',
name='metadata',
field=models.JSONField(default=dict),
),
migrations.AddField(
model_name='project',
name='cover_image',
field=models.URLField(blank=True, null=True),
),
migrations.CreateModel(
name='ProjectFavorite',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projectfavorite_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_projectfavorite', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='projectfavorite_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_favorites', to=settings.AUTH_USER_MODEL)),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_projectfavorite', to='db.workspace')),
],
options={
'verbose_name': 'Project Favorite',
'verbose_name_plural': 'Project Favorites',
'db_table': 'project_favorites',
'ordering': ('-created_at',),
'unique_together': {('project', 'user')},
},
),
migrations.CreateModel(
name='ModuleFavorite',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='modulefavorite_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('module', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='module_favorites', to='db.module')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_modulefavorite', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='modulefavorite_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='module_favorites', to=settings.AUTH_USER_MODEL)),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_modulefavorite', to='db.workspace')),
],
options={
'verbose_name': 'Module Favorite',
'verbose_name_plural': 'Module Favorites',
'db_table': 'module_favorites',
'ordering': ('-created_at',),
'unique_together': {('module', 'user')},
},
),
migrations.CreateModel(
name='CycleFavorite',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='cyclefavorite_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('cycle', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cycle_favorites', to='db.cycle')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_cyclefavorite', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='cyclefavorite_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cycle_favorites', to=settings.AUTH_USER_MODEL)),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_cyclefavorite', to='db.workspace')),
],
options={
'verbose_name': 'Cycle Favorite',
'verbose_name_plural': 'Cycle Favorites',
'db_table': 'cycle_favorites',
'ordering': ('-created_at',),
'unique_together': {('cycle', 'user')},
},
),
]

View File

@@ -0,0 +1,92 @@
# Generated by Django 3.2.16 on 2023-03-15 19:10
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('db', '0022_auto_20230307_0304'),
]
operations = [
migrations.CreateModel(
name='Importer',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('service', models.CharField(choices=[('github', 'GitHub')], max_length=50)),
('status', models.CharField(choices=[('queued', 'Queued'), ('processing', 'Processing'), ('completed', 'Completed'), ('failed', 'Failed')], default='queued', max_length=50)),
('metadata', models.JSONField(default=dict)),
('config', models.JSONField(default=dict)),
('data', models.JSONField(default=dict)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='importer_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('initiated_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='imports', to=settings.AUTH_USER_MODEL)),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_importer', to='db.project')),
('token', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='importer', to='db.apitoken')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='importer_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_importer', to='db.workspace')),
],
options={
'verbose_name': 'Importer',
'verbose_name_plural': 'Importers',
'db_table': 'importers',
'ordering': ('-created_at',),
},
),
migrations.CreateModel(
name='IssueView',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('name', models.CharField(max_length=255, verbose_name='View Name')),
('description', models.TextField(blank=True, verbose_name='View Description')),
('query', models.JSONField(verbose_name='View Query')),
('access', models.PositiveSmallIntegerField(choices=[(0, 'Private'), (1, 'Public')], default=1)),
('query_data', models.JSONField(default=dict)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issueview_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_issueview', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issueview_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_issueview', to='db.workspace')),
],
options={
'verbose_name': 'Issue View',
'verbose_name_plural': 'Issue Views',
'db_table': 'issue_views',
'ordering': ('-created_at',),
},
),
migrations.CreateModel(
name='IssueViewFavorite',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issueviewfavorite_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_issueviewfavorite', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='issueviewfavorite_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_view_favorites', to=settings.AUTH_USER_MODEL)),
('view', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='view_favorites', to='db.issueview')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_issueviewfavorite', to='db.workspace')),
],
options={
'verbose_name': 'View Favorite',
'verbose_name_plural': 'View Favorites',
'db_table': 'view_favorites',
'ordering': ('-created_at',),
'unique_together': {('view', 'user')},
},
),
migrations.AlterUniqueTogether(
name='label',
unique_together={('name', 'project')},
),
migrations.DeleteModel(
name='View',
),
]

View File

@@ -0,0 +1,113 @@
# Generated by Django 3.2.16 on 2023-03-21 20:08
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('db', '0023_auto_20230316_0040'),
]
operations = [
migrations.CreateModel(
name='Page',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('name', models.CharField(max_length=255)),
('description', models.JSONField(blank=True, default=dict)),
('description_html', models.TextField(blank=True, default='<p></p>')),
('description_stripped', models.TextField(blank=True, null=True)),
('access', models.PositiveSmallIntegerField(choices=[(0, 'Public'), (1, 'Private')], default=0)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='page_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('owned_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pages', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Page',
'verbose_name_plural': 'Pages',
'db_table': 'pages',
'ordering': ('-created_at',),
},
),
migrations.AddField(
model_name='project',
name='issue_views_view',
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name='importer',
name='service',
field=models.CharField(choices=[('github', 'GitHub'), ('jira', 'Jira')], max_length=50),
),
migrations.AlterField(
model_name='project',
name='cover_image',
field=models.URLField(blank=True, max_length=800, null=True),
),
migrations.CreateModel(
name='PageBlock',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('name', models.CharField(max_length=255)),
('description', models.JSONField(blank=True, default=dict)),
('description_html', models.TextField(blank=True, default='<p></p>')),
('description_stripped', models.TextField(blank=True, null=True)),
('completed_at', models.DateTimeField(null=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pageblock_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('issue', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='blocks', to='db.issue')),
('page', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='blocks', to='db.page')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_pageblock', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pageblock_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_pageblock', to='db.workspace')),
],
options={
'verbose_name': 'Page Block',
'verbose_name_plural': 'Page Blocks',
'db_table': 'page_blocks',
'ordering': ('-created_at',),
},
),
migrations.AddField(
model_name='page',
name='project',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_page', to='db.project'),
),
migrations.AddField(
model_name='page',
name='updated_by',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='page_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By'),
),
migrations.AddField(
model_name='page',
name='workspace',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_page', to='db.workspace'),
),
migrations.CreateModel(
name='PageFavorite',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pagefavorite_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('page', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='page_favorites', to='db.page')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_pagefavorite', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pagefavorite_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='page_favorites', to=settings.AUTH_USER_MODEL)),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_pagefavorite', to='db.workspace')),
],
options={
'verbose_name': 'Page Favorite',
'verbose_name_plural': 'Page Favorites',
'db_table': 'page_favorites',
'ordering': ('-created_at',),
'unique_together': {('page', 'user')},
},
),
]

View File

@@ -0,0 +1,61 @@
# Generated by Django 3.2.18 on 2023-03-30 20:33
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
dependencies = [
('db', '0024_auto_20230322_0138'),
]
operations = [
migrations.AddField(
model_name='page',
name='color',
field=models.CharField(blank=True, max_length=255),
),
migrations.AddField(
model_name='pageblock',
name='sort_order',
field=models.FloatField(default=65535),
),
migrations.AddField(
model_name='pageblock',
name='sync',
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name='project',
name='page_view',
field=models.BooleanField(default=True),
),
migrations.CreateModel(
name='PageLabel',
fields=[
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created At')),
('updated_at', models.DateTimeField(auto_now=True, verbose_name='Last Modified At')),
('id', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pagelabel_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created By')),
('label', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='page_labels', to='db.label')),
('page', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='page_labels', to='db.page')),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project_pagelabel', to='db.project')),
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pagelabel_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Last Modified By')),
('workspace', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='workspace_pagelabel', to='db.workspace')),
],
options={
'verbose_name': 'Page Label',
'verbose_name_plural': 'Page Labels',
'db_table': 'page_labels',
'ordering': ('-created_at',),
},
),
migrations.AddField(
model_name='page',
name='labels',
field=models.ManyToManyField(blank=True, related_name='pages', through='db.PageLabel', to='db.Label'),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 3.2.18 on 2023-04-04 21:50
from django.db import migrations, models
import plane.db.models.project
class Migration(migrations.Migration):
dependencies = [
('db', '0025_auto_20230331_0203'),
]
operations = [
migrations.AlterField(
model_name='projectmember',
name='view_props',
field=models.JSONField(default=plane.db.models.project.get_default_props),
),
]

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