diff --git a/packages/hoppscotch-common/assets/icons/github.svg b/packages/hoppscotch-common/assets/icons/github.svg
deleted file mode 100644
index 67c833827..000000000
--- a/packages/hoppscotch-common/assets/icons/github.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
diff --git a/packages/hoppscotch-common/assets/scss/styles.scss b/packages/hoppscotch-common/assets/scss/styles.scss
index b38b0c9c7..a0d38f19c 100644
--- a/packages/hoppscotch-common/assets/scss/styles.scss
+++ b/packages/hoppscotch-common/assets/scss/styles.scss
@@ -323,9 +323,10 @@ pre.ace_editor {
@apply after:justify-center;
@apply after:pointer-events-none;
@apply after:font-icon;
- @apply after:text-secondaryLight;
+ @apply after:text-current;
@apply after:right-3;
@apply after:content-["\e313"];
+ @apply after:text-lg;
}
.info-response {
diff --git a/packages/hoppscotch-common/locales/en.json b/packages/hoppscotch-common/locales/en.json
index f28b644c1..59f6f6157 100644
--- a/packages/hoppscotch-common/locales/en.json
+++ b/packages/hoppscotch-common/locales/en.json
@@ -19,6 +19,7 @@
"edit": "Edit",
"filter": "Filter",
"go_back": "Go back",
+ "go_forward": "Go forward",
"group_by": "Group by",
"label": "Label",
"learn_more": "Learn more",
@@ -117,12 +118,16 @@
},
"collection": {
"created": "Collection created",
+ "different_parent": "Cannot reorder collection with different parent",
"edit": "Edit Collection",
"invalid_name": "Please provide a name for the collection",
+ "invalid_root_move": "Collection already in the root",
+ "moved": "Moved Successfully",
"my_collections": "My Collections",
"name": "My New Collection",
"name_length_insufficient": "Collection name should be at least 3 characters long",
"new": "New Collection",
+ "order_changed": "Collection Order Updated",
"renamed": "Collection renamed",
"request_in_use": "Request in use",
"save_as": "Save as",
@@ -389,16 +394,19 @@
"text": "Text"
},
"copy_link": "Copy link",
+ "different_collection": "Cannot reorder requests from different collections",
+ "duplicated": "Request duplicated",
"duration": "Duration",
"enter_curl": "Enter cURL command",
- "duplicated": "Request duplicated",
"generate_code": "Generate code",
"generated_code": "Generated code",
"header_list": "Header List",
"invalid_name": "Please provide a name for the request",
"method": "Method",
+ "moved": "Request moved",
"name": "Request name",
"new": "New Request",
+ "order_changed": "Request Order Updated",
"override": "Override",
"override_help": "Set Content-Type in Headers",
"overriden": "Overridden",
@@ -629,6 +637,7 @@
"body": "Body",
"collections": "Collections",
"documentation": "Documentation",
+ "environments": "Environments",
"headers": "Headers",
"history": "History",
"mqtt": "MQTT",
@@ -655,6 +664,7 @@
"exit_disabled": "Only owner cannot exit the team",
"invalid_email_format": "Email format is invalid",
"invalid_id": "Invalid team ID. Contact your team owner.",
+ "invalid_coll_id": "Invalid collection ID",
"invalid_invite_link": "Invalid invite link",
"invalid_invite_link_description": "The link you followed is invalid. Contact your team owner.",
"invalid_member_permission": "Please provide a valid permission to the team member",
@@ -676,6 +686,7 @@
"member_removed": "User removed",
"member_role_updated": "User roles updated",
"members": "Members",
+ "more_members": "+{count} more",
"name_length_insufficient": "Team name should be at least 6 characters long",
"name_updated": "Team name updated",
"new": "New Team",
@@ -683,10 +694,13 @@
"new_name": "My New Team",
"no_access": "You do not have edit access to these collections",
"no_invite_found": "Invitation not found. Contact your team owner.",
+ "no_request_found": "Request not found.",
"not_found": "Team not found. Contact your team owner.",
"not_valid_viewer": "You are not a valid viewer. Contact your team owner.",
+ "parent_coll_move": "Cannot move collection to a child collection",
"pending_invites": "Pending invites",
"permissions": "Permissions",
+ "same_target_destination": "Same target and destination",
"saved": "Team saved",
"select_a_team": "Select a team",
"title": "Teams",
@@ -714,5 +728,11 @@
"message": "Message",
"protocols": "Protocols",
"url": "URL"
+ },
+ "workspace": {
+ "change": "Change workspace",
+ "personal": "My Workspace",
+ "team": "Team Workspace",
+ "title": "Workspaces"
}
}
diff --git a/packages/hoppscotch-common/src/components.d.ts b/packages/hoppscotch-common/src/components.d.ts
index e0268dcf4..970a9ec0b 100644
--- a/packages/hoppscotch-common/src/components.d.ts
+++ b/packages/hoppscotch-common/src/components.d.ts
@@ -16,6 +16,7 @@ declare module '@vue/runtime-core' {
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']
@@ -26,8 +27,6 @@ declare module '@vue/runtime-core' {
AppShortcutsPrompt: typeof import('./components/app/ShortcutsPrompt.vue')['default']
AppSidenav: typeof import('./components/app/Sidenav.vue')['default']
AppSupport: typeof import('./components/app/Support.vue')['default']
- ButtonPrimary: typeof import('./../../hoppscotch-ui/src/components/button/Primary.vue')['default']
- ButtonSecondary: typeof import('./../../hoppscotch-ui/src/components/button/Secondary.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']
@@ -52,9 +51,7 @@ declare module '@vue/runtime-core' {
CollectionsRequest: typeof import('./components/collections/Request.vue')['default']
CollectionsSaveRequest: typeof import('./components/collections/SaveRequest.vue')['default']
CollectionsTeamCollections: typeof import('./components/collections/TeamCollections.vue')['default']
- CollectionsTeamSelect: typeof import('./components/collections/TeamSelect.vue')['default']
Environments: typeof import('./components/environments/index.vue')['default']
- EnvironmentsChooseType: typeof import('./components/environments/ChooseType.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']
@@ -75,6 +72,24 @@ declare module '@vue/runtime-core' {
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']
+ HoppSmartToggle: typeof import('@hoppscotch/ui')['HoppSmartToggle']
HttpAuthorization: typeof import('./components/http/Authorization.vue')['default']
HttpBody: typeof import('./components/http/Body.vue')['default']
HttpBodyParameters: typeof import('./components/http/BodyParameters.vue')['default']
@@ -97,6 +112,18 @@ declare module '@vue/runtime-core' {
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']
@@ -116,41 +143,24 @@ declare module '@vue/runtime-core' {
RealtimeLogEntry: typeof import('./components/realtime/LogEntry.vue')['default']
RealtimeSubscription: typeof import('./components/realtime/Subscription.vue')['default']
SmartAccentModePicker: typeof import('./components/smart/AccentModePicker.vue')['default']
- SmartAnchor: typeof import('./../../hoppscotch-ui/src/components/smart/Anchor.vue')['default']
- SmartAutoComplete: typeof import('./../../hoppscotch-ui/src/components/smart/AutoComplete.vue')['default']
SmartChangeLanguage: typeof import('./components/smart/ChangeLanguage.vue')['default']
- SmartCheckbox: typeof import('./../../hoppscotch-ui/src/components/smart/Checkbox.vue')['default']
SmartColorModePicker: typeof import('./components/smart/ColorModePicker.vue')['default']
- SmartConfirmModal: typeof import('./../../hoppscotch-ui/src/components/smart/ConfirmModal.vue')['default']
SmartEnvInput: typeof import('./components/smart/EnvInput.vue')['default']
- SmartExpand: typeof import('./../../hoppscotch-ui/src/components/smart/Expand.vue')['default']
- SmartFileChip: typeof import('./../../hoppscotch-ui/src/components/smart/FileChip.vue')['default']
SmartFontSizePicker: typeof import('./components/smart/FontSizePicker.vue')['default']
- SmartIntersection: typeof import('./../../hoppscotch-ui/src/components/smart/Intersection.vue')['default']
- SmartItem: typeof import('./../../hoppscotch-ui/src/components/smart/Item.vue')['default']
- SmartLink: typeof import('./../../hoppscotch-ui/src/components/smart/Link.vue')['default']
- SmartModal: typeof import('./../../hoppscotch-ui/src/components/smart/Modal.vue')['default']
- SmartProgressRing: typeof import('./../../hoppscotch-ui/src/components/smart/ProgressRing.vue')['default']
- SmartRadio: typeof import('./../../hoppscotch-ui/src/components/smart/Radio.vue')['default']
- SmartRadioGroup: typeof import('./../../hoppscotch-ui/src/components/smart/RadioGroup.vue')['default']
- SmartSlideOver: typeof import('./../../hoppscotch-ui/src/components/smart/SlideOver.vue')['default']
- SmartSpinner: typeof import('./../../hoppscotch-ui/src/components/smart/Spinner.vue')['default']
- SmartTab: typeof import('./../../hoppscotch-ui/src/components/smart/Tab.vue')['default']
- SmartTabs: typeof import('./../../hoppscotch-ui/src/components/smart/Tabs.vue')['default']
- SmartToggle: typeof import('./../../hoppscotch-ui/src/components/smart/Toggle.vue')['default']
SmartTree: typeof import('./components/smart/Tree.vue')['default']
SmartTreeBranch: typeof import('./components/smart/TreeBranch.vue')['default']
- SmartWindow: typeof import('./../../hoppscotch-ui/src/components/smart/Window.vue')['default']
- SmartWindows: typeof import('./../../hoppscotch-ui/src/components/smart/Windows.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-common/src/components/app/Footer.vue b/packages/hoppscotch-common/src/components/app/Footer.vue
index a6731e11d..d79cc79fe 100644
--- a/packages/hoppscotch-common/src/components/app/Footer.vue
+++ b/packages/hoppscotch-common/src/components/app/Footer.vue
@@ -41,7 +41,7 @@
:on-shown="() => tippyActions!.focus()"
>
@@ -206,7 +206,6 @@ import IconShare2 from "~icons/lucide/share-2"
import IconColumns from "~icons/lucide/columns"
import IconSidebarOpen from "~icons/lucide/sidebar-open"
import IconShieldCheck from "~icons/lucide/shield-check"
-import IconHelpCircle from "~icons/lucide/help-circle"
import IconBook from "~icons/lucide/book"
import IconMessageCircle from "~icons/lucide/message-circle"
import IconGift from "~icons/lucide/gift"
@@ -215,6 +214,7 @@ import IconGithub from "~icons/lucide/github"
import IconTwitter from "~icons/lucide/twitter"
import IconUserPlus from "~icons/lucide/user-plus"
import IconLock from "~icons/lucide/lock"
+import IconLifeBuoy from "~icons/lucide/life-buoy"
import { showChat } from "@modules/crisp"
import { useSetting } from "@composables/settings"
import { useI18n } from "@composables/i18n"
diff --git a/packages/hoppscotch-common/src/components/app/Header.vue b/packages/hoppscotch-common/src/components/app/Header.vue
index 539d994c3..53ab0a975 100644
--- a/packages/hoppscotch-common/src/components/app/Header.vue
+++ b/packages/hoppscotch-common/src/components/app/Header.vue
@@ -4,7 +4,7 @@
class="flex items-center justify-between flex-1 flex-shrink-0 px-2 py-2 space-x-2 overflow-x-auto overflow-y-hidden"
>
-
+
-
+
+
+
+
+
+ {{ t("app.search") }}
+
+ /
+
+
-
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/hoppscotch-common/src/components/app/Navigation.vue b/packages/hoppscotch-common/src/components/app/Navigation.vue
new file mode 100644
index 000000000..8eaae3a99
--- /dev/null
+++ b/packages/hoppscotch-common/src/components/app/Navigation.vue
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
diff --git a/packages/hoppscotch-common/src/components/app/Options.vue b/packages/hoppscotch-common/src/components/app/Options.vue
index 707c5cd9d..5816dd658 100644
--- a/packages/hoppscotch-common/src/components/app/Options.vue
+++ b/packages/hoppscotch-common/src/components/app/Options.vue
@@ -145,7 +145,7 @@ import IconActivity from "~icons/lucide/activity"
import IconLock from "~icons/lucide/lock"
import IconDiscord from "~icons/brands/discord"
import IconTwitter from "~icons/brands/twitter"
-import IconGithub from "~icons/hopp/github"
+import IconGithub from "~icons/lucide/github"
import IconMessageCircle from "~icons/lucide/message-circle"
import IconUserPlus from "~icons/lucide/user-plus"
import IconShare2 from "~icons/lucide/share-2"
diff --git a/packages/hoppscotch-common/src/components/app/Support.vue b/packages/hoppscotch-common/src/components/app/Support.vue
index cdf0668b3..856232b8c 100644
--- a/packages/hoppscotch-common/src/components/app/Support.vue
+++ b/packages/hoppscotch-common/src/components/app/Support.vue
@@ -82,7 +82,7 @@
diff --git a/packages/hoppscotch-common/src/components/collections/MyCollections.vue b/packages/hoppscotch-common/src/components/collections/MyCollections.vue
index 9d71a7c36..7c6fdcbce 100644
--- a/packages/hoppscotch-common/src/components/collections/MyCollections.vue
+++ b/packages/hoppscotch-common/src/components/collections/MyCollections.vue
@@ -1,5 +1,5 @@
-
+
-
+
highlightChildren(isDraging ? node.id : null)
+ "
@toggle-children="
() => {
toggleChildren(),
@@ -85,6 +93,7 @@
/>
highlightChildren(isDraging ? node.id : null)
+ "
@toggle-children="
() => {
toggleChildren(),
@@ -182,7 +196,13 @@
@drag-request="
dragRequest($event, {
folderPath: node.data.data.parentIndex,
- requestIndex: pathToIndex(node.id),
+ requestIndex: node.id,
+ })
+ "
+ @update-request-order="
+ updateRequestOrder($event, {
+ folderPath: node.data.data.parentIndex,
+ requestIndex: node.id,
})
"
/>
@@ -413,7 +433,29 @@ const emit = defineEmits<{
payload: {
folderPath: string
requestIndex: string
- collectionIndex: string
+ destinationCollectionIndex: string
+ }
+ ): void
+ (
+ event: "drop-collection",
+ payload: {
+ collectionIndexDragged: string
+ destinationCollectionIndex: string
+ }
+ ): void
+ (
+ event: "update-request-order",
+ payload: {
+ dragedRequestIndex: string
+ destinationRequestIndex: string
+ destinationCollectionIndex: string
+ }
+ ): void
+ (
+ event: "update-collection-order",
+ payload: {
+ dragedCollectionIndex: string
+ destinationCollectionIndex: string
}
): void
(event: "select", payload: Picked | null): void
@@ -502,6 +544,10 @@ const selectRequest = (data: {
}
}
+const dragEvent = (dataTransfer: DataTransfer, collectionIndex: string) => {
+ dataTransfer.setData("collectionIndex", collectionIndex)
+}
+
const dragRequest = (
dataTransfer: DataTransfer,
{
@@ -514,13 +560,56 @@ const dragRequest = (
dataTransfer.setData("requestIndex", requestIndex)
}
-const dropEvent = (dataTransfer: DataTransfer, collectionIndex: string) => {
+const dropEvent = (
+ dataTransfer: DataTransfer,
+ destinationCollectionIndex: string
+) => {
const folderPath = dataTransfer.getData("folderPath")
const requestIndex = dataTransfer.getData("requestIndex")
- emit("drop-request", {
+ const collectionIndexDragged = dataTransfer.getData("collectionIndex")
+
+ if (folderPath && requestIndex) {
+ emit("drop-request", {
+ folderPath,
+ requestIndex,
+ destinationCollectionIndex,
+ })
+ } else {
+ emit("drop-collection", {
+ collectionIndexDragged,
+ destinationCollectionIndex,
+ })
+ }
+}
+
+const updateRequestOrder = (
+ dataTransfer: DataTransfer,
+ {
folderPath,
requestIndex,
- collectionIndex,
+ }: { folderPath: string | null; requestIndex: string }
+) => {
+ if (!folderPath) return
+ const dragedRequestIndex = dataTransfer.getData("requestIndex")
+ const destinationRequestIndex = requestIndex
+ const destinationCollectionIndex = folderPath
+
+ emit("update-request-order", {
+ dragedRequestIndex,
+ destinationRequestIndex,
+ destinationCollectionIndex,
+ })
+}
+
+const updateCollectionOrder = (
+ dataTransfer: DataTransfer,
+ destinationCollectionIndex: string
+) => {
+ const dragedCollectionIndex = dataTransfer.getData("collectionIndex")
+
+ emit("update-collection-order", {
+ dragedCollectionIndex,
+ destinationCollectionIndex,
})
}
diff --git a/packages/hoppscotch-common/src/components/collections/Request.vue b/packages/hoppscotch-common/src/components/collections/Request.vue
index cb2b0a328..206de110d 100644
--- a/packages/hoppscotch-common/src/components/collections/Request.vue
+++ b/packages/hoppscotch-common/src/components/collections/Request.vue
@@ -1,10 +1,22 @@
-
+
+
+
{{ request.method }}
@@ -149,6 +162,11 @@ const props = defineProps({
default: () => ({}),
required: true,
},
+ requestID: {
+ type: String,
+ default: "",
+ required: false,
+ },
collectionsType: {
type: String as PropType
,
default: "my-collections",
@@ -175,10 +193,15 @@ const props = defineProps({
required: false,
},
isSelected: {
- type: Boolean,
+ type: Boolean as PropType,
default: false,
required: false,
},
+ requestMoveLoading: {
+ type: Array as PropType,
+ default: () => [],
+ required: false,
+ },
})
const emit = defineEmits<{
@@ -187,6 +210,7 @@ const emit = defineEmits<{
(event: "remove-request"): void
(event: "select-request"): void
(event: "drag-request", payload: DataTransfer): void
+ (event: "update-request-order", payload: DataTransfer): void
}>()
const tippyActions = ref(null)
@@ -196,6 +220,7 @@ const options = ref(null)
const duplicate = ref(null)
const dragging = ref(false)
+const ordering = ref(false)
const requestMethodLabels = {
get: "text-green-500",
@@ -228,8 +253,24 @@ const selectRequest = () => {
const dragStart = ({ dataTransfer }: DragEvent) => {
if (dataTransfer) {
- dragging.value = !dragging.value
emit("drag-request", dataTransfer)
+ dragging.value = !dragging.value
}
}
+
+const dropEvent = (e: DragEvent) => {
+ if (e.dataTransfer) {
+ e.stopPropagation()
+ ordering.value = !ordering.value
+ emit("update-request-order", e.dataTransfer)
+ }
+}
+
+const isRequestLoading = computed(() => {
+ if (props.requestMoveLoading.length > 0 && props.requestID) {
+ return props.requestMoveLoading.includes(props.requestID)
+ } else {
+ return false
+ }
+})
diff --git a/packages/hoppscotch-common/src/components/collections/TeamCollections.vue b/packages/hoppscotch-common/src/components/collections/TeamCollections.vue
index 2a4eb6790..2b694d7fe 100644
--- a/packages/hoppscotch-common/src/components/collections/TeamCollections.vue
+++ b/packages/hoppscotch-common/src/components/collections/TeamCollections.vue
@@ -1,11 +1,11 @@
-
+
-
+
+ highlightChildren(isDraging ? node.data.data.data.id : null)
+ "
@toggle-children="
() => {
toggleChildren(),
@@ -100,11 +113,13 @@
/>
+ highlightChildren(isDraging ? node.data.data.data.id : null)
+ "
@toggle-children="
() => {
toggleChildren(),
@@ -153,10 +177,12 @@
e.stopPropagation()"
>
{{ t("empty.collections") }}
@@ -213,11 +252,12 @@
filled
outline
:title="t('team.no_access')"
- :label="t('add.new')"
+ :label="t('action.new')"
/>
e.stopPropagation()"
>
- {{ t("empty.collection") }}
+ {{ t("empty.collections") }}
-
-
e.stopPropagation()"
>
![]()
,
+ default: () => [],
+ required: false,
+ },
+ requestMoveLoading: {
+ type: Array as PropType
,
+ default: () => [],
+ required: false,
+ },
})
const emit = defineEmits<{
@@ -410,6 +440,36 @@ const emit = defineEmits<{
folderPath?: string | undefined
}
): void
+ (
+ event: "drop-request",
+ payload: {
+ folderPath: string
+ requestIndex: string
+ destinationCollectionIndex: string
+ }
+ ): void
+ (
+ event: "drop-collection",
+ payload: {
+ collectionIndexDragged: string
+ destinationCollectionIndex: string
+ }
+ ): void
+ (
+ event: "update-request-order",
+ payload: {
+ dragedRequestIndex: string
+ destinationRequestIndex: string
+ destinationCollectionIndex: string
+ }
+ ): void
+ (
+ event: "update-collection-order",
+ payload: {
+ dragedCollectionIndex: string
+ destinationCollectionIndex: string
+ }
+ ): void
(event: "select", payload: Picked | null): void
(event: "expand-team-collection", payload: string): void
(event: "display-modal-add"): void
@@ -493,6 +553,74 @@ const selectRequest = (data: {
}
}
+const dragRequest = (
+ dataTransfer: DataTransfer,
+ {
+ folderPath,
+ requestIndex,
+ }: { folderPath: string | null; requestIndex: string }
+) => {
+ if (!folderPath) return
+ dataTransfer.setData("folderPath", folderPath)
+ dataTransfer.setData("requestIndex", requestIndex)
+}
+
+const dragEvent = (dataTransfer: DataTransfer, collectionIndex: string) => {
+ dataTransfer.setData("collectionIndex", collectionIndex)
+}
+
+const dropEvent = (
+ dataTransfer: DataTransfer,
+ destinationCollectionIndex: string
+) => {
+ const folderPath = dataTransfer.getData("folderPath")
+ const requestIndex = dataTransfer.getData("requestIndex")
+ const collectionIndexDragged = dataTransfer.getData("collectionIndex")
+ if (folderPath && requestIndex) {
+ emit("drop-request", {
+ folderPath,
+ requestIndex,
+ destinationCollectionIndex,
+ })
+ } else {
+ emit("drop-collection", {
+ collectionIndexDragged,
+ destinationCollectionIndex,
+ })
+ }
+}
+
+const updateRequestOrder = (
+ dataTransfer: DataTransfer,
+ {
+ folderPath,
+ requestIndex,
+ }: { folderPath: string | null; requestIndex: string }
+) => {
+ if (!folderPath) return
+ const dragedRequestIndex = dataTransfer.getData("requestIndex")
+ const destinationRequestIndex = requestIndex
+ const destinationCollectionIndex = folderPath
+
+ emit("update-request-order", {
+ dragedRequestIndex,
+ destinationRequestIndex,
+ destinationCollectionIndex,
+ })
+}
+
+const updateCollectionOrder = (
+ dataTransfer: DataTransfer,
+ destinationCollectionIndex: string
+) => {
+ const dragedCollectionIndex = dataTransfer.getData("collectionIndex")
+
+ emit("update-collection-order", {
+ dragedCollectionIndex,
+ destinationCollectionIndex,
+ })
+}
+
type TeamCollections = {
type: "collections"
data: {
diff --git a/packages/hoppscotch-common/src/components/collections/TeamSelect.vue b/packages/hoppscotch-common/src/components/collections/TeamSelect.vue
deleted file mode 100644
index c4745017c..000000000
--- a/packages/hoppscotch-common/src/components/collections/TeamSelect.vue
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
- {{ t("state.loading") }}
-
-
- {
- updateSelectedTeam(team)
- hide()
- }
- "
- />
-
- {
- displayTeamModalAdd(true)
- hide()
- }
- "
- />
-
-
-
![]()
-
- {{ t("empty.teams") }}
-
-
{
- displayTeamModalAdd(true)
- hide()
- }
- "
- />
-
-
-
-
-
-
-
-
-
diff --git a/packages/hoppscotch-common/src/components/collections/index.vue b/packages/hoppscotch-common/src/components/collections/index.vue
index d8e360c29..57d0144e6 100644
--- a/packages/hoppscotch-common/src/components/collections/index.vue
+++ b/packages/hoppscotch-common/src/components/collections/index.vue
@@ -1,11 +1,22 @@
-
+
+
-
+
+
diff --git a/packages/hoppscotch-common/src/components/environments/index.vue b/packages/hoppscotch-common/src/components/environments/index.vue
index 8afe7d2ee..f868390b5 100644
--- a/packages/hoppscotch-common/src/components/environments/index.vue
+++ b/packages/hoppscotch-common/src/components/environments/index.vue
@@ -1,8 +1,9 @@
+
- help_outline
+
{{ getErrorMessage(adapterError) }}
@@ -156,11 +157,6 @@
class="border-b border-dividerLight"
@edit-environment="editEnvironment('Global')"
/>
-
{
- environmentType.value.selectedTeam = newSelectedTeam
-}
-const updateEnvironmentType = (newEnvironmentType: EnvironmentType) => {
- environmentType.value.type = newEnvironmentType
-}
+// TeamList-Adapter
+const teamListAdapter = new TeamListAdapter(true)
+const myTeams = useReadonlyStream(teamListAdapter.teamList$, null)
+const teamListFetched = ref(false)
+const REMEMBERED_TEAM_ID = useLocalState("REMEMBERED_TEAM_ID")
const adapter = new TeamEnvironmentAdapter(undefined)
const adapterLoading = useReadonlyStream(adapter.loading$, false)
@@ -243,6 +242,45 @@ const loading = computed(
() => adapterLoading.value && teamEnvironmentList.value.length === 0
)
+watch(
+ () => myTeams.value,
+ (newTeams) => {
+ if (newTeams && !teamListFetched.value) {
+ teamListFetched.value = true
+ if (REMEMBERED_TEAM_ID.value && currentUser.value) {
+ const team = newTeams.find((t) => t.id === REMEMBERED_TEAM_ID.value)
+ if (team) updateSelectedTeam(team)
+ }
+ }
+ }
+)
+
+watch(
+ () => environmentType.value.selectedTeam,
+ (newTeam) => {
+ if (newTeam) {
+ adapter.changeTeamID(newTeam.id)
+ }
+ }
+)
+
+const switchToMyEnvironments = () => {
+ environmentType.value.selectedTeam = undefined
+ updateEnvironmentType("my-environments")
+ adapter.changeTeamID(undefined)
+}
+
+const updateSelectedTeam = (newSelectedTeam: SelectedTeam) => {
+ if (newSelectedTeam) {
+ environmentType.value.selectedTeam = newSelectedTeam
+ REMEMBERED_TEAM_ID.value = newSelectedTeam.id
+ updateEnvironmentType("team-environments")
+ }
+}
+const updateEnvironmentType = (newEnvironmentType: EnvironmentType) => {
+ environmentType.value.type = newEnvironmentType
+}
+
watch(
() => environmentType.value.selectedTeam?.id,
(newTeamID) => {
@@ -254,7 +292,30 @@ watch(
() => currentUser.value,
(newValue) => {
if (!newValue) {
- updateEnvironmentType("my-environments")
+ switchToMyEnvironments()
+ }
+ }
+)
+
+onLoggedIn(() => {
+ !teamListAdapter.isInitialized && teamListAdapter.initialize()
+})
+
+const workspace = useReadonlyStream(workspaceStatus$, { type: "personal" })
+
+// Used to switch environment type and team when user switch workspace in the global workspace switcher
+// Check if there is a teamID in the workspace, if yes, switch to team environment and select the team
+// If there is no teamID, switch to my environment
+watch(
+ () => workspace.value.teamID,
+ (teamID) => {
+ if (!teamID) {
+ switchToMyEnvironments()
+ } else if (teamID) {
+ const team = myTeams.value?.find((t) => t.id === teamID)
+ if (team) {
+ updateSelectedTeam(team)
+ }
}
}
)
diff --git a/packages/hoppscotch-common/src/components/environments/teams/index.vue b/packages/hoppscotch-common/src/components/environments/teams/index.vue
index 3e77f7218..3d281c408 100644
--- a/packages/hoppscotch-common/src/components/environments/teams/index.vue
+++ b/packages/hoppscotch-common/src/components/environments/teams/index.vue
@@ -94,7 +94,7 @@
v-if="!loading && adapterError"
class="flex flex-col items-center py-4"
>
- help_outline
+
{{ getErrorMessage(adapterError) }}
-
+
-
-
+
-
-
-
- {{ t("action.filter") }}
+
+
+
+
+
+ {{ t("action.filter") }}
+
+
+
+
+ {{ t("action.group_by") }}
+
+
-
-
-
- {{ t("action.group_by") }}
-
-
-
-
-
-
+
+
+
+
diff --git a/packages/hoppscotch-common/src/components/http/CodegenModal.vue b/packages/hoppscotch-common/src/components/http/CodegenModal.vue
index 43f6afe58..d3186aabc 100644
--- a/packages/hoppscotch-common/src/components/http/CodegenModal.vue
+++ b/packages/hoppscotch-common/src/components/http/CodegenModal.vue
@@ -28,7 +28,7 @@
-
+
@@ -180,7 +179,6 @@
:label="shareButtonText"
:icon="copyLinkIcon"
:loading="fetchingShareLink"
- :shortcut="['C']"
@click="
() => {
copyRequest()
diff --git a/packages/hoppscotch-common/src/components/http/Sidebar.vue b/packages/hoppscotch-common/src/components/http/Sidebar.vue
index ae210d3f8..c4465ec3d 100644
--- a/packages/hoppscotch-common/src/components/http/Sidebar.vue
+++ b/packages/hoppscotch-common/src/components/http/Sidebar.vue
@@ -22,7 +22,7 @@
diff --git a/packages/hoppscotch-common/src/components/profile/Picture.vue b/packages/hoppscotch-common/src/components/profile/Picture.vue
index 3e958bd28..a9eaf68ba 100644
--- a/packages/hoppscotch-common/src/components/profile/Picture.vue
+++ b/packages/hoppscotch-common/src/components/profile/Picture.vue
@@ -1,7 +1,7 @@
-
![]()
-
+
diff --git a/packages/hoppscotch-common/src/components/tab/Primary.vue b/packages/hoppscotch-common/src/components/tab/Primary.vue
index e7bd3639c..24269fe31 100644
--- a/packages/hoppscotch-common/src/components/tab/Primary.vue
+++ b/packages/hoppscotch-common/src/components/tab/Primary.vue
@@ -3,7 +3,7 @@
:to="to"
:exact="exact"
:blank="blank"
- class="inline-flex items-center px-4 py-2 truncate rounded transition focus:outline-none"
+ class="inline-flex items-center px-4 py-2 truncate transition rounded focus:outline-none"
:class="[
color
? `text-${color}-500 hover:text-${color}-600 focus-visible:text-${color}-600`
@@ -19,11 +19,13 @@
class="opacity-75 svg-icons"
:class="label ? (reverse ? 'ml-4' : 'mr-4') : ''"
/>
- {{ label }}
+
+ {{ label }}
+
-
diff --git a/packages/hoppscotch-common/src/components/teams/Team.vue b/packages/hoppscotch-common/src/components/teams/Team.vue
index 3a0d6b5e0..990b04b25 100644
--- a/packages/hoppscotch-common/src/components/teams/Team.vue
+++ b/packages/hoppscotch-common/src/components/teams/Team.vue
@@ -27,31 +27,7 @@
>
{{ team.name || t("state.nothing_found") }}
-
+
@@ -171,7 +147,7 @@
import { ref } from "vue"
import { pipe } from "fp-ts/function"
import * as TE from "fp-ts/TaskEither"
-import { TeamMemberRole } from "~/helpers/backend/graphql"
+import { GetMyTeamsQuery } from "~/helpers/backend/graphql"
import {
deleteTeam as backendDeleteTeam,
leaveTeam,
@@ -189,18 +165,7 @@ import IconTrash2 from "~icons/lucide/trash-2"
const t = useI18n()
const props = defineProps<{
- team: {
- name: string
- myRole: TeamMemberRole
- ownersCount: number
- teamMembers: Array<{
- user: {
- displayName: string
- photoURL: string | null
- email: string | null
- }
- }>
- }
+ team: GetMyTeamsQuery["myTeams"][number]
teamID: string
compact: boolean
}>()
diff --git a/packages/hoppscotch-common/src/components/workspace/Current.vue b/packages/hoppscotch-common/src/components/workspace/Current.vue
new file mode 100644
index 000000000..517143b8e
--- /dev/null
+++ b/packages/hoppscotch-common/src/components/workspace/Current.vue
@@ -0,0 +1,38 @@
+
+
+
+ {{
+ workspace.type === "personal"
+ ? t("workspace.personal")
+ : teamWorkspaceName
+ }}
+
+
+ {{ section }}
+
+
+
+
diff --git a/packages/hoppscotch-common/src/components/workspace/Selector.vue b/packages/hoppscotch-common/src/components/workspace/Selector.vue
new file mode 100644
index 000000000..2724e2347
--- /dev/null
+++ b/packages/hoppscotch-common/src/components/workspace/Selector.vue
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+ {{ t("state.loading") }}
+
+
+
+ {{ t("empty.teams") }}
+
+
+
+
+
+
+ {{ t("team.title") }}
+
+
+
+
+
+
+ help_outline
+ {{ t("error.something_went_wrong") }}
+
+
+
+
+
+
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamCollection.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamCollection.graphql
new file mode 100644
index 000000000..88794ca7a
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamCollection.graphql
@@ -0,0 +1,8 @@
+mutation MoveRESTTeamCollection($collectionID: ID!, $parentCollectionID: ID) {
+ moveCollection(
+ collectionID: $collectionID
+ parentCollectionID: $parentCollectionID
+ ) {
+ id
+ }
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamRequest.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamRequest.graphql
new file mode 100644
index 000000000..c1538d31e
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamRequest.graphql
@@ -0,0 +1,5 @@
+mutation MoveRESTTeamRequest($collectionID: ID!, $requestID: ID!) {
+ moveRequest(destCollID: $collectionID, requestID: $requestID) {
+ id
+ }
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamRquest.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamRquest.graphql
deleted file mode 100644
index 3c0bc3b46..000000000
--- a/packages/hoppscotch-common/src/helpers/backend/gql/mutations/MoveRESTTeamRquest.graphql
+++ /dev/null
@@ -1,5 +0,0 @@
-mutation MoveRESTTeamRequest($requestID: ID!, $collectionID: ID!) {
- moveRequest(requestID: $requestID, destCollID: $collectionID) {
- id
- }
-}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/mutations/UpdateCollectionOrder.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/UpdateCollectionOrder.graphql
new file mode 100644
index 000000000..fdc422fa2
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/UpdateCollectionOrder.graphql
@@ -0,0 +1,3 @@
+mutation UpdateCollectionOrder($collectionID: ID!, $destCollID: ID!) {
+ updateCollectionOrder(collectionID: $collectionID, destCollID: $destCollID)
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/mutations/UpdateLookUpRequestOrder.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/UpdateLookUpRequestOrder.graphql
new file mode 100644
index 000000000..972f7a619
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/mutations/UpdateLookUpRequestOrder.graphql
@@ -0,0 +1,11 @@
+mutation UpdateLookUpRequestOrder(
+ $requestID: ID!
+ $nextRequestID: ID
+ $collectionID: ID!
+) {
+ updateLookUpRequestOrder(
+ requestID: $requestID
+ nextRequestID: $nextRequestID
+ collectionID: $collectionID
+ )
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/queries/GetSingleCollection.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/queries/GetSingleCollection.graphql
new file mode 100644
index 000000000..50505d6f5
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/queries/GetSingleCollection.graphql
@@ -0,0 +1,9 @@
+query GetSingleCollection($collectionID: ID!) {
+ collection(collectionID: $collectionID) {
+ id
+ title
+ parent {
+ id
+ }
+ }
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/queries/GetSingleRequest.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/queries/GetSingleRequest.graphql
new file mode 100644
index 000000000..ba7cb4c11
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/queries/GetSingleRequest.graphql
@@ -0,0 +1,8 @@
+query GetSingleRequest($requestID: ID!) {
+ request(requestID: $requestID) {
+ id
+ collectionID
+ title
+ request
+ }
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamCollectionMoved.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamCollectionMoved.graphql
new file mode 100644
index 000000000..6fff331af
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamCollectionMoved.graphql
@@ -0,0 +1,9 @@
+subscription TeamCollectionMoved($teamID: ID!) {
+ teamCollectionMoved(teamID: $teamID) {
+ id
+ title
+ parent {
+ id
+ }
+ }
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamCollectionOrderUpdated.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamCollectionOrderUpdated.graphql
new file mode 100644
index 000000000..0509082ab
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamCollectionOrderUpdated.graphql
@@ -0,0 +1,18 @@
+subscription TeamCollectionOrderUpdated($teamID: ID!) {
+ collectionOrderUpdated(teamID: $teamID) {
+ collection {
+ id
+ title
+ parent {
+ id
+ }
+ }
+ nextCollection {
+ id
+ title
+ parent {
+ id
+ }
+ }
+ }
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamRequestMoved.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamRequestMoved.graphql
new file mode 100644
index 000000000..bda0cb05f
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamRequestMoved.graphql
@@ -0,0 +1,8 @@
+subscription TeamRequestMoved($teamID: ID!) {
+ requestMoved(teamID: $teamID) {
+ id
+ collectionID
+ request
+ title
+ }
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamRequestOrderUpdated.graphql b/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamRequestOrderUpdated.graphql
new file mode 100644
index 000000000..1b09ce52e
--- /dev/null
+++ b/packages/hoppscotch-common/src/helpers/backend/gql/subscriptions/TeamRequestOrderUpdated.graphql
@@ -0,0 +1,16 @@
+subscription TeamRequestOrderUpdated($teamID: ID!) {
+ requestOrderUpdated(teamID: $teamID) {
+ request {
+ id
+ collectionID
+ request
+ title
+ }
+ nextRequest {
+ id
+ collectionID
+ request
+ title
+ }
+ }
+}
diff --git a/packages/hoppscotch-common/src/helpers/backend/mutations/TeamCollection.ts b/packages/hoppscotch-common/src/helpers/backend/mutations/TeamCollection.ts
index 87b818236..23a450897 100644
--- a/packages/hoppscotch-common/src/helpers/backend/mutations/TeamCollection.ts
+++ b/packages/hoppscotch-common/src/helpers/backend/mutations/TeamCollection.ts
@@ -12,16 +12,37 @@ import {
ImportFromJsonDocument,
ImportFromJsonMutation,
ImportFromJsonMutationVariables,
+ MoveRestTeamCollectionDocument,
+ MoveRestTeamCollectionMutation,
+ MoveRestTeamCollectionMutationVariables,
RenameCollectionDocument,
RenameCollectionMutation,
RenameCollectionMutationVariables,
+ UpdateCollectionOrderDocument,
+ UpdateCollectionOrderMutation,
+ UpdateCollectionOrderMutationVariables,
} from "../graphql"
type CreateNewRootCollectionError = "team_coll/short_title"
+
type CreateChildCollectionError = "team_coll/short_title"
+
type RenameCollectionError = "team_coll/short_title"
+
type DeleteCollectionError = "team/invalid_coll_id"
+type MoveRestTeamCollectionError =
+ | "team/invalid_coll_id"
+ | "team_coll/invalid_target_id"
+ | "team/collection_is_parent_coll"
+ | "team/target_and_destination_collection_are_same"
+ | "team/target_collection_is_already_root_collection"
+
+type UpdateCollectionOrderError =
+ | "team/invalid_coll_id"
+ | "team/collection_and_next_collection_are_same"
+ | "team/team_collections_have_different_parents"
+
export const createNewRootCollection = (title: string, teamID: string) =>
runMutation<
CreateNewRootCollectionMutation,
@@ -66,6 +87,33 @@ export const deleteCollection = (collectionID: string) =>
collectionID,
})
+/** Can be used to move both collection and folder (considered same in BE) */
+export const moveRESTTeamCollection = (
+ collectionID: string,
+ destinationCollectionID: string | null
+) =>
+ runMutation<
+ MoveRestTeamCollectionMutation,
+ MoveRestTeamCollectionMutationVariables,
+ MoveRestTeamCollectionError
+ >(MoveRestTeamCollectionDocument, {
+ collectionID,
+ parentCollectionID: destinationCollectionID,
+ })
+
+export const updateOrderRESTTeamCollection = (
+ collectionID: string,
+ destCollID: string
+) =>
+ runMutation<
+ UpdateCollectionOrderMutation,
+ UpdateCollectionOrderMutationVariables,
+ UpdateCollectionOrderError
+ >(UpdateCollectionOrderDocument, {
+ collectionID,
+ destCollID,
+ })
+
export const importJSONToTeam = (collectionJSON: string, teamID: string) =>
runMutation
(
ImportFromJsonDocument,
diff --git a/packages/hoppscotch-common/src/helpers/backend/mutations/TeamRequest.ts b/packages/hoppscotch-common/src/helpers/backend/mutations/TeamRequest.ts
index 7346a66c5..daff454a5 100644
--- a/packages/hoppscotch-common/src/helpers/backend/mutations/TeamRequest.ts
+++ b/packages/hoppscotch-common/src/helpers/backend/mutations/TeamRequest.ts
@@ -9,16 +9,27 @@ import {
MoveRestTeamRequestDocument,
MoveRestTeamRequestMutation,
MoveRestTeamRequestMutationVariables,
+ UpdateLookUpRequestOrderDocument,
+ UpdateLookUpRequestOrderMutation,
+ UpdateLookUpRequestOrderMutationVariables,
UpdateRequestDocument,
UpdateRequestMutation,
UpdateRequestMutationVariables,
} from "../graphql"
+type DeleteRequestErrors = "team_req/not_found"
+
type MoveRestTeamRequestErrors =
| "team_req/not_found"
| "team_req/invalid_target_id"
+ | "team/invalid_coll_id"
+ | "team_req/not_required_role"
+ | "bug/team_req/no_req_id"
-type DeleteRequestErrors = "team_req/not_found"
+type UpdateLookUpRequestOrderErrors =
+ | "team_req/not_found"
+ | "team/request_and_next_request_are_same"
+ | "team_req/requests_not_from_same_collection"
export const createRequestInCollection = (
collectionID: string,
@@ -61,12 +72,27 @@ export const deleteTeamRequest = (requestID: string) =>
requestID,
})
-export const moveRESTTeamRequest = (requestID: string, collectionID: string) =>
+export const moveRESTTeamRequest = (collectionID: string, requestID: string) =>
runMutation<
MoveRestTeamRequestMutation,
MoveRestTeamRequestMutationVariables,
MoveRestTeamRequestErrors
>(MoveRestTeamRequestDocument, {
+ collectionID,
requestID,
+ })
+
+export const updateOrderRESTTeamRequest = (
+ requestID: string,
+ nextRequestID: string,
+ collectionID: string
+) =>
+ runMutation<
+ UpdateLookUpRequestOrderMutation,
+ UpdateLookUpRequestOrderMutationVariables,
+ UpdateLookUpRequestOrderErrors
+ >(UpdateLookUpRequestOrderDocument, {
+ requestID,
+ nextRequestID,
collectionID,
})
diff --git a/packages/hoppscotch-common/src/helpers/fb/index.ts b/packages/hoppscotch-common/src/helpers/fb/index.ts
index 7463c3b8a..1e8af88d7 100644
--- a/packages/hoppscotch-common/src/helpers/fb/index.ts
+++ b/packages/hoppscotch-common/src/helpers/fb/index.ts
@@ -2,7 +2,6 @@ import { initializeApp } from "firebase/app"
import { platform } from "~/platform"
import { initAnalytics } from "./analytics"
import { initCollections } from "./collections"
-import { initEnvironments } from "./environments"
import { initHistory } from "./history"
import { initSettings } from "./settings"
@@ -28,7 +27,7 @@ export function initializeFirebase() {
initSettings()
initCollections()
initHistory()
- initEnvironments()
+ platform.sync.environments.initEnvironmentsSync()
initAnalytics()
initialized = true
diff --git a/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts b/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts
index 49a891bde..ee9617d31 100644
--- a/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts
+++ b/packages/hoppscotch-common/src/helpers/teams/TeamCollectionAdapter.ts
@@ -16,6 +16,10 @@ import {
TeamRequestDeletedDocument,
GetCollectionChildrenDocument,
GetCollectionRequestsDocument,
+ TeamRequestMovedDocument,
+ TeamCollectionMovedDocument,
+ TeamRequestOrderUpdatedDocument,
+ TeamCollectionOrderUpdatedDocument,
} from "~/helpers/backend/graphql"
const TEAMS_BACKEND_PAGE_SIZE = 10
@@ -201,6 +205,10 @@ export default class NewTeamCollectionAdapter {
private teamRequestAdded$: Subscription | null
private teamRequestUpdated$: Subscription | null
private teamRequestDeleted$: Subscription | null
+ private teamRequestMoved$: Subscription | null
+ private teamCollectionMoved$: Subscription | null
+ private teamRequestOrderUpdated$: Subscription | null
+ private teamCollectionOrderUpdated$: Subscription | null
private teamCollectionAddedSub: WSubscription | null
private teamCollectionUpdatedSub: WSubscription | null
@@ -208,6 +216,10 @@ export default class NewTeamCollectionAdapter {
private teamRequestAddedSub: WSubscription | null
private teamRequestUpdatedSub: WSubscription | null
private teamRequestDeletedSub: WSubscription | null
+ private teamRequestMovedSub: WSubscription | null
+ private teamCollectionMovedSub: WSubscription | null
+ private teamRequestOrderUpdatedSub: WSubscription | null
+ private teamCollectionOrderUpdatedSub: WSubscription | null
constructor(private teamID: string | null) {
this.collections$ = new BehaviorSubject([])
@@ -221,6 +233,10 @@ export default class NewTeamCollectionAdapter {
this.teamRequestAdded$ = null
this.teamRequestDeleted$ = null
this.teamRequestUpdated$ = null
+ this.teamRequestMoved$ = null
+ this.teamCollectionMoved$ = null
+ this.teamRequestOrderUpdated$ = null
+ this.teamCollectionOrderUpdated$ = null
this.teamCollectionAddedSub = null
this.teamCollectionUpdatedSub = null
@@ -228,6 +244,10 @@ export default class NewTeamCollectionAdapter {
this.teamRequestAddedSub = null
this.teamRequestDeletedSub = null
this.teamRequestUpdatedSub = null
+ this.teamRequestMovedSub = null
+ this.teamCollectionMovedSub = null
+ this.teamRequestOrderUpdatedSub = null
+ this.teamCollectionOrderUpdatedSub = null
if (this.teamID) this.initialize()
}
@@ -255,6 +275,10 @@ export default class NewTeamCollectionAdapter {
this.teamRequestAdded$?.unsubscribe()
this.teamRequestDeleted$?.unsubscribe()
this.teamRequestUpdated$?.unsubscribe()
+ this.teamRequestMoved$?.unsubscribe()
+ this.teamCollectionMoved$?.unsubscribe()
+ this.teamRequestOrderUpdated$?.unsubscribe()
+ this.teamCollectionOrderUpdated$?.unsubscribe()
this.teamCollectionAddedSub?.unsubscribe()
this.teamCollectionUpdatedSub?.unsubscribe()
@@ -262,6 +286,10 @@ export default class NewTeamCollectionAdapter {
this.teamRequestAddedSub?.unsubscribe()
this.teamRequestDeletedSub?.unsubscribe()
this.teamRequestUpdatedSub?.unsubscribe()
+ this.teamRequestMovedSub?.unsubscribe()
+ this.teamCollectionMovedSub?.unsubscribe()
+ this.teamRequestOrderUpdatedSub?.unsubscribe()
+ this.teamCollectionOrderUpdatedSub?.unsubscribe()
}
private async initialize() {
@@ -279,6 +307,9 @@ export default class NewTeamCollectionAdapter {
collection: TeamCollection,
parentCollectionID: string | null
) {
+ // Check if we have it already in the entity tree, if so, we don't need it again
+ if (this.entityIDs.has(`collection-${collection.id}`)) return
+
const tree = this.collections$.value
if (!parentCollectionID) {
@@ -328,7 +359,7 @@ export default class NewTeamCollectionAdapter {
this.loadingCollections$.getValue().filter((x) => x !== "root")
)
- throw new Error(`Error fetching root collections: ${result}`)
+ throw new Error(`Error fetching root collections: ${result.left.error}`)
}
totalCollections.push(
@@ -456,6 +487,143 @@ export default class NewTeamCollectionAdapter {
this.collections$.next(tree)
}
+ /**
+ * Moves a request from one collection to another
+ *
+ * @param {string} request - The request to move
+ */
+ private async moveRequest(request: TeamRequest) {
+ const tree = this.collections$.value
+
+ // Remove the request from the current collection
+ this.removeRequest(request.id)
+
+ const currentRequest = request.request
+
+ if (currentRequest === null || currentRequest === undefined) return
+
+ // Find request in tree, don't attempt if no collection or no requests is found
+ const collection = findCollInTree(tree, request.collectionID)
+ if (!collection) return // Ignore add request
+
+ // Collection is not expanded
+ if (!collection.requests) return
+
+ this.addRequest({
+ id: request.id,
+ collectionID: request.collectionID,
+ request: translateToNewRequest(request.request),
+ title: request.title,
+ })
+ }
+
+ /**
+ * Moves a collection from one collection to another or to root
+ *
+ * @param {string} collectionID - The ID of the collection to move
+ */
+ private async moveCollection(
+ collectionID: string,
+ parentID: string | null,
+ title: string
+ ) {
+ // Remove the collection from the current position
+ this.removeCollection(collectionID)
+
+ if (collectionID === null || parentID === undefined) return
+
+ // Expand the parent collection if it is not expanded
+ // so that the old children is also visible when expanding
+ if (parentID) this.expandCollection(parentID)
+
+ this.addCollection(
+ {
+ id: collectionID,
+ children: null,
+ requests: null,
+ title: title,
+ },
+ parentID ?? null
+ )
+ }
+
+ public updateRequestOrder(
+ dragedRequestID: string,
+ destinationRequestID: string,
+ destinationCollectionID: string
+ ) {
+ const tree = this.collections$.value
+
+ // Find collection in tree, don't attempt if no collection is found
+ const collection = findCollInTree(tree, destinationCollectionID)
+ if (!collection) return // Ignore order update
+
+ // Collection is not expanded
+ if (!collection.requests) return
+
+ const requestIndex = collection.requests.findIndex(
+ (req) => req.id === dragedRequestID
+ )
+ const destinationIndex = collection.requests.findIndex(
+ (req) => req.id === destinationRequestID
+ )
+
+ if (requestIndex === -1) return
+
+ const request = collection.requests[requestIndex]
+
+ collection.requests.splice(requestIndex, 1)
+ collection.requests.splice(destinationIndex, 0, request)
+
+ this.collections$.next(tree)
+ }
+
+ public updateCollectionOrder = (
+ collectionID: string,
+ destinationCollectionID: string
+ ) => {
+ const tree = this.collections$.value
+
+ // Find collection in tree
+ const coll = findParentOfColl(tree, destinationCollectionID)
+
+ // If the collection has a parent collection and check if it has children
+ if (coll && coll.children) {
+ const collectionIndex = coll.children.findIndex(
+ (coll) => coll.id === collectionID
+ )
+
+ const destinationIndex = coll.children.findIndex(
+ (coll) => coll.id === destinationCollectionID
+ )
+
+ // If the collection index is not found, don't update
+ if (collectionIndex === -1) return
+
+ const collection = coll.children[collectionIndex]
+
+ coll.children.splice(collectionIndex, 1)
+ coll.children.splice(destinationIndex, 0, collection)
+ } else {
+ // If the collection has no parent collection, it is a root collection
+ const collectionIndex = tree.findIndex((coll) => coll.id === collectionID)
+
+ const destinationIndex = tree.findIndex(
+ (coll) => coll.id === destinationCollectionID
+ )
+
+ // If the collection index is not found, don't update
+ if (collectionIndex === -1) return
+
+ const collection = tree[collectionIndex]
+
+ tree.splice(collectionIndex, 1)
+ tree.splice(destinationIndex, 0, collection)
+ }
+
+ this.collections$.next(tree)
+ }
+
private registerSubscriptions() {
if (!this.teamID) return
@@ -575,7 +743,7 @@ export default class NewTeamCollectionAdapter {
},
})
- this.teamRequestUpdatedSub = teamReqDeleted
+ this.teamRequestDeletedSub = teamReqDeleted
this.teamRequestDeleted$ = teamReqDeleted$.subscribe((result) => {
if (E.isLeft(result))
throw new Error(
@@ -584,6 +752,110 @@ export default class NewTeamCollectionAdapter {
this.removeRequest(result.right.teamRequestDeleted)
})
+
+ const [teamRequestMoved$, teamRequestMoved] = runGQLSubscription({
+ query: TeamRequestMovedDocument,
+ variables: {
+ teamID: this.teamID,
+ },
+ })
+
+ this.teamRequestMovedSub = teamRequestMoved
+ this.teamRequestMoved$ = teamRequestMoved$.subscribe((result) => {
+ if (E.isLeft(result))
+ throw new Error(
+ `Team Request Move Error ${JSON.stringify(result.left)}`
+ )
+
+ const { requestMoved } = result.right
+
+ const request = {
+ id: requestMoved.id,
+ collectionID: requestMoved.collectionID,
+ title: requestMoved.title,
+ request: JSON.parse(requestMoved.request),
+ }
+
+ this.moveRequest(request)
+ })
+
+ const [teamCollectionMoved$, teamCollectionMoved] = runGQLSubscription({
+ query: TeamCollectionMovedDocument,
+ variables: {
+ teamID: this.teamID,
+ },
+ })
+
+ this.teamCollectionMovedSub = teamCollectionMoved
+ this.teamCollectionMoved$ = teamCollectionMoved$.subscribe((result) => {
+ if (E.isLeft(result))
+ throw new Error(
+ `Team Collection Move Error ${JSON.stringify(result.left)}`
+ )
+
+ const { teamCollectionMoved } = result.right
+ const { id, parent, title } = teamCollectionMoved
+
+ const parentID = parent?.id ?? null
+
+ this.moveCollection(id, parentID, title)
+ })
+
+ const [teamRequestOrderUpdated$, teamRequestOrderUpdated] =
+ runGQLSubscription({
+ query: TeamRequestOrderUpdatedDocument,
+ variables: {
+ teamID: this.teamID,
+ },
+ })
+
+ this.teamRequestOrderUpdatedSub = teamRequestOrderUpdated
+ this.teamRequestOrderUpdated$ = teamRequestOrderUpdated$.subscribe(
+ (result) => {
+ if (E.isLeft(result))
+ throw new Error(
+ `Team Request Order Update Error ${JSON.stringify(result.left)}`
+ )
+
+ const { requestOrderUpdated } = result.right
+ const { request } = requestOrderUpdated
+ const { nextRequest } = requestOrderUpdated
+
+ if (!nextRequest) return
+
+ this.updateRequestOrder(
+ request.id,
+ nextRequest.id,
+ nextRequest.collectionID
+ )
+ }
+ )
+
+ const [teamCollectionOrderUpdated$, teamCollectionOrderUpdated] =
+ runGQLSubscription({
+ query: TeamCollectionOrderUpdatedDocument,
+ variables: {
+ teamID: this.teamID,
+ },
+ })
+
+ this.teamCollectionOrderUpdatedSub = teamCollectionOrderUpdated
+ this.teamCollectionOrderUpdated$ = teamCollectionOrderUpdated$.subscribe(
+ (result) => {
+ if (E.isLeft(result))
+ throw new Error(
+ `Team Collection Order Update Error ${JSON.stringify(result.left)}`
+ )
+
+ const { collectionOrderUpdated } = result.right
+ const { collection } = collectionOrderUpdated
+ const { nextCollection } = collectionOrderUpdated
+
+ if (!nextCollection) return
+
+ this.updateCollectionOrder(collection.id, nextCollection.id)
+ }
+ )
}
/**
diff --git a/packages/hoppscotch-common/src/helpers/teams/TeamEnvironmentAdapter.ts b/packages/hoppscotch-common/src/helpers/teams/TeamEnvironmentAdapter.ts
index 55ab6b57c..7ed676625 100644
--- a/packages/hoppscotch-common/src/helpers/teams/TeamEnvironmentAdapter.ts
+++ b/packages/hoppscotch-common/src/helpers/teams/TeamEnvironmentAdapter.ts
@@ -11,11 +11,19 @@ import {
} from "../backend/graphql"
import { TeamEnvironment } from "./TeamEnvironment"
+type EntityType = "environment"
+type EntityID = `${EntityType}-${string}`
export default class TeamEnvironmentAdapter {
error$: BehaviorSubject | null>
loading$: BehaviorSubject
teamEnvironmentList$: BehaviorSubject
+ /**
+ * Stores the entity (environments) ids of all the loaded entities.
+ * Used for preventing duplication of data which definitely is not possible (duplication due to network problems etc.)
+ */
+ private entityIDs: Set
+
private isDispose: boolean
private teamEnvironmentCreated$: Subscription | null
@@ -32,6 +40,8 @@ export default class TeamEnvironmentAdapter {
this.teamEnvironmentList$ = new BehaviorSubject([])
this.isDispose = true
+ this.entityIDs = new Set()
+
this.teamEnvironmentCreated$ = null
this.teamEnvironmentDeleted$ = null
this.teamEnvironmentUpdated$ = null
@@ -56,6 +66,8 @@ export default class TeamEnvironmentAdapter {
this.teamEnvironmentList$.next([])
this.loading$.next(false)
+ this.entityIDs.clear()
+
this.unsubscribeSubscriptions()
if (this.teamID) this.initialize()
@@ -112,16 +124,25 @@ export default class TeamEnvironmentAdapter {
)
}
+ // Add all the environments to the entity ids list
+ results.forEach((env) => this.entityIDs.add(`environment-${env.id}`))
+
this.teamEnvironmentList$.next(results)
this.loading$.next(false)
}
private createNewTeamEnvironment(newEnvironment: TeamEnvironment) {
+ // Check if we have it already in the entity tree, if so, we don't need it again
+ if (this.entityIDs.has(`environment-${newEnvironment.id}`)) return
+
const teamEnvironments = this.teamEnvironmentList$.value
teamEnvironments.push(newEnvironment)
+ // Add to entity ids set
+ this.entityIDs.add(`environment-${newEnvironment.id}`)
+
this.teamEnvironmentList$.next(teamEnvironments)
}
@@ -129,7 +150,7 @@ export default class TeamEnvironmentAdapter {
const teamEnvironments = this.teamEnvironmentList$.value.filter(
({ id }) => id !== envId
)
-
+ this.entityIDs.delete(`environment-${envId}`)
this.teamEnvironmentList$.next(teamEnvironments)
}
diff --git a/packages/hoppscotch-common/src/helpers/teams/TeamListAdapter.ts b/packages/hoppscotch-common/src/helpers/teams/TeamListAdapter.ts
index 35ffb2a4b..9acdf4eda 100644
--- a/packages/hoppscotch-common/src/helpers/teams/TeamListAdapter.ts
+++ b/packages/hoppscotch-common/src/helpers/teams/TeamListAdapter.ts
@@ -15,6 +15,8 @@ export default class TeamListAdapter {
private timeoutHandle: ReturnType | null
private isDispose: boolean
+ public isInitialized: boolean
+
constructor(deferInit = false) {
this.error$ = new BehaviorSubject | null>(null)
this.loading$ = new BehaviorSubject(false)
@@ -22,6 +24,8 @@ export default class TeamListAdapter {
this.timeoutHandle = null
this.isDispose = false
+ this.isInitialized = false
+
if (!deferInit) this.initialize()
}
@@ -29,6 +33,8 @@ export default class TeamListAdapter {
if (this.timeoutHandle) throw new Error(`Adapter already initialized`)
if (this.isDispose) throw new Error(`Adapter has been disposed`)
+ this.isInitialized = true
+
const func = async () => {
await this.fetchList()
@@ -44,6 +50,7 @@ export default class TeamListAdapter {
this.isDispose = true
clearTimeout(this.timeoutHandle as any)
this.timeoutHandle = null
+ this.isInitialized = false
}
async fetchList() {
diff --git a/packages/hoppscotch-common/src/newstore/collections.ts b/packages/hoppscotch-common/src/newstore/collections.ts
index 6ccec0e66..bcfe05571 100644
--- a/packages/hoppscotch-common/src/newstore/collections.ts
+++ b/packages/hoppscotch-common/src/newstore/collections.ts
@@ -186,6 +186,133 @@ const restCollectionDispatchers = defineDispatchers({
}
},
+ moveFolder(
+ { state }: RESTCollectionStoreType,
+ { path, destinationPath }: { path: string; destinationPath: string | null }
+ ) {
+ const newState = state
+
+ // Move the folder to the root
+ if (destinationPath === null) {
+ const indexPaths = path.split("/").map((x) => parseInt(x))
+
+ if (indexPaths.length === 0) {
+ console.log("Given path too short. Skipping request.")
+ return {}
+ }
+
+ const folderIndex = indexPaths.pop() as number
+
+ const containingFolder = navigateToFolderWithIndexPath(
+ newState,
+ indexPaths
+ )
+ if (containingFolder === null) {
+ console.error(
+ `The folder to move is already in the root. Skipping request to move folder.`
+ )
+ return {}
+ }
+
+ const theFolder = containingFolder.folders.splice(folderIndex, 1)
+ newState.push(theFolder[0] as HoppCollection)
+
+ return {
+ state: newState,
+ }
+ }
+
+ const indexPaths = path.split("/").map((x) => parseInt(x))
+
+ const destinationIndexPaths = destinationPath
+ .split("/")
+ .map((x) => parseInt(x))
+
+ if (indexPaths.length === 0 || destinationIndexPaths.length === 0) {
+ console.error(
+ `Given path is too short. Skipping request to move folder '${path}' to destination '${destinationPath}'.`
+ )
+ return {}
+ }
+
+ const target = navigateToFolderWithIndexPath(
+ newState,
+ destinationIndexPaths
+ )
+ if (target === null) {
+ console.error(
+ `Could not resolve destination path '${destinationPath}'. Skipping moveFolder dispatch.`
+ )
+ return {}
+ }
+
+ const folderIndex = indexPaths.pop() as number
+
+ const containingFolder = navigateToFolderWithIndexPath(newState, indexPaths)
+ // We are moving a folder from the root
+ if (containingFolder === null) {
+ const theFolder = newState.splice(folderIndex, 1)
+
+ target.folders.push(theFolder[0])
+ } else {
+ const theFolder = containingFolder.folders.splice(folderIndex, 1)
+
+ target.folders.push(theFolder[0])
+ }
+
+ return { state: newState }
+ },
+
+ updateCollectionOrder(
+ { state }: RESTCollectionStoreType,
+ {
+ collectionIndex,
+ destinationCollectionIndex,
+ }: {
+ collectionIndex: string
+ destinationCollectionIndex: string
+ }
+ ) {
+ const newState = state
+
+ const indexPaths = collectionIndex.split("/").map((x) => parseInt(x))
+
+ const destinationIndexPaths = destinationCollectionIndex
+ .split("/")
+ .map((x) => parseInt(x))
+
+ if (indexPaths.length === 0 || destinationIndexPaths.length === 0) {
+ console.log("Given path too short. Skipping request.")
+ return {}
+ }
+
+ const folderIndex = indexPaths.pop() as number
+ const destinationFolderIndex = destinationIndexPaths.pop() as number
+
+ const containingFolder = navigateToFolderWithIndexPath(
+ newState,
+ destinationIndexPaths
+ )
+
+ if (containingFolder === null) {
+ const [removed] = newState.splice(folderIndex, 1)
+
+ newState.splice(destinationFolderIndex, 0, removed)
+
+ return {
+ state: newState,
+ }
+ }
+
+ const [removed] = containingFolder.folders.splice(folderIndex, 1)
+
+ containingFolder.folders.splice(destinationFolderIndex, 0, removed)
+
+ return {
+ state: newState,
+ }
+ },
+
editRequest(
{ state }: RESTCollectionStoreType,
{
@@ -286,6 +413,11 @@ const restCollectionDispatchers = defineDispatchers({
const indexPaths = path.split("/").map((x) => parseInt(x))
+ if (indexPaths.length === 0) {
+ console.log("Given path too short. Skipping request.")
+ return {}
+ }
+
const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
if (targetLocation === null) {
@@ -315,6 +447,47 @@ const restCollectionDispatchers = defineDispatchers({
state: newState,
}
},
+
+ updateRequestOrder(
+ { state }: RESTCollectionStoreType,
+ {
+ requestIndex,
+ destinationRequestIndex,
+ destinationCollectionPath,
+ }: {
+ requestIndex: number
+ destinationRequestIndex: number
+ destinationCollectionPath: string
+ }
+ ) {
+ const newState = state
+
+ const indexPaths = destinationCollectionPath
+ .split("/")
+ .map((x) => parseInt(x))
+
+ if (indexPaths.length === 0) {
+ console.log("Given path too short. Skipping request.")
+ return {}
+ }
+
+ const targetLocation = navigateToFolderWithIndexPath(newState, indexPaths)
+
+ if (targetLocation === null) {
+ console.log(
+ `Could not resolve path '${destinationCollectionPath}'. Ignoring reorderRequest dispatch.`
+ )
+ return {}
+ }
+
+ const [removed] = targetLocation.requests.splice(requestIndex, 1)
+
+ targetLocation.requests.splice(destinationRequestIndex, 0, removed)
+
+ return {
+ state: newState,
+ }
+ },
})
const gqlCollectionDispatchers = defineDispatchers({
@@ -691,6 +864,16 @@ export function removeRESTFolder(path: string) {
})
}
+export function moveRESTFolder(path: string, destinationPath: string | null) {
+ restCollectionStore.dispatch({
+ dispatcher: "moveFolder",
+ payload: {
+ path,
+ destinationPath,
+ },
+ })
+}
+
export function editRESTRequest(
path: string,
requestIndex: number,
@@ -757,6 +940,34 @@ export function moveRESTRequest(
})
}
+export function updateRESTRequestOrder(
+ requestIndex: number,
+ destinationRequestIndex: number,
+ destinationCollectionPath: string
+) {
+ restCollectionStore.dispatch({
+ dispatcher: "updateRequestOrder",
+ payload: {
+ requestIndex,
+ destinationRequestIndex,
+ destinationCollectionPath,
+ },
+ })
+}
+
+export function updateRESTCollectionOrder(
+ collectionIndex: string,
+ destinationCollectionIndex: string
+) {
+ restCollectionStore.dispatch({
+ dispatcher: "updateCollectionOrder",
+ payload: {
+ collectionIndex,
+ destinationCollectionIndex,
+ },
+ })
+}
+
export function setGraphqlCollections(
entries: HoppCollection[]
) {
diff --git a/packages/hoppscotch-common/src/newstore/workspace.ts b/packages/hoppscotch-common/src/newstore/workspace.ts
new file mode 100644
index 000000000..944b3d843
--- /dev/null
+++ b/packages/hoppscotch-common/src/newstore/workspace.ts
@@ -0,0 +1,67 @@
+import { distinctUntilChanged, pluck } from "rxjs"
+import DispatchingStore, { defineDispatchers } from "./DispatchingStore"
+
+type Workspace =
+ | { type: "personal" }
+ | { type: "team"; teamID: string; teamName: string }
+
+type WorkspaceState = {
+ workspace: Workspace
+}
+
+const initialState: WorkspaceState = {
+ workspace: {
+ type: "personal",
+ },
+}
+
+const dispatchers = defineDispatchers({
+ changeWorkspace(_, { workspace }: { workspace: Workspace }) {
+ return {
+ workspace,
+ }
+ },
+ updateWorkspaceTeamName(
+ _,
+ { workspace, newTeamName }: { workspace: Workspace; newTeamName: string }
+ ) {
+ if (workspace.type === "team") {
+ return {
+ workspace: {
+ ...workspace,
+ teamName: newTeamName,
+ },
+ }
+ }
+ return {
+ workspace,
+ }
+ },
+})
+
+export const hoppWorkspaceStore = new DispatchingStore(
+ initialState,
+ dispatchers
+)
+
+export const workspaceStatus$ = hoppWorkspaceStore.subject$.pipe(
+ pluck("workspace"),
+ distinctUntilChanged()
+)
+
+export function changeWorkspace(workspace: Workspace) {
+ hoppWorkspaceStore.dispatch({
+ dispatcher: "changeWorkspace",
+ payload: { workspace },
+ })
+}
+
+export function updateWorkspaceTeamName(
+ workspace: Workspace,
+ newTeamName: string
+) {
+ hoppWorkspaceStore.dispatch({
+ dispatcher: "updateWorkspaceTeamName",
+ payload: { workspace, newTeamName },
+ })
+}
diff --git a/packages/hoppscotch-common/src/pages/join-team.vue b/packages/hoppscotch-common/src/pages/join-team.vue
index 7ff7ba577..0a5d3f48e 100644
--- a/packages/hoppscotch-common/src/pages/join-team.vue
+++ b/packages/hoppscotch-common/src/pages/join-team.vue
@@ -4,7 +4,7 @@
v-if="invalidLink"
class="flex flex-col items-center justify-center flex-1"
>
- error_outline
+
{{ t("team.invalid_invite_link") }}
@@ -42,7 +42,7 @@
v-if="!inviteDetails.loading && E.isLeft(inviteDetails.data)"
class="flex flex-col items-center p-4"
>
- error_outline
+
{{ getErrorMessage(inviteDetails.data.left) }}
diff --git a/packages/hoppscotch-common/src/pages/r/_id.vue b/packages/hoppscotch-common/src/pages/r/_id.vue
index 89710cf9f..d1faa769f 100644
--- a/packages/hoppscotch-common/src/pages/r/_id.vue
+++ b/packages/hoppscotch-common/src/pages/r/_id.vue
@@ -4,7 +4,7 @@
v-if="invalidLink"
class="flex flex-col items-center justify-center flex-1"
>
- error_outline
+
{{ t("error.invalid_link") }}
@@ -24,7 +24,7 @@
v-if="!shortcodeDetails.loading && E.isLeft(shortcodeDetails.data)"
class="flex flex-col items-center p-4"
>
- error_outline
+
{{ t("error.invalid_link") }}
diff --git a/packages/hoppscotch-common/src/platform/environments.ts b/packages/hoppscotch-common/src/platform/environments.ts
new file mode 100644
index 000000000..6ba4f0f2c
--- /dev/null
+++ b/packages/hoppscotch-common/src/platform/environments.ts
@@ -0,0 +1,3 @@
+export type EnvironmentsPlatformDef = {
+ initEnvironmentsSync: () => void
+}
diff --git a/packages/hoppscotch-common/src/platform/index.ts b/packages/hoppscotch-common/src/platform/index.ts
index 94e9a2734..5a0203dc7 100644
--- a/packages/hoppscotch-common/src/platform/index.ts
+++ b/packages/hoppscotch-common/src/platform/index.ts
@@ -1,9 +1,13 @@
import { AuthPlatformDef } from "./auth"
import { UIPlatformDef } from "./ui"
+import { EnvironmentsPlatformDef } from "./environments"
export type PlatformDef = {
ui?: UIPlatformDef
auth: AuthPlatformDef
+ sync: {
+ environments: EnvironmentsPlatformDef
+ }
}
export let platform: PlatformDef
diff --git a/packages/hoppscotch-ui/src/components/button/Primary.vue b/packages/hoppscotch-ui/src/components/button/Primary.vue
index 89656dace..f4513d7b7 100644
--- a/packages/hoppscotch-ui/src/components/button/Primary.vue
+++ b/packages/hoppscotch-ui/src/components/button/Primary.vue
@@ -19,14 +19,27 @@
'border border-accent hover:border-accentDark focus-visible:border-accentDark':
outline,
},
- ]" :disabled="disabled" :tabindex="loading ? '-1' : '0'" role="button">
-
-
- {{ label }}
+ ]"
+ :disabled="disabled"
+ :tabindex="loading ? '-1' : '0'"
+ role="button"
+ >
+
+
+
+ {{ label }}
+
diff --git a/packages/hoppscotch-ui/src/components/button/Secondary.vue b/packages/hoppscotch-ui/src/components/button/Secondary.vue
index 5151424f2..9b3b0782e 100644
--- a/packages/hoppscotch-ui/src/components/button/Secondary.vue
+++ b/packages/hoppscotch-ui/src/components/button/Secondary.vue
@@ -19,14 +19,28 @@
'bg-primaryLight hover:bg-primaryDark focus-visible:bg-primaryDark':
filled,
},
- ]" :disabled="disabled" :tabindex="loading ? '-1' : '0'" role="button">
-
-
- {{ label }}
+ ]"
+ :disabled="disabled"
+ :tabindex="loading ? '-1' : '0'"
+ role="button"
+ >
+
+
+
+ {{ label }}
+
{{ key }}
diff --git a/packages/hoppscotch-ui/src/components/smart/FileChip.vue b/packages/hoppscotch-ui/src/components/smart/FileChip.vue
index 34b508d8f..9ad855a6e 100644
--- a/packages/hoppscotch-ui/src/components/smart/FileChip.vue
+++ b/packages/hoppscotch-ui/src/components/smart/FileChip.vue
@@ -1,7 +1,7 @@
-
+
diff --git a/packages/hoppscotch-ui/src/components/smart/Item.vue b/packages/hoppscotch-ui/src/components/smart/Item.vue
index ddef4eb5a..c6a5866f5 100644
--- a/packages/hoppscotch-ui/src/components/smart/Item.vue
+++ b/packages/hoppscotch-ui/src/components/smart/Item.vue
@@ -19,15 +19,19 @@
-
+
{{ label }}
{{ description }}
-
+
{{ key }}
diff --git a/packages/hoppscotch-ui/vite.config.ts b/packages/hoppscotch-ui/vite.config.ts
index cd5a15099..86ff5fb15 100644
--- a/packages/hoppscotch-ui/vite.config.ts
+++ b/packages/hoppscotch-ui/vite.config.ts
@@ -4,6 +4,7 @@ import path from "path"
import Icons from "unplugin-icons/vite"
import { defineConfig } from "vite"
import WindiCSS from "vite-plugin-windicss"
+import { VitePluginFonts } from "vite-plugin-fonts"
export default defineConfig({
plugins: [
@@ -19,6 +20,15 @@ export default defineConfig({
Icons({
compiler: "vue3"
}),
+ VitePluginFonts({
+ google: {
+ families: [
+ "Inter:wght@400;500;600;700;800",
+ "Roboto+Mono:wght@400;500",
+ "Material+Icons",
+ ],
+ },
+ }),
], // to process SFC
build: {
sourcemap: true,
diff --git a/packages/hoppscotch-ui/windi.config.ts b/packages/hoppscotch-ui/windi.config.ts
index 8e391aecb..34716006a 100644
--- a/packages/hoppscotch-ui/windi.config.ts
+++ b/packages/hoppscotch-ui/windi.config.ts
@@ -20,6 +20,7 @@ export default defineConfig({
lowerSecondaryStickyFold: "var(--lower-secondary-sticky-fold)",
lowerTertiaryStickyFold: "var(--lower-tertiary-sticky-fold)",
sidebarPrimaryStickyFold: "var(--sidebar-primary-sticky-fold)",
+ sidebarSecondaryStickyFold: "var(--line-height-body)",
},
colors: {
primary: "var(--primary-color)",
diff --git a/packages/hoppscotch-common/src/helpers/fb/environments.ts b/packages/hoppscotch-web/src/environments.ts
similarity index 86%
rename from packages/hoppscotch-common/src/helpers/fb/environments.ts
rename to packages/hoppscotch-web/src/environments.ts
index be34b184a..823dd7b88 100644
--- a/packages/hoppscotch-common/src/helpers/fb/environments.ts
+++ b/packages/hoppscotch-web/src/environments.ts
@@ -6,14 +6,18 @@ import {
onSnapshot,
setDoc,
} from "firebase/firestore"
-import { platform } from "~/platform"
+import { def as platformAuth } from "./firebase/auth"
import {
environments$,
globalEnv$,
replaceEnvironments,
setGlobalEnvVariables,
-} from "~/newstore/environments"
-import { getSettingSubject, settingsStore } from "~/newstore/settings"
+} from "@hoppscotch/common/newstore/environments"
+import {
+ getSettingSubject,
+ settingsStore,
+} from "@hoppscotch/common/newstore/settings"
+import { EnvironmentsPlatformDef } from "@hoppscotch/common/platform/environments"
/**
* Used locally to prevent infinite loop when environment sync update
@@ -32,7 +36,7 @@ let loadedEnvironments = false
let loadedGlobals = true
async function writeEnvironments(environment: Environment[]) {
- const currentUser = platform.auth.getCurrentUser()
+ const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("Cannot write environments when signed out")
@@ -57,7 +61,7 @@ async function writeEnvironments(environment: Environment[]) {
}
async function writeGlobalEnvironment(variables: Environment["variables"]) {
- const currentUser = platform.auth.getCurrentUser()
+ const currentUser = platformAuth.getCurrentUser()
if (currentUser === null)
throw new Error("Cannot write global environment when signed out")
@@ -81,11 +85,11 @@ async function writeGlobalEnvironment(variables: Environment["variables"]) {
}
}
-export function initEnvironments() {
- const currentUser$ = platform.auth.getCurrentUserStream()
+export function initEnvironmentsSync() {
+ const currentUser$ = platformAuth.getCurrentUserStream()
const envListenSub = environments$.subscribe((envs) => {
- const currentUser = platform.auth.getCurrentUser()
+ const currentUser = platformAuth.getCurrentUser()
if (
currentUser &&
@@ -97,7 +101,7 @@ export function initEnvironments() {
})
const globalListenSub = globalEnv$.subscribe((vars) => {
- const currentUser = platform.auth.getCurrentUser()
+ const currentUser = platformAuth.getCurrentUser()
if (currentUser && settingsStore.value.syncEnvironments && loadedGlobals) {
writeGlobalEnvironment(vars)
@@ -171,8 +175,12 @@ export function initEnvironments() {
globalListenSub.unsubscribe()
currentUserSub.unsubscribe()
- initEnvironments()
+ initEnvironmentsSync()
}
}
)
}
+
+export const def: EnvironmentsPlatformDef = {
+ initEnvironmentsSync,
+}
diff --git a/packages/hoppscotch-web/src/main.ts b/packages/hoppscotch-web/src/main.ts
index 9114700af..5945e25ac 100644
--- a/packages/hoppscotch-web/src/main.ts
+++ b/packages/hoppscotch-web/src/main.ts
@@ -1,6 +1,10 @@
import { createHoppApp } from "@hoppscotch/common"
import { def as authDef } from "./firebase/auth"
+import { def as envDef } from "./environments"
createHoppApp("#app", {
auth: authDef,
+ sync: {
+ environments: envDef,
+ },
})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fa96a2d8b..2d3c49646 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -58,6 +58,7 @@ importers:
'@relmify/jest-fp-ts': ^2.0.2
'@types/argon2': ^0.15.0
'@types/bcrypt': ^5.0.0
+ '@types/cookie': ^0.5.1
'@types/cookie-parser': ^1.4.3
'@types/express': ^4.17.14
'@types/jest': ^29.4.0
@@ -74,6 +75,7 @@ importers:
apollo-server-plugin-base: ^3.7.1
argon2: ^0.30.3
bcrypt: ^5.1.0
+ cookie: ^0.5.0
cookie-parser: ^1.4.6
eslint: ^8.29.0
eslint-config-prettier: ^8.5.0
@@ -122,6 +124,7 @@ importers:
apollo-server-plugin-base: 3.7.1_graphql@15.8.0
argon2: 0.30.3
bcrypt: 5.1.0
+ cookie: 0.5.0
cookie-parser: 1.4.6
express: 4.18.2
fp-ts: 2.13.1
@@ -150,6 +153,7 @@ importers:
'@relmify/jest-fp-ts': 2.0.2_fp-ts@2.13.1+io-ts@2.2.16
'@types/argon2': 0.15.0
'@types/bcrypt': 5.0.0
+ '@types/cookie': 0.5.1
'@types/cookie-parser': 1.4.3
'@types/express': 4.17.14
'@types/jest': 29.4.0
@@ -4670,12 +4674,12 @@ packages:
extract-files: 11.0.0
graphql: 15.8.0
graphql-ws: 5.9.1_graphql@15.8.0
- isomorphic-ws: 5.0.0_ws@8.12.0
+ isomorphic-ws: 5.0.0_ws@8.12.1
meros: 1.2.0
sync-fetch: 0.4.1
tslib: 2.4.0
value-or-promise: 1.0.11
- ws: 8.12.0
+ ws: 8.12.1
transitivePeerDependencies:
- '@types/node'
- bufferutil
@@ -4697,10 +4701,10 @@ packages:
'@types/ws': 8.5.3
'@whatwg-node/fetch': 0.8.1
graphql: 16.6.0
- isomorphic-ws: 5.0.0_ws@8.12.0
+ isomorphic-ws: 5.0.0_ws@8.12.1
tslib: 2.5.0
value-or-promise: 1.0.11
- ws: 8.12.0
+ ws: 8.12.1
transitivePeerDependencies:
- '@types/node'
- bufferutil
@@ -5113,7 +5117,7 @@ packages:
debug: 4.3.4
fast-glob: 3.2.11
source-map: 0.6.1
- vite: 3.2.4_sass@1.53.0
+ vite: 3.2.4
transitivePeerDependencies:
- supports-color
dev: true
@@ -6712,6 +6716,10 @@ packages:
'@types/express': 4.17.14
dev: true
+ /@types/cookie/0.5.1:
+ resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
+ dev: true
+
/@types/cookiejar/2.1.2:
resolution: {integrity: sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==}
dev: true
@@ -7824,7 +7832,7 @@ packages:
magic-string: 0.26.7
regenerator-runtime: 0.13.10
systemjs: 6.13.0
- vite: 3.2.4_sass@1.53.0
+ vite: 3.2.4
/@vitejs/plugin-vue/1.10.2_vite@2.9.15:
resolution: {integrity: sha512-/QJ0Z9qfhAFtKRY+r57ziY4BSbGUTGsPRMpB/Ron3QPwBZM4OZAZHdTa4a8PafCwU5DTatXG8TMDoP8z+oDqJw==}
@@ -7853,7 +7861,7 @@ packages:
vite: ^3.0.0
vue: ^3.2.25
dependencies:
- vite: 3.2.4_sass@1.53.0
+ vite: 3.2.4
vue: 3.2.45
dev: true
@@ -8673,7 +8681,7 @@ packages:
hasBin: true
/after/0.8.2:
- resolution: {integrity: sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==}
+ resolution: {integrity: sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=}
dev: false
/agent-base/6.0.2:
@@ -9280,7 +9288,7 @@ packages:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
/base64-arraybuffer/0.1.4:
- resolution: {integrity: sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==}
+ resolution: {integrity: sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=}
engines: {node: '>= 0.6.0'}
dev: false
@@ -9836,14 +9844,14 @@ packages:
dev: true
/component-bind/1.0.0:
- resolution: {integrity: sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==}
+ resolution: {integrity: sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=}
dev: false
/component-emitter/1.3.0:
resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==}
/component-inherit/0.0.3:
- resolution: {integrity: sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==}
+ resolution: {integrity: sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=}
dev: false
/concat-map/0.0.1:
@@ -12876,7 +12884,7 @@ packages:
dev: false
/has-cors/1.1.0:
- resolution: {integrity: sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==}
+ resolution: {integrity: sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=}
dev: false
/has-flag/3.0.0:
@@ -13222,7 +13230,7 @@ packages:
engines: {node: '>=8'}
/indexof/0.0.1:
- resolution: {integrity: sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==}
+ resolution: {integrity: sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=}
dev: false
/inflight/1.0.6:
@@ -13642,20 +13650,12 @@ packages:
- encoding
dev: true
- /isomorphic-ws/5.0.0_ws@8.12.0:
- resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
- peerDependencies:
- ws: '*'
- dependencies:
- ws: 8.12.0
-
/isomorphic-ws/5.0.0_ws@8.12.1:
resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
peerDependencies:
ws: '*'
dependencies:
ws: 8.12.1
- dev: true
/istanbul-lib-coverage/3.2.0:
resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==}
@@ -14829,7 +14829,7 @@ packages:
whatwg-encoding: 2.0.0
whatwg-mimetype: 3.0.0
whatwg-url: 11.0.0
- ws: 8.11.0
+ ws: 8.12.1
xml-name-validator: 4.0.0
transitivePeerDependencies:
- bufferutil
@@ -18110,7 +18110,7 @@ packages:
dev: true
/to-array/0.1.4:
- resolution: {integrity: sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==}
+ resolution: {integrity: sha1-F+bBH3PdTz10zaek/zI46a2b+JA=}
dev: false
/to-fast-properties/2.0.0:
@@ -19039,7 +19039,7 @@ packages:
dependencies:
acorn: 8.8.0
chokidar: 3.5.3
- vite: 3.2.4_sass@1.53.0
+ vite: 3.2.4
webpack-sources: 3.2.3
webpack-virtual-modules: 0.4.4
dev: true
@@ -19417,7 +19417,7 @@ packages:
vite: ^2.0.0 || ^3.0.0
dependencies:
fast-glob: 3.2.11
- vite: 3.2.4_sass@1.53.0
+ vite: 3.2.4
dev: true
/vite-plugin-html-config/1.0.10_vite@3.1.4:
@@ -19435,7 +19435,7 @@ packages:
peerDependencies:
vite: '>=2.0.0'
dependencies:
- vite: 3.2.4_sass@1.53.0
+ vite: 3.2.4
dev: true
/vite-plugin-inspect/0.7.4_vite@3.1.4:
@@ -19467,7 +19467,7 @@ packages:
kolorist: 1.5.1
sirv: 2.0.2
ufo: 0.8.5
- vite: 3.2.4_sass@1.53.0
+ vite: 3.2.4
transitivePeerDependencies:
- supports-color
dev: true
@@ -19741,7 +19741,7 @@ packages:
'@windicss/plugin-utils': 1.8.8
debug: 4.3.4
kolorist: 1.5.1
- vite: 3.2.4_sass@1.53.0
+ vite: 3.2.4
windicss: 3.5.6
transitivePeerDependencies:
- supports-color
@@ -19829,7 +19829,6 @@ 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==}
@@ -20789,18 +20788,7 @@ packages:
optional: true
utf-8-validate:
optional: true
-
- /ws/8.12.0:
- resolution: {integrity: sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==}
- engines: {node: '>=10.0.0'}
- peerDependencies:
- bufferutil: ^4.0.1
- utf-8-validate: '>=5.0.2'
- peerDependenciesMeta:
- bufferutil:
- optional: true
- utf-8-validate:
- optional: true
+ dev: false
/ws/8.12.1:
resolution: {integrity: sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==}
@@ -20995,7 +20983,7 @@ packages:
dev: false
/yeast/0.1.2:
- resolution: {integrity: sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==}
+ resolution: {integrity: sha1-AI4G2AlDIMNy28L47XagymyKxBk=}
dev: false
/yn/3.1.1: