From 3263b5414116dbfb81567ecd138a2852658ceee7 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 10 Dec 2024 01:10:14 +0530 Subject: [PATCH 01/71] chore: update lucide --- frontend/lucideIcons.js | 8 +++++++- frontend/package.json | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/lucideIcons.js b/frontend/lucideIcons.js index a328a99c..e666a73a 100644 --- a/frontend/lucideIcons.js +++ b/frontend/lucideIcons.js @@ -2,10 +2,10 @@ import * as LucideIcons from 'lucide-static' let icons = {} for (const icon in LucideIcons) { - let iconSvg = LucideIcons[icon] if (icon == 'default') { continue } + let iconSvg = LucideIcons[icon] // set stroke-width to 1.5 if (iconSvg && iconSvg.includes('stroke-width')) { @@ -26,8 +26,14 @@ export default icons function camelToDash(key) { // barChart2 -> bar-chart-2 let withNumber = key.replace(/[A-Z0-9]/g, (m) => '-' + m.toLowerCase()) + if (withNumber.startsWith('-')) { + withNumber = withNumber.substring(1) + } // barChart2 -> bar-chart2 let withoutNumber = key.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()) + if (withoutNumber.startsWith('-')) { + withoutNumber = withoutNumber.substring(1) + } if (withNumber !== withoutNumber) { // both are required because unplugin icon resolver doesn't put a dash before numbers diff --git a/frontend/package.json b/frontend/package.json index 5187bb3d..1ac42c9f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,7 +29,7 @@ "@vitejs/plugin-vue-jsx": "^3.0.1", "autoprefixer": "^10.4.2", "cypress": "10.11.0", - "lucide-static": "^0.257.0", + "lucide-static": "^0.468.0", "postcss": "^8.4.5", "prettier": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.8", From 24b6314edfc49462c5d73f05de83391a8b573c21 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 10 Dec 2024 01:12:23 +0530 Subject: [PATCH 02/71] chore: add tsconfig.json --- frontend/tsconfig.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 frontend/tsconfig.json diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 00000000..a63ff5df --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "Node", + "strict": true, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM"], + "skipLibCheck": true, + "noEmit": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "**/*.spec.ts"] +} From 334677a88a6db92c4f3b99dfd9ce713536063228 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 10 Dec 2024 01:16:33 +0530 Subject: [PATCH 03/71] fix: space list view - join/leave actions - create new space --- frontend/components.d.ts | 1 + frontend/src/components/NewSpaceDialog.vue | 66 ++++++++ frontend/src/data/newDoc.js | 21 +++ frontend/src/data/projects.js | 1 + frontend/src/data/{users.js => users.ts} | 4 + frontend/src/pages/SpaceList.vue | 152 ++++++++++++++++++ frontend/src/router.js | 5 + .../gameplan/doctype/gp_project/gp_project.py | 17 ++ 8 files changed, 267 insertions(+) create mode 100644 frontend/src/components/NewSpaceDialog.vue create mode 100644 frontend/src/data/newDoc.js rename frontend/src/data/{users.js => users.ts} (93%) create mode 100644 frontend/src/pages/SpaceList.vue diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 237a4b84..a50e8a49 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -74,6 +74,7 @@ declare module 'vue' { LucideX: (typeof import('~icons/lucide/x'))['default'] Members: (typeof import('./src/components/Settings/Members.vue'))['default'] MobileLayout: (typeof import('./src/components/MobileLayout.vue'))['default'] +NewSpaceDialog: (typeof import('./src/components/NewSpaceDialog.vue'))['default'] NewTaskDialog: (typeof import('./src/components/NewTaskDialog.vue'))['default'] PageList: (typeof import('./src/components/PageList.vue'))['default'] Pie: (typeof import('./src/components/Pie.vue'))['default'] diff --git a/frontend/src/components/NewSpaceDialog.vue b/frontend/src/components/NewSpaceDialog.vue new file mode 100644 index 00000000..4595096d --- /dev/null +++ b/frontend/src/components/NewSpaceDialog.vue @@ -0,0 +1,66 @@ + + diff --git a/frontend/src/data/newDoc.js b/frontend/src/data/newDoc.js new file mode 100644 index 00000000..4848af5f --- /dev/null +++ b/frontend/src/data/newDoc.js @@ -0,0 +1,21 @@ +import { createResource } from 'frappe-ui' +import { unref, reactive } from 'vue' + +export function useNewDoc(doctype, doc = {}) { + doc = reactive(doc) + const resource = createResource({ + url: 'frappe.client.insert', + makeParams() { + let values = unref(doc) + return { + doc: { + doctype, + ...values, + }, + } + }, + }) + + resource.doc = doc + return resource +} diff --git a/frontend/src/data/projects.js b/frontend/src/data/projects.js index 2589460c..b7d76cec 100644 --- a/frontend/src/data/projects.js +++ b/frontend/src/data/projects.js @@ -13,6 +13,7 @@ export let projects = createListResource({ 'modified', 'tasks_count', 'discussions_count', + { members: ['user'] }, ], orderBy: 'title asc', pageLength: 999, diff --git a/frontend/src/data/users.js b/frontend/src/data/users.ts similarity index 93% rename from frontend/src/data/users.js rename to frontend/src/data/users.ts index 64e65d0b..d1086206 100644 --- a/frontend/src/data/users.js +++ b/frontend/src/data/users.ts @@ -43,3 +43,7 @@ export function getUser(email) { export let activeUsers = computed(() => { return users.data.filter((user) => user.enabled) }) + +export function useSessionUser() { + return getUser('sessionUser') +} diff --git a/frontend/src/pages/SpaceList.vue b/frontend/src/pages/SpaceList.vue new file mode 100644 index 00000000..dc39bdaa --- /dev/null +++ b/frontend/src/pages/SpaceList.vue @@ -0,0 +1,152 @@ + + diff --git a/frontend/src/router.js b/frontend/src/router.js index c6f0f7a0..246daea4 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -71,6 +71,11 @@ const routes = [ name: 'Teams', component: () => import('@/pages/Teams.vue'), }, + { + path: '/spaces', + name: 'Spaces', + component: () => import('@/pages/SpaceList.vue'), + }, { path: '/people/:personId', name: 'PersonProfile', diff --git a/gameplan/gameplan/doctype/gp_project/gp_project.py b/gameplan/gameplan/doctype/gp_project/gp_project.py index 1bfd8ca5..acadea51 100644 --- a/gameplan/gameplan/doctype/gp_project/gp_project.py +++ b/gameplan/gameplan/doctype/gp_project/gp_project.py @@ -213,6 +213,23 @@ def unfollow(self): ) frappe.delete_doc("GP Followed Project", follow_id) + @frappe.whitelist() + def join(self): + user = frappe.session.user + users = [d.user for d in self.members] + if user not in users: + self.append("members", {"user": user}) + self.save() + + @frappe.whitelist() + def leave(self): + user = frappe.session.user + for member in self.members: + if member.user == user: + self.remove(member) + self.save() + break + def get_meta_tags(url): response = requests.get(url, timeout=2, allow_redirects=True) From 159cbe44a80f66f7ad8e67b8aac76812786aceed Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Tue, 10 Dec 2024 02:38:36 +0530 Subject: [PATCH 04/71] fix: show only joined spaces in sidebar - refactor sidebar code into composition api --- frontend/src/components/AppSidebar.vue | 305 ++++++------------ .../src/components/DropdownMoreOptions.vue | 15 + frontend/src/components/IconPicker.vue | 4 +- frontend/src/components/NewSpaceDialog.vue | 4 +- frontend/src/data/teams.js | 2 +- frontend/src/utils/sidebarResize.ts | 45 +++ 6 files changed, 172 insertions(+), 203 deletions(-) create mode 100644 frontend/src/components/DropdownMoreOptions.vue create mode 100644 frontend/src/utils/sidebarResize.ts diff --git a/frontend/src/components/AppSidebar.vue b/frontend/src/components/AppSidebar.vue index 9b2f6abd..d0fa37bb 100644 --- a/frontend/src/components/AppSidebar.vue +++ b/frontend/src/components/AppSidebar.vue @@ -62,62 +62,57 @@
-

Teams

- +

Spaces

+
Date: Wed, 8 Jan 2025 12:30:04 +0530 Subject: [PATCH 43/71] fix: update joined spaces on join/leave --- frontend/src/data/spaces.ts | 4 ++++ frontend/src/pages/SpaceList.vue | 27 ++++++++++++++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/frontend/src/data/spaces.ts b/frontend/src/data/spaces.ts index 6adb3043..5c679fd4 100644 --- a/frontend/src/data/spaces.ts +++ b/frontend/src/data/spaces.ts @@ -60,3 +60,7 @@ export const joinedSpaces = useCall({ cacheKey: 'joinedSpaces', initialData: [], }) + +export function hasJoined(spaceId: MaybeRefOrGetter) { + return joinedSpaces.data?.includes(toValue(spaceId)) +} diff --git a/frontend/src/pages/SpaceList.vue b/frontend/src/pages/SpaceList.vue index d767354d..77f40ce2 100644 --- a/frontend/src/pages/SpaceList.vue +++ b/frontend/src/pages/SpaceList.vue @@ -55,7 +55,7 @@
+
+ +
@@ -36,6 +39,7 @@ import { computed, ref } from 'vue' import { Breadcrumbs, Select, TabButtons, usePageMeta } from 'frappe-ui' import DiscussionList from '@/components/DiscussionList.vue' +import LastPostReminder from '@/components/LastPostReminder.vue' const feedType = ref('following') const orderBy = ref('last_post_at desc') diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 8229d5f5..e246414d 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2681,10 +2681,10 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lucide-static@^0.468.0: - version "0.468.0" - resolved "https://registry.yarnpkg.com/lucide-static/-/lucide-static-0.468.0.tgz#f4e5525123fff588decd8e1aa10856842b107b78" - integrity sha512-JvpWui2umxRyEVMoETfMzb+qKqibV/sdoqJbKmW1JLdkuhXluJKoO6NqCbvCK/vAbUuH5bTEFD4T6uECsrNcnA== +lucide-static@^0.469.0: + version "0.469.0" + resolved "https://registry.yarnpkg.com/lucide-static/-/lucide-static-0.469.0.tgz#edf4eb55476fa1b2ae1e1c1922152365dec66854" + integrity sha512-ravTgZodIVLO53rJyjIq0iuCRHs+kjd3dAfOcTbA41KCDfdy0Pt6Me8akkhda3jRpbIxjKe1PpYZOg2eQnI/lA== magic-string@^0.30.0: version "0.30.0" diff --git a/gameplan/gameplan/doctype/gp_user_profile/gp_user_profile.py b/gameplan/gameplan/doctype/gp_user_profile/gp_user_profile.py index 40da0454..4a7e672c 100644 --- a/gameplan/gameplan/doctype/gp_user_profile/gp_user_profile.py +++ b/gameplan/gameplan/doctype/gp_user_profile/gp_user_profile.py @@ -158,3 +158,16 @@ def remove_imgbg_in_background(profile_name, default_color=None): profile.image_background_color = default_color profile.save() gameplan.refetch_resource("Users", user=profile.user) + + +@frappe.whitelist() +def get_last_post(): + result = frappe.db.get_list( + "GP Discussion", + filters={"owner": frappe.session.user}, + fields=["creation"], + order_by="creation desc", + limit=1, + pluck="creation", + ) + return result[0] if result else None From 1edf759df5b193ab0ce15225686632d629c2525f Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 8 Jan 2025 13:46:33 +0530 Subject: [PATCH 45/71] fix: revert list return format --- gameplan/gameplan/doctype/gp_discussion/api.py | 4 +++- gameplan/gameplan/doctype/gp_task/gp_task.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gameplan/gameplan/doctype/gp_discussion/api.py b/gameplan/gameplan/doctype/gp_discussion/api.py index 96c9196a..3baa4d97 100644 --- a/gameplan/gameplan/doctype/gp_discussion/api.py +++ b/gameplan/gameplan/doctype/gp_discussion/api.py @@ -95,7 +95,9 @@ def get_discussions(filters=None, order_by=None, start=None, limit=None): ) for discussion in discussions: discussion["ongoing_polls"] = [p for p in ongoing_polls if str(p.discussion) == str(discussion.name)] - return {"result": discussions, "has_next_page": has_next_page} + + frappe.response["has_next_page"] = has_next_page + return discussions def clause_discussions_commented_by_user(user): diff --git a/gameplan/gameplan/doctype/gp_task/gp_task.py b/gameplan/gameplan/doctype/gp_task/gp_task.py index d3ee66d2..732d9370 100644 --- a/gameplan/gameplan/doctype/gp_task/gp_task.py +++ b/gameplan/gameplan/doctype/gp_task/gp_task.py @@ -102,4 +102,5 @@ def get_list( query = query.where((Task.assigned_to == assigned_or_owner) | (Task.owner == assigned_or_owner)) data = query.run(as_dict=True, debug=debug) - return {"result": data[:limit], "has_next_page": len(data) > limit} + frappe.response["has_next_page"] = len(data) > limit + return data[:limit] From 2a74a2a1bd3a22d0428cbdd76f028a185ffefaeb Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 8 Jan 2025 14:01:08 +0530 Subject: [PATCH 46/71] feat: clear cache functionality --- frontend/src/components/UserDropdown.vue | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/frontend/src/components/UserDropdown.vue b/frontend/src/components/UserDropdown.vue index 30308547..566eda3d 100644 --- a/frontend/src/components/UserDropdown.vue +++ b/frontend/src/components/UserDropdown.vue @@ -23,9 +23,11 @@ import { Dropdown } from 'frappe-ui' import { showSettingsDialog } from '@/components/Settings/SettingsDialog.vue' import LucideCreditCard from '~icons/lucide/credit-card' import LucideMoon from '~icons/lucide/moon' +import LucideListRestart from '~icons/lucide/list-restart' import GameplanLogo from './GameplanLogo.vue' import { useUser } from '@/data/users' import { session } from '@/data/session' +import { clear as clearIndexDb } from 'idb-keyval' const user = useUser() @@ -49,6 +51,11 @@ const dropdownItems = computed(() => [ label: 'Toggle theme', onClick: toggleTheme, }, + { + icon: LucideListRestart, + label: 'Clear cache', + onClick: clearCache, + }, { icon: () => h(LucideCreditCard), label: 'Subscription', @@ -71,6 +78,15 @@ function toggleTheme() { localStorage.setItem('theme', theme) } +function clearCache() { + localStorage.clear() + sessionStorage.clear() + clearIndexDb().then(() => { + console.log('Cache cleared') + window.location.reload() + }) +} + onMounted(() => { const theme = localStorage.getItem('theme') if (['light', 'dark'].includes(theme)) { From f8ac585cd4e6c39edd328f12c17a83eac0abe48c Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 8 Jan 2025 14:13:55 +0530 Subject: [PATCH 47/71] fix: remove projects usage --- frontend/src/components/MergeSpaceDialog.vue | 56 +++++++++----------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/frontend/src/components/MergeSpaceDialog.vue b/frontend/src/components/MergeSpaceDialog.vue index 1b88e4ae..206d84d7 100644 --- a/frontend/src/components/MergeSpaceDialog.vue +++ b/frontend/src/components/MergeSpaceDialog.vue @@ -6,7 +6,6 @@ @after-leave=" () => { selectedSpace = null - projects.runDocMethod.reset() } " v-model="show" @@ -26,25 +25,16 @@ {{ option.icon }} - + @@ -54,14 +44,17 @@ import { computed, ref } from 'vue' import { useRouter } from 'vue-router' import { Autocomplete } from 'frappe-ui' import { useGroupedSpaces } from '@/data/groupedSpaces' -import { projects, getProject } from '@/data/projects' +import { useDoctype } from 'frappe-ui/src/data-fetching' +import { GPProject } from '@/types/doctypes' +import { useSpace } from '@/data/spaces' const props = defineProps<{ - spaceId: string | number + spaceId: string }>() const router = useRouter() -const space = computed(() => getProject(props.spaceId)) +const spaces = useDoctype('GP Project') +const space = useSpace(() => props.spaceId) const selectedSpace = ref(null) const show = defineModel() @@ -82,28 +75,27 @@ const groupedSpaceOptions = computed(() => { }) function submit() { - projects.runDocMethod.submit( - { + spaces.runDocMethod + .submit({ method: 'merge_with_project', name: props.spaceId, - project: selectedSpace.value?.value, - }, - { + params: { + project: selectedSpace.value?.value, + }, validate() { if (!selectedSpace.value?.value) { return 'Please select a project to merge' } }, - onSuccess() { - if (selectedSpace.value) { - show.value = false - return router.replace({ - name: 'Space', - params: { spaceId: selectedSpace.value.value }, - }) - } - }, - }, - ) + }) + .then(() => { + if (selectedSpace.value) { + show.value = false + return router.replace({ + name: 'Space', + params: { spaceId: selectedSpace.value.value }, + }) + } + }) } From 25c4c799b3da489428f890c4ec16b82d2b3e28f4 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 8 Jan 2025 14:14:11 +0530 Subject: [PATCH 48/71] fix: disable projects fetch --- frontend/src/components/Settings/InvitePeople.vue | 2 +- frontend/src/data/projects.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Settings/InvitePeople.vue b/frontend/src/components/Settings/InvitePeople.vue index 1d913413..6bfa2e46 100644 --- a/frontend/src/components/Settings/InvitePeople.vue +++ b/frontend/src/components/Settings/InvitePeople.vue @@ -94,7 +94,7 @@ From e48e49b8d35893167dd7d56d2a1f84cdb57554e5 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 8 Jan 2025 14:40:35 +0530 Subject: [PATCH 50/71] fix: update frappe-ui --- frontend/package.json | 2 +- frontend/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 2645f49b..05102f37 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,7 +15,7 @@ "@vueuse/core": "^10.1.2", "dayjs": "^1.10.7", "feather-icons": "^4.28.0", - "frappe-ui": "^0.1.97", + "frappe-ui": "^0.1.101", "fuzzysort": "^2.0.4", "gemoji": "^7.1.0", "htmldiff-js": "^1.0.5", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index e246414d..f54d853c 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2108,10 +2108,10 @@ fraction.js@^4.2.0: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== -frappe-ui@^0.1.97: - version "0.1.97" - resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.97.tgz#8eb9532ae9c916fcd15e8798b8e1376bd4d73a59" - integrity sha512-jYbSm2703nHS+pLOGs2lXNCNLZmhmVaS25fcysax5wzcAXiWT7ZC2iRRvTaHKA9znJxnXXgeaMV37Z+zeWSpdA== +frappe-ui@^0.1.101: + version "0.1.101" + resolved "https://registry.yarnpkg.com/frappe-ui/-/frappe-ui-0.1.101.tgz#12077b4ca18574c11e95dae40df59fdadfada16f" + integrity sha512-IZb0KKQz/fcgnn2Q6MZoLImZECN9/cvHbyD/kpAGQlAHqOTKw6cdZMNq93CwdGZQgKfdH3p/2dqu6G6jP59PtQ== dependencies: "@headlessui/vue" "^1.7.14" "@popperjs/core" "^2.11.2" From 465ad051433e748f9ade84706ff1f58e4d45e851 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Wed, 8 Jan 2025 15:07:33 +0530 Subject: [PATCH 51/71] fix: spacing --- frontend/src/components/LastPostReminder.vue | 39 ++++++++++---------- frontend/src/pages/Discussions.vue | 5 +-- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/LastPostReminder.vue b/frontend/src/components/LastPostReminder.vue index 8d6f43d7..5c1f2127 100644 --- a/frontend/src/components/LastPostReminder.vue +++ b/frontend/src/components/LastPostReminder.vue @@ -1,27 +1,26 @@ diff --git a/frontend/src/data/teams.ts b/frontend/src/data/teams.ts index 9cb07d54..89698372 100644 --- a/frontend/src/data/teams.ts +++ b/frontend/src/data/teams.ts @@ -16,12 +16,6 @@ export let teams = useList({ cacheKey: 'Teams', limit: 999, immediate: true, - transform(data) { - for (let team of data) { - team.name = team.name.toString() - } - return data - }, }) export let activeTeams = computed(() => { diff --git a/frontend/src/pages/Page.vue b/frontend/src/pages/Page.vue index d85704bf..793f55a9 100644 --- a/frontend/src/pages/Page.vue +++ b/frontend/src/pages/Page.vue @@ -165,6 +165,7 @@ const updateUrlSlug = () => { name: page.doc?.project ? 'SpacePage' : 'Page', params: { ...route.params, + spaceId: page.doc?.project, slug: page.doc?.slug, }, query: route.query, diff --git a/frontend/src/pages/SpaceList.vue b/frontend/src/pages/SpaceList.vue index 15f0387d..134479f2 100644 --- a/frontend/src/pages/SpaceList.vue +++ b/frontend/src/pages/SpaceList.vue @@ -1,18 +1,56 @@ diff --git a/frontend/src/components/DiscussionRow.vue b/frontend/src/components/DiscussionRow.vue index ae4d5bf5..a3358c29 100644 --- a/frontend/src/components/DiscussionRow.vue +++ b/frontend/src/components/DiscussionRow.vue @@ -45,7 +45,13 @@ {{ user.full_name }} - in {{ discussion.project_title }} + + in {{ discussion.project_title }} + +
@@ -75,11 +81,13 @@ import { Tooltip } from 'frappe-ui' import { dayjs } from '@/utils/dayjs' import UserAvatar from './UserAvatar.vue' import UserInfo from './UserInfo.vue' +import { useSpace } from '@/data/spaces' +import { Discussion } from '@/data/discussions' import LucidePin from '~icons/lucide/pin' const props = defineProps<{ - discussion: Object + discussion: Discussion index: number total: number showSpaceName: boolean @@ -96,6 +104,10 @@ function discussionTimestamp(d) { return dayjs(timestamp).format('D MMM YYYY') } +function isSpacePrivate(spaceId: string) { + return useSpace(spaceId).value?.is_private +} + function discussionTimestampDescription(d) { return [`First Post: ${dayjs(d.creation)}`, `Latest Post: ${dayjs(d.last_post_at)}`].join('\n') } diff --git a/frontend/src/data/discussions.ts b/frontend/src/data/discussions.ts index 994bae48..74b5dbf5 100644 --- a/frontend/src/data/discussions.ts +++ b/frontend/src/data/discussions.ts @@ -3,7 +3,8 @@ import { useDoc, useList } from 'frappe-ui/src/data-fetching' import { UseListOptions } from 'frappe-ui/src/data-fetching/useList/types' import { GPDiscussion } from '@/types/doctypes' -interface Discussion extends GPDiscussion { +export interface Discussion extends GPDiscussion { + project_title: string last_visit: string last_post_at: string unread: boolean @@ -11,17 +12,18 @@ interface Discussion extends GPDiscussion { export type UseDiscussionOptions = Pick< UseListOptions, - 'cacheKey' | 'filters' | 'limit' | 'orderBy' + 'cacheKey' | 'filters' | 'limit' | 'orderBy' | 'immediate' > export function useDiscussions(options: UseDiscussionOptions) { const discussions = useList({ url: '/api/v2/method/gameplan.gameplan.doctype.gp_discussion.api.get_discussions', doctype: 'GP Discussion', - cacheKey: ['Discussions', { ...options }], + cacheKey: options.cacheKey ? ['Discussions', options.cacheKey] : undefined, filters: options.filters, limit: options.limit || 50, orderBy: options.orderBy, + immediate: options.immediate ?? true, transform(data) { return data.map((d) => ({ ...d, diff --git a/frontend/src/pages/Discussions.vue b/frontend/src/pages/Discussions.vue index ceb90791..d456d4c8 100644 --- a/frontend/src/pages/Discussions.vue +++ b/frontend/src/pages/Discussions.vue @@ -27,7 +27,9 @@ diff --git a/frontend/src/pages/PersonProfileBookmarks.vue b/frontend/src/pages/PersonProfileBookmarks.vue index 61b304a8..ae50213d 100644 --- a/frontend/src/pages/PersonProfileBookmarks.vue +++ b/frontend/src/pages/PersonProfileBookmarks.vue @@ -1,22 +1,8 @@ - diff --git a/frontend/src/pages/PersonProfilePosts.vue b/frontend/src/pages/PersonProfilePosts.vue index 64652c5e..30bf485f 100644 --- a/frontend/src/pages/PersonProfilePosts.vue +++ b/frontend/src/pages/PersonProfilePosts.vue @@ -1,9 +1,6 @@ From 5ff05706d2759bb4a1a36d03799e24b0600f7f4c Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 9 Jan 2025 17:29:11 +0530 Subject: [PATCH 64/71] fix: Poll styling and anonymous polls --- frontend/src/components/CommentsArea.vue | 3 ++ frontend/src/components/Poll.vue | 40 +++++++++++++----------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/CommentsArea.vue b/frontend/src/components/CommentsArea.vue index 9e99f30e..4f53848e 100644 --- a/frontend/src/components/CommentsArea.vue +++ b/frontend/src/components/CommentsArea.vue @@ -173,6 +173,7 @@ const newComment = ref(localStorage.getItem(draftCommentKey()) || '') const newPoll = ref({ title: '', multiple_answers: false, + anonymous: false, options: [ { title: '', idx: 1 }, { title: '', idx: 2 }, @@ -303,6 +304,7 @@ function resetCommentState() { newPoll.value = { title: '', multiple_answers: false, + anonymouse: false, options: [ { title: '', idx: 1 }, { title: '', idx: 2 }, @@ -356,6 +358,7 @@ function submitPoll() { .submit({ discussion: props.name, title: newPoll.value.title, + anonymous: newPoll.value.anonymous ? 1 : 0, multiple_answers: newPoll.value.multiple_answers ? 1 : 0, options: newPoll.value.options, }) diff --git a/frontend/src/components/Poll.vue b/frontend/src/components/Poll.vue index d094894c..c5656df1 100644 --- a/frontend/src/components/Poll.vue +++ b/frontend/src/components/Poll.vue @@ -40,7 +40,7 @@ />
-
{{ _poll.title }}
+
{{ _poll.title }}
Multiple answers · Anonymous · @@ -72,7 +72,7 @@ />
-
{{ option.title }}
+
{{ option.title }}
({{ option.percentage }}%)
@@ -82,29 +82,31 @@
- + +
-
@@ -37,6 +31,7 @@ class="w-full border-0 p-0 pt-4 text-3xl font-semibold focus:outline-none focus:ring-0 bg-surface-white text-ink-gray-9" type="text" v-model="title" + @change="autosave" @keydown.enter="textEditor?.editor?.commands.focus()" ref="titleInput" /> @@ -44,7 +39,12 @@ import { ref, computed, onMounted, onBeforeUnmount, useTemplateRef } from 'vue' import { useRoute, useRouter } from 'vue-router' -import { Breadcrumbs, TextEditor, usePageMeta } from 'frappe-ui' +import { Breadcrumbs, TextEditor, usePageMeta, debounce } from 'frappe-ui' import { useDoc } from 'frappe-ui/src/data-fetching' import { useSpace } from '@/data/spaces' import { GPPage } from '@/types/doctypes' @@ -83,9 +83,9 @@ const page = useDoc({ name: () => props.pageId, }) -page.onSuccess(() => { - title.value = page.doc?.title || '' - content.value = page.doc?.content || '' +page.onSuccess((doc) => { + title.value = doc.title || '' + content.value = doc.content || '' updateUrlSlug() titleInput.value?.focus() }) @@ -111,6 +111,7 @@ const breadcrumbs = computed(() => { name: 'Page', params: { pageId: props.pageId, slug: props.slug }, }, + isPageTitle: true, }, ] } @@ -145,13 +146,30 @@ const breadcrumbs = computed(() => { ] }) +const isAutosaving = ref(false) +const MIN_AUTOSAVING_DURATION = 2000 // 2 seconds + const save = () => { - page.setValue.submit({ - title: title.value, - content: content.value, - }) + isAutosaving.value = true + const startTime = Date.now() + + page.setValue + .submit({ + title: title.value, + content: content.value, + }) + .finally(() => { + const elapsedTime = Date.now() - startTime + const remainingTime = Math.max(0, MIN_AUTOSAVING_DURATION - elapsedTime) + + setTimeout(() => { + isAutosaving.value = false + }, remainingTime) + }) } +const autosave = debounce(save, 1000) + const handleKeyboardShortcuts = (e: KeyboardEvent) => { if (e.key === 's' && (e.metaKey || e.ctrlKey)) { e.preventDefault() From 3a2a8997bd54f01da541423246f0598f4d299773 Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 9 Jan 2025 17:56:16 +0530 Subject: [PATCH 66/71] fix: fetch poll doc always --- frontend/src/components/Poll.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/Poll.vue b/frontend/src/components/Poll.vue index c5656df1..09cdadb7 100644 --- a/frontend/src/components/Poll.vue +++ b/frontend/src/components/Poll.vue @@ -153,7 +153,6 @@ export default { type: 'document', doctype: 'GP Poll', name: this.poll.name, - auto: false, realtime: true, whitelistedMethods: { submitVote: 'submit_vote', From 8d278bf69f6f9a4a8ba26bf4a2d30201a7b6cf7d Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 9 Jan 2025 17:56:32 +0530 Subject: [PATCH 67/71] fix: update title on input --- frontend/src/pages/Page.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/Page.vue b/frontend/src/pages/Page.vue index 45d09676..666d875c 100644 --- a/frontend/src/pages/Page.vue +++ b/frontend/src/pages/Page.vue @@ -31,7 +31,7 @@ class="w-full border-0 p-0 pt-4 text-3xl font-semibold focus:outline-none focus:ring-0 bg-surface-white text-ink-gray-9" type="text" v-model="title" - @change="autosave" + @input="autosave" @keydown.enter="textEditor?.editor?.commands.focus()" ref="titleInput" /> From 32c7931131b4586b76699f8be6265e570c071bab Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Thu, 9 Jan 2025 19:09:54 +0530 Subject: [PATCH 68/71] fix: delete comments instead of setting deleted_at --- frontend/src/components/Comment.vue | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/frontend/src/components/Comment.vue b/frontend/src/components/Comment.vue index 6f7b2dae..a430c71d 100644 --- a/frontend/src/components/Comment.vue +++ b/frontend/src/components/Comment.vue @@ -179,12 +179,7 @@ const dropdownOptions = computed(() => [ variant: 'solid', theme: 'red', onClick: ({ close }) => { - return props.comments.setValue - .submit({ - name: props.comment.name, - deleted_at: $dayjs().format('YYYY-MM-DD HH:mm:ss'), - }) - .then(close) + return props.comments.delete.submit({ name: props.comment.name }).then(close) }, }, ], From 135db51a42432fc0a293a418ceec26b60fd331bc Mon Sep 17 00:00:00 2001 From: Faris Ansari Date: Fri, 10 Jan 2025 14:47:51 +0530 Subject: [PATCH 69/71] fix: add container padding in discussion view --- frontend/src/components/DiscussionView.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/DiscussionView.vue b/frontend/src/components/DiscussionView.vue index 80839c59..9006099a 100644 --- a/frontend/src/components/DiscussionView.vue +++ b/frontend/src/components/DiscussionView.vue @@ -1,6 +1,6 @@