diff --git a/packages/hoppscotch-common/src/components.d.ts b/packages/hoppscotch-common/src/components.d.ts index 40471f3c5..e69de29bb 100644 --- a/packages/hoppscotch-common/src/components.d.ts +++ b/packages/hoppscotch-common/src/components.d.ts @@ -1,165 +0,0 @@ -// generated by unplugin-vue-components -// We suggest you to commit this file into source control -// Read more: https://github.com/vuejs/core/pull/3399 -import '@vue/runtime-core' - -export {} - -declare module '@vue/runtime-core' { - export interface GlobalComponents { - AppActionHandler: typeof import('./components/app/ActionHandler.vue')['default'] - AppAnnouncement: typeof import('./components/app/Announcement.vue')['default'] - AppDeveloperOptions: typeof import('./components/app/DeveloperOptions.vue')['default'] - AppFooter: typeof import('./components/app/Footer.vue')['default'] - AppFuse: typeof import('./components/app/Fuse.vue')['default'] - AppGitHubStarButton: typeof import('./components/app/GitHubStarButton.vue')['default'] - AppHeader: typeof import('./components/app/Header.vue')['default'] - AppInterceptor: typeof import('./components/app/Interceptor.vue')['default'] - AppLogo: typeof import('./components/app/Logo.vue')['default'] - AppNavigation: typeof import('./components/app/Navigation.vue')['default'] - AppOptions: typeof import('./components/app/Options.vue')['default'] - AppPaneLayout: typeof import('./components/app/PaneLayout.vue')['default'] - AppPowerSearch: typeof import('./components/app/PowerSearch.vue')['default'] - AppPowerSearchEntry: typeof import('./components/app/PowerSearchEntry.vue')['default'] - AppShare: typeof import('./components/app/Share.vue')['default'] - AppShortcuts: typeof import('./components/app/Shortcuts.vue')['default'] - AppShortcutsEntry: typeof import('./components/app/ShortcutsEntry.vue')['default'] - AppShortcutsPrompt: typeof import('./components/app/ShortcutsPrompt.vue')['default'] - AppSidenav: typeof import('./components/app/Sidenav.vue')['default'] - AppSupport: typeof import('./components/app/Support.vue')['default'] - Collections: typeof import('./components/collections/index.vue')['default'] - CollectionsAdd: typeof import('./components/collections/Add.vue')['default'] - CollectionsAddFolder: typeof import('./components/collections/AddFolder.vue')['default'] - CollectionsAddRequest: typeof import('./components/collections/AddRequest.vue')['default'] - CollectionsCollection: typeof import('./components/collections/Collection.vue')['default'] - CollectionsEdit: typeof import('./components/collections/Edit.vue')['default'] - CollectionsEditFolder: typeof import('./components/collections/EditFolder.vue')['default'] - CollectionsEditRequest: typeof import('./components/collections/EditRequest.vue')['default'] - CollectionsGraphql: typeof import('./components/collections/graphql/index.vue')['default'] - CollectionsGraphqlAdd: typeof import('./components/collections/graphql/Add.vue')['default'] - CollectionsGraphqlAddFolder: typeof import('./components/collections/graphql/AddFolder.vue')['default'] - CollectionsGraphqlAddRequest: typeof import('./components/collections/graphql/AddRequest.vue')['default'] - CollectionsGraphqlCollection: typeof import('./components/collections/graphql/Collection.vue')['default'] - CollectionsGraphqlEdit: typeof import('./components/collections/graphql/Edit.vue')['default'] - CollectionsGraphqlEditFolder: typeof import('./components/collections/graphql/EditFolder.vue')['default'] - CollectionsGraphqlEditRequest: typeof import('./components/collections/graphql/EditRequest.vue')['default'] - CollectionsGraphqlFolder: typeof import('./components/collections/graphql/Folder.vue')['default'] - CollectionsGraphqlImportExport: typeof import('./components/collections/graphql/ImportExport.vue')['default'] - CollectionsGraphqlRequest: typeof import('./components/collections/graphql/Request.vue')['default'] - CollectionsImportExport: typeof import('./components/collections/ImportExport.vue')['default'] - CollectionsMyCollections: typeof import('./components/collections/MyCollections.vue')['default'] - CollectionsRequest: typeof import('./components/collections/Request.vue')['default'] - CollectionsSaveRequest: typeof import('./components/collections/SaveRequest.vue')['default'] - CollectionsTeamCollections: typeof import('./components/collections/TeamCollections.vue')['default'] - Environments: typeof import('./components/environments/index.vue')['default'] - EnvironmentsImportExport: typeof import('./components/environments/ImportExport.vue')['default'] - EnvironmentsMy: typeof import('./components/environments/my/index.vue')['default'] - EnvironmentsMyDetails: typeof import('./components/environments/my/Details.vue')['default'] - EnvironmentsMyEnvironment: typeof import('./components/environments/my/Environment.vue')['default'] - EnvironmentsTeams: typeof import('./components/environments/teams/index.vue')['default'] - EnvironmentsTeamsDetails: typeof import('./components/environments/teams/Details.vue')['default'] - EnvironmentsTeamsEnvironment: typeof import('./components/environments/teams/Environment.vue')['default'] - FirebaseLogin: typeof import('./components/firebase/Login.vue')['default'] - FirebaseLogout: typeof import('./components/firebase/Logout.vue')['default'] - GraphqlAuthorization: typeof import('./components/graphql/Authorization.vue')['default'] - GraphqlField: typeof import('./components/graphql/Field.vue')['default'] - GraphqlRequest: typeof import('./components/graphql/Request.vue')['default'] - GraphqlRequestOptions: typeof import('./components/graphql/RequestOptions.vue')['default'] - GraphqlResponse: typeof import('./components/graphql/Response.vue')['default'] - GraphqlSidebar: typeof import('./components/graphql/Sidebar.vue')['default'] - GraphqlType: typeof import('./components/graphql/Type.vue')['default'] - GraphqlTypeLink: typeof import('./components/graphql/TypeLink.vue')['default'] - History: typeof import('./components/history/index.vue')['default'] - HistoryGraphqlCard: typeof import('./components/history/graphql/Card.vue')['default'] - HistoryRestCard: typeof import('./components/history/rest/Card.vue')['default'] - HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary'] - HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary'] - HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor'] - HoppSmartAutoComplete: typeof import('@hoppscotch/ui')['HoppSmartAutoComplete'] - HoppSmartCheckbox: typeof import('@hoppscotch/ui')['HoppSmartCheckbox'] - HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal'] - HoppSmartExpand: typeof import('@hoppscotch/ui')['HoppSmartExpand'] - HoppSmartFileChip: typeof import('@hoppscotch/ui')['HoppSmartFileChip'] - HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem'] - HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink'] - HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal'] - HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing'] - HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup'] - HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver'] - HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'] - HoppSmartTab: typeof import('@hoppscotch/ui')['HoppSmartTab'] - HoppSmartTabs: typeof import('@hoppscotch/ui')['HoppSmartTabs'] - HttpAuthorization: typeof import('./components/http/Authorization.vue')['default'] - HttpBody: typeof import('./components/http/Body.vue')['default'] - HttpBodyParameters: typeof import('./components/http/BodyParameters.vue')['default'] - HttpCodegenModal: typeof import('./components/http/CodegenModal.vue')['default'] - HttpHeaders: typeof import('./components/http/Headers.vue')['default'] - HttpImportCurl: typeof import('./components/http/ImportCurl.vue')['default'] - HttpOAuth2Authorization: typeof import('./components/http/OAuth2Authorization.vue')['default'] - HttpParameters: typeof import('./components/http/Parameters.vue')['default'] - HttpPreRequestScript: typeof import('./components/http/PreRequestScript.vue')['default'] - HttpRawBody: typeof import('./components/http/RawBody.vue')['default'] - HttpReqChangeConfirmModal: typeof import('./components/http/ReqChangeConfirmModal.vue')['default'] - HttpRequest: typeof import('./components/http/Request.vue')['default'] - HttpRequestOptions: typeof import('./components/http/RequestOptions.vue')['default'] - HttpResponse: typeof import('./components/http/Response.vue')['default'] - HttpResponseMeta: typeof import('./components/http/ResponseMeta.vue')['default'] - HttpSidebar: typeof import('./components/http/Sidebar.vue')['default'] - HttpTestResult: typeof import('./components/http/TestResult.vue')['default'] - HttpTestResultEntry: typeof import('./components/http/TestResultEntry.vue')['default'] - HttpTestResultEnv: typeof import('./components/http/TestResultEnv.vue')['default'] - HttpTestResultReport: typeof import('./components/http/TestResultReport.vue')['default'] - HttpTests: typeof import('./components/http/Tests.vue')['default'] - HttpURLEncodedParams: typeof import('./components/http/URLEncodedParams.vue')['default'] - IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default'] - IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default'] - IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default'] - IconLucideGlobe: typeof import('~icons/lucide/globe')['default'] - IconLucideHelpCircle: typeof import('~icons/lucide/help-circle')['default'] - IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] - IconLucideInfo: typeof import('~icons/lucide/info')['default'] - IconLucideLayers: typeof import('~icons/lucide/layers')['default'] - IconLucideMinus: typeof import('~icons/lucide/minus')['default'] - IconLucideSearch: typeof import('~icons/lucide/search')['default'] - IconLucideUser: typeof import('~icons/lucide/user')['default'] - IconLucideUsers: typeof import('~icons/lucide/users')['default'] - LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.vue')['default'] - LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default'] - LensesRenderersHTMLLensRenderer: typeof import('./components/lenses/renderers/HTMLLensRenderer.vue')['default'] - LensesRenderersImageLensRenderer: typeof import('./components/lenses/renderers/ImageLensRenderer.vue')['default'] - LensesRenderersJSONLensRenderer: typeof import('./components/lenses/renderers/JSONLensRenderer.vue')['default'] - LensesRenderersPDFLensRenderer: typeof import('./components/lenses/renderers/PDFLensRenderer.vue')['default'] - LensesRenderersRawLensRenderer: typeof import('./components/lenses/renderers/RawLensRenderer.vue')['default'] - LensesRenderersXMLLensRenderer: typeof import('./components/lenses/renderers/XMLLensRenderer.vue')['default'] - LensesResponseBodyRenderer: typeof import('./components/lenses/ResponseBodyRenderer.vue')['default'] - ProfilePicture: typeof import('./components/profile/Picture.vue')['default'] - ProfileShortcode: typeof import('./components/profile/Shortcode.vue')['default'] - ProfileShortcodes: typeof import('./components/profile/Shortcodes.vue')['default'] - ProfileUserDelete: typeof import('./components/profile/UserDelete.vue')['default'] - RealtimeCommunication: typeof import('./components/realtime/Communication.vue')['default'] - RealtimeConnectionConfig: typeof import('./components/realtime/ConnectionConfig.vue')['default'] - RealtimeLog: typeof import('./components/realtime/Log.vue')['default'] - RealtimeLogEntry: typeof import('./components/realtime/LogEntry.vue')['default'] - RealtimeSubscription: typeof import('./components/realtime/Subscription.vue')['default'] - SmartAccentModePicker: typeof import('./components/smart/AccentModePicker.vue')['default'] - SmartChangeLanguage: typeof import('./components/smart/ChangeLanguage.vue')['default'] - SmartColorModePicker: typeof import('./components/smart/ColorModePicker.vue')['default'] - SmartEnvInput: typeof import('./components/smart/EnvInput.vue')['default'] - SmartFontSizePicker: typeof import('./components/smart/FontSizePicker.vue')['default'] - SmartTree: typeof import('./components/smart/Tree.vue')['default'] - SmartTreeBranch: typeof import('./components/smart/TreeBranch.vue')['default'] - TabPrimary: typeof import('./components/tab/Primary.vue')['default'] - TabSecondary: typeof import('./components/tab/Secondary.vue')['default'] - Teams: typeof import('./components/teams/index.vue')['default'] - TeamsAdd: typeof import('./components/teams/Add.vue')['default'] - TeamsEdit: typeof import('./components/teams/Edit.vue')['default'] - TeamsInvite: typeof import('./components/teams/Invite.vue')['default'] - TeamsMemberStack: typeof import('./components/teams/MemberStack.vue')['default'] - TeamsModal: typeof import('./components/teams/Modal.vue')['default'] - TeamsTeam: typeof import('./components/teams/Team.vue')['default'] - Tippy: typeof import('vue-tippy')['Tippy'] - WorkspaceCurrent: typeof import('./components/workspace/Current.vue')['default'] - WorkspaceSelector: typeof import('./components/workspace/Selector.vue')['default'] - } - -} diff --git a/packages/hoppscotch-sh-admin/package.json b/packages/hoppscotch-sh-admin/package.json index 1edb33271..8de132898 100644 --- a/packages/hoppscotch-sh-admin/package.json +++ b/packages/hoppscotch-sh-admin/package.json @@ -25,13 +25,16 @@ "express-graphql": "^0.12.0", "fp-ts": "^2.13.1", "graphql": "^16.6.0", + "io-ts": "^2.2.16", "lodash-es": "^4.17.21", "rxjs": "^7.8.0", "ts-node-dev": "^2.0.0", "unplugin-icons": "^0.14.9", "unplugin-vue-components": "^0.21.0", "vue": "^3.2.6", - "vue-router": "4" + "vue-router": "4", + "tippy.js": "^6.3.7", + "vue-tippy": "6.0.0-alpha.58" }, "devDependencies": { "@graphql-codegen/cli": "3.0.0", diff --git a/packages/hoppscotch-sh-admin/src/components.d.ts b/packages/hoppscotch-sh-admin/src/components.d.ts index 66d312765..b683dfe5b 100644 --- a/packages/hoppscotch-sh-admin/src/components.d.ts +++ b/packages/hoppscotch-sh-admin/src/components.d.ts @@ -18,36 +18,24 @@ declare module '@vue/runtime-core' { HoppSmartAnchor: typeof import('@hoppscotch/ui')['HoppSmartAnchor'] HoppSmartConfirmModal: typeof import('@hoppscotch/ui')['HoppSmartConfirmModal'] HoppSmartItem: typeof import('@hoppscotch/ui')['HoppSmartItem'] - HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal'] - HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'] - IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default'] - IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] - IconLucideLayoutDashboard: typeof import('~icons/lucide/layout-dashboard')['default'] - IconLucideMenu: typeof import('~icons/lucide/menu')['default'] - IconLucideMoreHorizontal: typeof import('~icons/lucide/more-horizontal')['default'] - IconLucideSidebarClose: typeof import('~icons/lucide/sidebar-close')['default'] - IconLucideSidebarOpen: typeof import('~icons/lucide/sidebar-open')['default'] - IconLucideUser: typeof import('~icons/lucide/user')['default'] - IconLucideBell: typeof import('~icons/lucide/bell')['default'] IconLucideChevronDown: typeof import('~icons/lucide/chevron-down')['default'] IconLucideChevronLeft: typeof import('~icons/lucide/chevron-left')['default'] IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default'] - IconLucideFolderTree: typeof import('~icons/lucide/folder-tree')['default'] IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] IconLucideLayoutDashboard: typeof import('~icons/lucide/layout-dashboard')['default'] - IconLucideLineChart: typeof import('~icons/lucide/line-chart')['default'] IconLucideMenu: typeof import('~icons/lucide/menu')['default'] IconLucideMoreHorizontal: typeof import('~icons/lucide/more-horizontal')['default'] - IconLucideSettings: typeof import('~icons/lucide/settings')['default'] IconLucideSidebarClose: typeof import('~icons/lucide/sidebar-close')['default'] IconLucideSidebarOpen: typeof import('~icons/lucide/sidebar-open')['default'] IconLucideUser: typeof import('~icons/lucide/user')['default'] - IconLucideUserCog: typeof import('~icons/lucide/user-cog')['default'] IconLucideUsers: typeof import('~icons/lucide/users')['default'] ProfilePicture: typeof import('./components/profile/Picture.vue')['default'] - RouterLink: typeof import('vue-router')['RouterLink'] - RouterView: typeof import('vue-router')['RouterView'] TeamsAddMembers: typeof import('./components/teams/AddMembers.vue')['default'] + TeamsDetails: typeof import('./components/teams/Details.vue')['default'] + TeamsInvite: typeof import('./components/teams/Invite.vue')['default'] + TeamsMembers: typeof import('./components/teams/Members.vue')['default'] + TeamsPendingInvites: typeof import('./components/teams/PendingInvites.vue')['default'] + Tippy: typeof import('vue-tippy')['Tippy'] } } diff --git a/packages/hoppscotch-sh-admin/src/components/teams/AddMembers.vue b/packages/hoppscotch-sh-admin/src/components/teams/AddMembers.vue index 55d89b0b9..cc7deb28d 100644 --- a/packages/hoppscotch-sh-admin/src/components/teams/AddMembers.vue +++ b/packages/hoppscotch-sh-admin/src/components/teams/AddMembers.vue @@ -41,17 +41,6 @@ - -
- - - -
diff --git a/packages/hoppscotch-sh-admin/src/components/teams/Details.vue b/packages/hoppscotch-sh-admin/src/components/teams/Details.vue new file mode 100644 index 000000000..79f0e3329 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components/teams/Details.vue @@ -0,0 +1,483 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/components/teams/Invite.vue b/packages/hoppscotch-sh-admin/src/components/teams/Invite.vue new file mode 100644 index 000000000..9081f637c --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components/teams/Invite.vue @@ -0,0 +1,402 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/components/teams/Members.vue b/packages/hoppscotch-sh-admin/src/components/teams/Members.vue new file mode 100644 index 000000000..07f1465d8 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components/teams/Members.vue @@ -0,0 +1,329 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/components/teams/PendingInvites.vue b/packages/hoppscotch-sh-admin/src/components/teams/PendingInvites.vue new file mode 100644 index 000000000..2c9c9c449 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components/teams/PendingInvites.vue @@ -0,0 +1,99 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/composables/usePagedQuery.ts b/packages/hoppscotch-sh-admin/src/composables/usePagedQuery.ts index c4c64e70e..568631564 100644 --- a/packages/hoppscotch-sh-admin/src/composables/usePagedQuery.ts +++ b/packages/hoppscotch-sh-admin/src/composables/usePagedQuery.ts @@ -23,17 +23,18 @@ export function usePagedQuery< const fetchNextPage = async () => { fetching.value = true; try { - const result = await client.query(query, { - ...variables, - cursor: list.value.length > 0 - ? getCursor(list.value.at(-1)) - : undefined - }).toPromise(); + const result = await client + .query(query, { + ...variables, + cursor: + list.value.length > 0 ? getCursor(list.value.at(-1)) : undefined, + }) + .toPromise(); const resultList = getList(result.data!); if (resultList.length < 20) { - hasNextPage.value = false + hasNextPage.value = false; } list.value.push(...resultList); @@ -42,22 +43,30 @@ export function usePagedQuery< error.value = true; } fetching.value = false; - } + }; onMounted(async () => { - await fetchNextPage() + await fetchNextPage(); }); const goToNextPage = async () => { if (hasNextPage.value) { - await fetchNextPage() + await fetchNextPage(); } }; + const refetch = async () => { + currentPage.value = 0; + hasNextPage.value = true; + list.value = []; + await fetchNextPage(); + }; + return { fetching, error, goToNextPage, + refetch, list, hasNextPage, }; diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/Email.ts b/packages/hoppscotch-sh-admin/src/helpers/backend/Email.ts new file mode 100644 index 000000000..0fd0538ba --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/Email.ts @@ -0,0 +1,16 @@ +import * as t from "io-ts" + +const emailRegex = + /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + +interface EmailBrand { + readonly Email: unique symbol +} + +export const EmailCodec = t.brand( + t.string, + (x): x is t.Branded => emailRegex.test(x), + "Email" +) + +export type Email = t.TypeOf diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/AcceptTeamInvitation.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/AcceptTeamInvitation.graphql new file mode 100644 index 000000000..41d125554 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/AcceptTeamInvitation.graphql @@ -0,0 +1,12 @@ +mutation AcceptTeamInvitation($inviteID: ID!) { + acceptTeamInvitation(inviteID: $inviteID) { + membershipID + role + user { + uid + displayName + photoURL + email + } + } +} \ No newline at end of file diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/CreateTeam.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/CreateTeam.graphql new file mode 100644 index 000000000..128ab2dbf --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/CreateTeam.graphql @@ -0,0 +1,20 @@ +mutation CreateTeam($userUid: String!, $name: String!) { + createTeamByAdmin(userUid: $userUid, name: $name) { + id + name + members { + membershipID + role + user { + uid + displayName + email + photoURL + } + } + myRole + ownersCount + editorsCount + viewersCount + } +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/CreateTeamInvitation.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/CreateTeamInvitation.graphql new file mode 100644 index 000000000..98fcb580d --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/CreateTeamInvitation.graphql @@ -0,0 +1,9 @@ +mutation CreateTeamInvitation($inviteeEmail: String!, $inviteeRole: TeamMemberRole!, $teamID: ID!) { + createTeamInvitation(inviteeRole: $inviteeRole, inviteeEmail: $inviteeEmail, teamID: $teamID) { + id + teamID + creatorUid + inviteeEmail + inviteeRole + } +} \ No newline at end of file diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveTeam.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveTeam.graphql new file mode 100644 index 000000000..64f1c542c --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveTeam.graphql @@ -0,0 +1,3 @@ +mutation RemoveTeam($uid: ID!) { + deleteTeamByAdmin(teamID: $uid) +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveTeamMember.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveTeamMember.graphql new file mode 100644 index 000000000..ae09e4acc --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RemoveTeamMember.graphql @@ -0,0 +1,3 @@ +mutation RemoveTeamMember($userUid: ID!, $teamID: ID!) { + removeTeamMember(userUid: $userUid, teamID: $teamID) +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RenameTeam.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RenameTeam.graphql new file mode 100644 index 000000000..7abfe71fb --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RenameTeam.graphql @@ -0,0 +1,6 @@ +mutation RenameTeam($uid: ID!, $name: String!) { + renameTeamByAdmin(teamID: $uid, newName: $name) { + id + name + } +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeTeamInvitation.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeTeamInvitation.graphql new file mode 100644 index 000000000..a8652db46 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/RevokeTeamInvitation.graphql @@ -0,0 +1,3 @@ +mutation RevokeTeamInvitation($inviteID: ID!) { + revokeTeamInvitation(inviteID: $inviteID) +} \ No newline at end of file diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/TeamInvitationAdded.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/TeamInvitationAdded.graphql new file mode 100644 index 000000000..878ec130b --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/TeamInvitationAdded.graphql @@ -0,0 +1,5 @@ +subscription TeamInvitationAdded($teamID: ID!) { + teamInvitationAdded(teamID: $teamID) { + id + } +} \ No newline at end of file diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/TeamInvitationRemoved.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/TeamInvitationRemoved.graphql new file mode 100644 index 000000000..d90488f9c --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/TeamInvitationRemoved.graphql @@ -0,0 +1,3 @@ +subscription TeamInvitationRemoved($teamID: ID!) { + teamInvitationRemoved(teamID: $teamID) +} \ No newline at end of file diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/UpdateTeamMemberRole.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/UpdateTeamMemberRole.graphql new file mode 100644 index 000000000..b866b254c --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/mutations/UpdateTeamMemberRole.graphql @@ -0,0 +1,10 @@ +mutation UpdateTeamMemberRole( + $newRole: TeamMemberRole! + $userUid: ID! + $teamID: ID! +) { + updateTeamMemberRole(newRole: $newRole, userUid: $userUid, teamID: $teamID) { + membershipID + role + } +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/TeamInfo.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/TeamInfo.graphql new file mode 100644 index 000000000..16e90f87b --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/TeamInfo.graphql @@ -0,0 +1,30 @@ +query TeamInfo($uid: ID!) { + team(teamID: $uid) { + id + name + + teamMembers { + membershipID + role + user { + uid + displayName + email + photoURL + } + } + teamInvitations { + id + inviteeEmail + inviteeRole + } + teamEnvironments { + id + name + } + myRole + ownersCount + editorsCount + viewersCount + } +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/TeamList.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/TeamList.graphql new file mode 100644 index 000000000..7fff6fbc9 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/TeamList.graphql @@ -0,0 +1,11 @@ +query TeamList($cursor: ID) { + admin { + allTeams(cursor: $cursor) { + id + name + members { + membershipID + } + } + } +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/pendingInvites.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/pendingInvites.graphql new file mode 100644 index 000000000..bbc10779b --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/pendingInvites.graphql @@ -0,0 +1,10 @@ +query GetPendingInvites($teamID: ID!) { + team(teamID: $teamID) { + id + teamInvitations { + inviteeRole + inviteeEmail + id + } + } +} diff --git a/packages/hoppscotch-sh-admin/src/modules/tippy.ts b/packages/hoppscotch-sh-admin/src/modules/tippy.ts new file mode 100644 index 000000000..a2149c3cd --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/modules/tippy.ts @@ -0,0 +1,32 @@ +import { HoppModule } from '.'; +import VueTippy, { roundArrow, setDefaultProps } from 'vue-tippy'; + +import 'tippy.js/dist/tippy.css'; +import 'tippy.js/animations/scale-subtle.css'; +import 'tippy.js/dist/border.css'; +import 'tippy.js/dist/svg-arrow.css'; + +export default { + onVueAppInit(app) { + app.use(VueTippy); + + setDefaultProps({ + animation: 'scale-subtle', + appendTo: document.body, + allowHTML: false, + animateFill: false, + arrow: roundArrow + roundArrow, + popperOptions: { + // https://popper.js.org/docs/v2/utils/detect-overflow/ + modifiers: [ + { + name: 'preventOverflow', + options: { + rootBoundary: 'document', + }, + }, + ], + }, + }); + }, +}; diff --git a/packages/hoppscotch-sh-admin/src/pages/teams/AddTeam.vue b/packages/hoppscotch-sh-admin/src/pages/teams/AddTeam.vue index 35cb29fc3..c791a84f7 100644 --- a/packages/hoppscotch-sh-admin/src/pages/teams/AddTeam.vue +++ b/packages/hoppscotch-sh-admin/src/pages/teams/AddTeam.vue @@ -4,8 +4,8 @@
-
-
+
+
- +
-
- +
+
@@ -30,4 +31,50 @@
- + diff --git a/packages/hoppscotch-sh-admin/src/pages/teams/_id.vue b/packages/hoppscotch-sh-admin/src/pages/teams/_id.vue new file mode 100644 index 000000000..30c34737c --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/teams/_id.vue @@ -0,0 +1,3 @@ + diff --git a/packages/hoppscotch-sh-admin/src/pages/teams/details.vue b/packages/hoppscotch-sh-admin/src/pages/teams/details.vue deleted file mode 100644 index 161557e4a..000000000 --- a/packages/hoppscotch-sh-admin/src/pages/teams/details.vue +++ /dev/null @@ -1,120 +0,0 @@ - - - diff --git a/packages/hoppscotch-sh-admin/src/pages/teams/index.vue b/packages/hoppscotch-sh-admin/src/pages/teams/index.vue index e6c86a5c9..8a4572ec0 100644 --- a/packages/hoppscotch-sh-admin/src/pages/teams/index.vue +++ b/packages/hoppscotch-sh-admin/src/pages/teams/index.vue @@ -2,11 +2,11 @@

Teams

-
-
+
+
-
+
+
- - + - - + - + + + -
Team ID Team NameTeam ID + Number of Members DateAction
-
- - {{ team.id }} - -
-
+ + {{ team.id }} + + - {{ team.members }} - -
- -
+ {{ team.members?.length }}
- + + + + +
+ +
+ +
+ + diff --git a/packages/hoppscotch-sh-admin/vite.config.ts b/packages/hoppscotch-sh-admin/vite.config.ts index 4144aee91..c475ec70b 100644 --- a/packages/hoppscotch-sh-admin/vite.config.ts +++ b/packages/hoppscotch-sh-admin/vite.config.ts @@ -48,6 +48,12 @@ export default defineConfig({ else return undefined; }, ], + types: [ + { + from: 'vue-tippy', + names: ['Tippy'], + }, + ], }), Icons({ compiler: 'vue3', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e7f2b729e..1f8bfd771 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -498,7 +498,7 @@ importers: vite-plugin-inspect: 0.7.4_vite@3.1.4 vite-plugin-pages: 0.26.0_vnheu5mvzzbfbuhqo4shkhdhei vite-plugin-pages-sitemap: 1.4.0 - vite-plugin-pwa: 0.13.1_bg4cnt4dy3xq3a47wkujd6ryzq + vite-plugin-pwa: 0.13.1_vite@3.1.4 vite-plugin-vue-layouts: 0.7.0_oewzdqozxqnqgsrjzmwikx34vi vite-plugin-windicss: 1.8.8_vite@3.1.4 vue-tsc: 0.38.2_typescript@4.7.4 @@ -658,7 +658,7 @@ importers: vite-plugin-inspect: 0.7.4_vite@3.2.4 vite-plugin-pages: 0.26.0_vite@3.2.4 vite-plugin-pages-sitemap: 1.4.0 - vite-plugin-pwa: 0.13.1_3kw35epztoiwny7qtfesjexvtu + vite-plugin-pwa: 0.13.1_vite@3.2.4 vite-plugin-static-copy: 0.12.0_vite@3.2.4 vite-plugin-vue-layouts: 0.7.0_vite@3.2.4+vue@3.2.45 vite-plugin-windicss: 1.8.8_vite@3.2.4 @@ -692,10 +692,12 @@ importers: fp-ts: ^2.13.1 graphql: ^16.6.0 graphql-tag: ^2.12.6 + io-ts: ^2.2.16 lodash-es: ^4.17.21 npm-run-all: ^4.1.5 rxjs: ^7.8.0 sass: ^1.57.1 + tippy.js: ^6.3.7 ts-node: ^10.9.1 ts-node-dev: ^2.0.0 typescript: ^4.9.3 @@ -707,6 +709,7 @@ importers: vite-plugin-windicss: ^1.8.8 vue: ^3.2.6 vue-router: '4' + vue-tippy: 6.0.0-alpha.58 vue-tsc: ^0.3.0 windicss: ^3.5.6 dependencies: @@ -724,13 +727,16 @@ importers: express-graphql: 0.12.0_graphql@16.6.0 fp-ts: 2.13.1 graphql: 16.6.0 + io-ts: 2.2.16_fp-ts@2.13.1 lodash-es: 4.17.21 rxjs: 7.8.0 + tippy.js: 6.3.7 ts-node-dev: 2.0.0_typescript@4.9.3 unplugin-icons: 0.14.9_ucej6auec2vidlux2n3htzvxf4 unplugin-vue-components: 0.21.0_vite@3.2.4+vue@3.2.45 vue: 3.2.45 vue-router: 4.1.0_vue@3.2.45 + vue-tippy: 6.0.0-alpha.58_vue@3.2.45 devDependencies: '@graphql-codegen/cli': 3.0.0_rf2sx74yjwgv4c7f6t6izlk5dy '@graphql-codegen/client-preset': 2.1.0_graphql@16.6.0 @@ -959,7 +965,7 @@ importers: vite-plugin-inspect: 0.7.4_vite@3.2.4 vite-plugin-pages: 0.26.0_vite@3.2.4 vite-plugin-pages-sitemap: 1.4.0 - vite-plugin-pwa: 0.13.1_3kw35epztoiwny7qtfesjexvtu + vite-plugin-pwa: 0.13.1_vite@3.2.4 vite-plugin-static-copy: 0.12.0_vite@3.2.4 vite-plugin-vue-layouts: 0.7.0_vite@3.2.4+vue@3.2.45 vite-plugin-windicss: 1.8.8_vite@3.2.4 @@ -5252,7 +5258,7 @@ packages: debug: 4.3.4 fast-glob: 3.2.11 source-map: 0.6.1 - vite: 3.2.4 + vite: 3.2.4_sass@1.53.0 transitivePeerDependencies: - supports-color dev: true @@ -8014,7 +8020,7 @@ packages: magic-string: 0.26.7 regenerator-runtime: 0.13.10 systemjs: 6.13.0 - vite: 3.2.4 + vite: 3.2.4_sass@1.53.0 /@vitejs/plugin-vue/3.1.0_vite@3.1.4+vue@3.2.37: resolution: {integrity: sha512-fmxtHPjSOEIRg6vHYDaem+97iwCUg/uSIaTzp98lhELt2ISOQuDo2hbkBdXod0g15IhfPMQmAxh4heUks2zvDA==} @@ -8034,7 +8040,7 @@ packages: vite: ^3.0.0 vue: ^3.2.25 dependencies: - vite: 3.2.4 + vite: 3.2.4_sass@1.53.0 vue: 3.2.45 dev: true @@ -18385,7 +18391,6 @@ packages: chokidar: 3.5.3 immutable: 4.1.0 source-map-js: 1.0.2 - dev: true /sax/1.2.4: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} @@ -20307,7 +20312,7 @@ packages: dependencies: acorn: 8.8.0 chokidar: 3.5.3 - vite: 3.2.4 + vite: 3.2.4_sass@1.53.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.4.4 @@ -20354,7 +20359,7 @@ packages: dependencies: acorn: 8.8.0 chokidar: 3.5.3 - vite: 3.2.4 + vite: 3.2.4_sass@1.58.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.4.4 @@ -20668,7 +20673,7 @@ packages: vite: ^2.0.0 || ^3.0.0 dependencies: fast-glob: 3.2.11 - vite: 3.2.4 + vite: 3.2.4_sass@1.53.0 dev: true /vite-plugin-html-config/1.0.10_vite@3.1.4: @@ -20686,7 +20691,7 @@ packages: peerDependencies: vite: '>=2.0.0' dependencies: - vite: 3.2.4 + vite: 3.2.4_sass@1.53.0 dev: true /vite-plugin-inspect/0.7.4_vite@3.1.4: @@ -20718,7 +20723,7 @@ packages: kolorist: 1.5.1 sirv: 2.0.2 ufo: 0.8.5 - vite: 3.2.4 + vite: 3.2.4_sass@1.53.0 transitivePeerDependencies: - supports-color dev: true @@ -20745,7 +20750,7 @@ packages: json5: 2.2.1 local-pkg: 0.4.2 picocolors: 1.0.0 - vite: 3.2.4_sass@1.58.0 + vite: 3.2.4_sass@1.53.0 yaml: 2.1.1 transitivePeerDependencies: - supports-color @@ -20798,29 +20803,10 @@ packages: - supports-color dev: true - /vite-plugin-pwa/0.13.1_3kw35epztoiwny7qtfesjexvtu: + /vite-plugin-pwa/0.13.1_vite@3.1.4: resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==} peerDependencies: vite: ^3.1.0 - workbox-window: ^6.5.4 - dependencies: - debug: 4.3.4 - fast-glob: 3.2.11 - pretty-bytes: 6.0.0 - rollup: 2.79.1 - vite: 3.2.4 - workbox-build: 6.5.4 - workbox-window: 6.5.4 - transitivePeerDependencies: - - '@types/babel__core' - - supports-color - dev: true - - /vite-plugin-pwa/0.13.1_bg4cnt4dy3xq3a47wkujd6ryzq: - resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==} - peerDependencies: - vite: ^3.1.0 - workbox-window: ^6.5.4 dependencies: debug: 4.3.4 fast-glob: 3.2.11 @@ -20838,7 +20824,6 @@ packages: resolution: {integrity: sha512-NR3dIa+o2hzlzo4lF4Gu0cYvoMjSw2DdRc6Epw1yjmCqWaGuN86WK9JqZie4arNlE1ZuWT3CLiMdiX5wcmmUmg==} peerDependencies: vite: ^3.1.0 - workbox-window: ^6.5.4 dependencies: debug: 4.3.4 fast-glob: 3.2.11 @@ -20908,7 +20893,7 @@ packages: '@vue/compiler-sfc': 3.2.45 debug: 4.3.4 fast-glob: 3.2.11 - vite: 3.2.4_sass@1.58.0 + vite: 3.2.4_sass@1.53.0 vue: 3.2.45 vue-router: 4.1.0_vue@3.2.45 transitivePeerDependencies: @@ -20937,7 +20922,7 @@ packages: '@windicss/plugin-utils': 1.8.8 debug: 4.3.4 kolorist: 1.5.1 - vite: 3.2.4 + vite: 3.2.4_sass@1.53.0 windicss: 3.5.6 transitivePeerDependencies: - supports-color @@ -21001,6 +20986,7 @@ packages: rollup: 2.79.1 optionalDependencies: fsevents: 2.3.2 + dev: true /vite/3.2.4_sass@1.53.0: resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==} @@ -21067,7 +21053,6 @@ packages: sass: 1.58.0 optionalDependencies: fsevents: 2.3.2 - dev: true /vm2/3.9.14: resolution: {integrity: sha512-HgvPHYHeQy8+QhzlFryvSteA4uQLBCOub02mgqdR+0bN/akRZ48TGB1v0aCv7ksyc0HXx16AZtMHKS38alc6TA==}