diff --git a/packages/hoppscotch-common/locales/en.json b/packages/hoppscotch-common/locales/en.json index 378cbf67f..29fce808d 100644 --- a/packages/hoppscotch-common/locales/en.json +++ b/packages/hoppscotch-common/locales/en.json @@ -11,6 +11,7 @@ "connect": "Connect", "connecting": "Connecting", "copy": "Copy", + "create": "Create", "delete": "Delete", "disconnect": "Disconnect", "dismiss": "Dismiss", @@ -40,6 +41,7 @@ "scroll_to_top": "Scroll to top", "search": "Search", "send": "Send", + "share": "Share", "start": "Start", "starting": "Starting", "stop": "Stop", @@ -188,6 +190,7 @@ "remove_folder": "Are you sure you want to permanently delete this folder?", "remove_history": "Are you sure you want to permanently delete all history?", "remove_request": "Are you sure you want to permanently delete this request?", + "remove_shared_request": "Are you sure you want to permanently delete this shared request?", "remove_team": "Are you sure you want to delete this team?", "remove_telemetry": "Are you sure you want to opt-out of Telemetry?", "request_change": "Are you sure you want to discard current request, unsaved changes will be lost.", @@ -229,7 +232,8 @@ "profile": "Login to view your profile", "protocols": "Protocols are empty", "schema": "Connect to a GraphQL endpoint to view schema", - "shortcodes": "Shortcodes are empty", + "shared_requests_logout": "Login to view your shared requests or create a new one", + "shared_requests": "Shared requests are empty", "subscription": "Subscriptions are empty", "team_name": "Team name empty", "teams": "You don't belong to any teams", @@ -416,6 +420,7 @@ "collections": "Collections", "confirm": "Confirm", "edit_request": "Edit Request", + "share_request":"Share Request", "import_export": "Import / Export" }, "mqtt": { @@ -491,7 +496,6 @@ "structured": "Structured", "text": "Text" }, - "copy_link": "Copy link", "different_collection": "Cannot reorder requests from different collections", "duplicated": "Request duplicated", "duration": "Duration", @@ -524,6 +528,7 @@ "saved": "Request saved", "share": "Share", "share_description": "Share Hoppscotch with your friends", + "share_request": "Share Request", "stop": "Stop", "title": "Request", "type": "Request type", @@ -604,14 +609,30 @@ "additional": "Additional Settings", "verify_email": "Verify email" }, - "shortcodes": { - "actions": "Actions", - "created_on": "Created on", - "deleted": "Shortcode deleted", - "method": "Method", - "not_found": "Shortcode not found", - "short_code": "Short code", - "url": "URL" + "shared_requests":{ + "button":"Button", + "button_info": "Create a 'Run in Hoppscotch' button for your website, blog or a README.", + "customize": "Customize", + "creating_widget": "Creating widget", + "copy_html": "Copy HTML", + "copy_link": "Copy Link", + "copy_markdown": "Copy Markdown", + "deleted":"Shared request deleted", + "description": "Select a widget, you can change and customize this later", + "embed":"Embed", + "embed_info": "Add a mini 'Hoppscotch API Playground' to your website, blog or documentation.", + "link":"Link", + "link_info": "Create a shareable link to share with anyone on the internet with view access.", + "not_found":"Shared request not found", + "open_new_tab": "Open in new tab", + "preview":"Preview", + "run_in_hoppscotch":"Run in Hoppscotch", + "theme":{ + "dark":"Dark", + "light":"Light", + "system" :"System", + "title":"Theme" + } }, "shortcut": { "general": { @@ -641,7 +662,6 @@ "title": "Others" }, "request": { - "copy_request_link": "Copy Request Link", "delete_method": "Select DELETE method", "get_method": "Select GET method", "head_method": "Select HEAD method", @@ -657,6 +677,7 @@ "save_to_collections": "Save to Collections", "send_request": "Send Request", "show_code": "Generate code snippet", + "share_request":"Share Request", "title": "Request" }, "response": { @@ -840,6 +861,7 @@ "queries": "Queries", "query": "Query", "schema": "Schema", + "shared_requests": "Shared Requests", "socketio": "Socket.IO", "sse": "SSE", "tests": "Tests", diff --git a/packages/hoppscotch-common/src/components.d.ts b/packages/hoppscotch-common/src/components.d.ts index 9f670f06f..1b7bbd4a0 100644 --- a/packages/hoppscotch-common/src/components.d.ts +++ b/packages/hoppscotch-common/src/components.d.ts @@ -185,6 +185,16 @@ declare module 'vue' { RealtimeSubscription: typeof import('./components/realtime/Subscription.vue')['default'] SettingsExtension: typeof import('./components/settings/Extension.vue')['default'] SettingsProxy: typeof import('./components/settings/Proxy.vue')['default'] + Share: typeof import('./components/share/index.vue')['default'] + ShareCreateModal: typeof import('./components/share/CreateModal.vue')['default'] + ShareCustomizeModal: typeof import('./components/share/CustomizeModal.vue')['default'] + ShareModal: typeof import('./components/share/Modal.vue')['default'] + ShareRequest: typeof import('./components/share/Request.vue')['default'] + ShareRequestModal: typeof import('./components/share/RequestModal.vue')['default'] + ShareShareRequestModal: typeof import('./components/share/ShareRequestModal.vue')['default'] + ShareTemplatesButton: typeof import('./components/share/templates/Button.vue')['default'] + ShareTemplatesEmbeds: typeof import('./components/share/templates/Embeds.vue')['default'] + ShareTemplatesLink: typeof import('./components/share/templates/Link.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'] diff --git a/packages/hoppscotch-common/src/components/collections/MyCollections.vue b/packages/hoppscotch-common/src/components/collections/MyCollections.vue index a493a5c49..07a58eb82 100644 --- a/packages/hoppscotch-common/src/components/collections/MyCollections.vue +++ b/packages/hoppscotch-common/src/components/collections/MyCollections.vue @@ -222,6 +222,12 @@ requestIndex: pathToIndex(node.id), }) " + @share-request=" + node.data.type === 'requests' && + emit('share-request', { + request: node.data.data.data, + }) + " @drag-request=" dragRequest($event, { folderPath: node.data.data.parentIndex, @@ -460,6 +466,12 @@ const emit = defineEmits<{ isActive: boolean } ): void + ( + event: "share-request", + payload: { + request: HoppRESTRequest + } + ): void ( event: "drop-request", payload: { diff --git a/packages/hoppscotch-common/src/components/collections/Request.vue b/packages/hoppscotch-common/src/components/collections/Request.vue index b0b4878dd..d5de9831d 100644 --- a/packages/hoppscotch-common/src/components/collections/Request.vue +++ b/packages/hoppscotch-common/src/components/collections/Request.vue @@ -94,6 +94,7 @@ @keyup.e="edit?.$el.click()" @keyup.d="duplicate?.$el.click()" @keyup.delete="deleteAction?.$el.click()" + @keyup.s="shareAction?.$el.click()" @keyup.escape="hide()" > + @@ -162,6 +175,7 @@ import IconEdit from "~icons/lucide/edit" import IconCopy from "~icons/lucide/copy" import IconTrash2 from "~icons/lucide/trash-2" import IconRotateCCW from "~icons/lucide/rotate-ccw" +import IconShare2 from "~icons/lucide/share-2" import { ref, PropType, watch, computed } from "vue" import { HoppRESTRequest } from "@hoppscotch/data" import { useI18n } from "@composables/i18n" @@ -240,6 +254,7 @@ const emit = defineEmits<{ (event: "duplicate-request"): void (event: "remove-request"): void (event: "select-request"): void + (event: "share-request"): void (event: "drag-request", payload: DataTransfer): void (event: "update-request-order", payload: DataTransfer): void (event: "update-last-request-order", payload: DataTransfer): void @@ -250,6 +265,7 @@ const edit = ref(null) const deleteAction = ref(null) const options = ref(null) const duplicate = ref(null) +const shareAction = ref(null) const dragging = ref(false) const ordering = ref(false) diff --git a/packages/hoppscotch-common/src/components/collections/TeamCollections.vue b/packages/hoppscotch-common/src/components/collections/TeamCollections.vue index a6692264e..592c147fb 100644 --- a/packages/hoppscotch-common/src/components/collections/TeamCollections.vue +++ b/packages/hoppscotch-common/src/components/collections/TeamCollections.vue @@ -240,6 +240,12 @@ requestIndex: node.data.data.data.id, }) " + @share-request=" + node.data.type === 'requests' && + emit('share-request', { + request: node.data.data.data.request, + }) + " @drag-request=" dragRequest($event, { folderPath: node.data.data.parentIndex, @@ -473,6 +479,12 @@ const emit = defineEmits<{ folderPath?: string | undefined } ): void + ( + event: "share-request", + payload: { + request: HoppRESTRequest + } + ): void ( event: "drop-request", payload: { diff --git a/packages/hoppscotch-common/src/components/collections/index.vue b/packages/hoppscotch-common/src/components/collections/index.vue index 64cfe2051..b4a15ec5c 100644 --- a/packages/hoppscotch-common/src/components/collections/index.vue +++ b/packages/hoppscotch-common/src/components/collections/index.vue @@ -41,6 +41,7 @@ @export-data="exportData" @remove-collection="removeCollection" @remove-folder="removeFolder" + @share-request="shareRequest" @drop-collection="dropCollection" @update-request-order="updateRequestOrder" @update-collection-order="updateCollectionOrder" @@ -71,6 +72,7 @@ @export-data="exportData" @remove-collection="removeCollection" @remove-folder="removeFolder" + @share-request="shareRequest" @edit-request="editRequest" @duplicate-request="duplicateRequest" @remove-request="removeRequest" @@ -229,7 +231,7 @@ import { resetTeamRequestsContext, } from "~/helpers/collection/collection" import { currentReorderingStatus$ } from "~/newstore/reordering" -import { defineActionHandler } from "~/helpers/actions" +import { defineActionHandler, invokeAction } from "~/helpers/actions" import { WorkspaceService } from "~/services/workspace.service" import { useService } from "dioc/vue" import { RESTTabService } from "~/services/tab/rest" @@ -2012,6 +2014,17 @@ const importToTeams = async (collection: HoppCollection[]) => { )() } +const shareRequest = ({ request }: { request: HoppRESTRequest }) => { + if (currentUser.value) { + // opens the share request modal + invokeAction("share.request", { + request, + }) + } else { + invokeAction("modals.login.toggle") + } +} + const resolveConfirmModal = (title: string | null) => { if (title === `${t("confirm.remove_collection")}`) onRemoveCollection() else if (title === `${t("confirm.remove_request")}`) onRemoveRequest() diff --git a/packages/hoppscotch-common/src/components/environments/Add.vue b/packages/hoppscotch-common/src/components/environments/Add.vue index 3c647eeeb..dad4148ff 100644 --- a/packages/hoppscotch-common/src/components/environments/Add.vue +++ b/packages/hoppscotch-common/src/components/environments/Add.vue @@ -42,7 +42,7 @@
@@ -55,7 +57,10 @@

@@ -95,9 +100,9 @@ const t = useI18n() const tabs = useService(RESTTabService) const invalidLink = ref(false) -const shortcodeID = ref("") +const sharedRequestID = ref("") -const shortcodeDetails = useGQLQuery< +const sharedRequestDetails = useGQLQuery< ResolveShortcodeQuery, ResolveShortcodeQueryVariables, "" @@ -109,14 +114,14 @@ const shortcodeDetails = useGQLQuery< }) watch( - () => shortcodeDetails.data, + () => sharedRequestDetails.data, () => addRequestToTab() ) const addRequestToTab = () => { - if (shortcodeDetails.loading) return + if (sharedRequestDetails.loading) return - const data = shortcodeDetails.data + const data = sharedRequestDetails.data if (E.isRight(data)) { if (!data.right.shortcode?.request) { @@ -145,9 +150,9 @@ const reloadApplication = () => { onMounted(() => { if (typeof route.params.id === "string") { - shortcodeID.value = route.params.id - shortcodeDetails.execute() + sharedRequestID.value = route.params.id + sharedRequestDetails.execute() } - invalidLink.value = !shortcodeID.value + invalidLink.value = !sharedRequestID.value }) diff --git a/packages/hoppscotch-common/src/services/spotlight/searchers/request.searcher.ts b/packages/hoppscotch-common/src/services/spotlight/searchers/request.searcher.ts index 1e4f1ebd3..f67a49202 100644 --- a/packages/hoppscotch-common/src/services/spotlight/searchers/request.searcher.ts +++ b/packages/hoppscotch-common/src/services/spotlight/searchers/request.searcher.ts @@ -12,7 +12,7 @@ import { RESTOptionTabs } from "~/components/http/RequestOptions.vue" import IconWindow from "~icons/lucide/app-window" import IconCheckCircle from "~icons/lucide/check-circle" import IconCode2 from "~icons/lucide/code-2" -import IconCopy from "~icons/lucide/copy" +import IconShare2 from "~icons/lucide/share-2" import IconFileCode from "~icons/lucide/file-code" import IconRename from "~icons/lucide/file-edit" import IconPlay from "~icons/lucide/play" @@ -94,10 +94,10 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ icon: markRaw(IconRename), excludeFromSearch: computed(() => !this.isRESTOrGQLPage.value), }, - copy_request_link: { - text: this.t("shortcut.request.copy_request_link"), - alternates: ["copy", "link"], - icon: markRaw(IconCopy), + share_request: { + text: this.t("shortcut.request.share_request"), + alternates: ["share", "request", "copy"], + icon: markRaw(IconShare2), excludeFromSearch: computed(() => !this.isRESTPage.value), }, reset_request: { @@ -277,8 +277,8 @@ export class RequestSpotlightSearcherService extends StaticSpotlightSearcherServ case "rename_request": invokeAction("request.rename") break - case "copy_request_link": - invokeAction("request.copy-link") + case "share_request": + invokeAction("request.share-request") break case "reset_request": invokeAction("request.reset") diff --git a/packages/hoppscotch-common/windi.config.ts b/packages/hoppscotch-common/windi.config.ts deleted file mode 100644 index cbedf96f1..000000000 --- a/packages/hoppscotch-common/windi.config.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { defineConfig } from "windicss/helpers" - -export default defineConfig({ - extract: { - include: ["src/**/*.{vue,html}", "../hoppscotch-ui/src/**/*.{vue,html}"], - }, - theme: { - container: { - center: true, - }, - extend: { - inset: { - upperPrimaryStickyFold: "var(--upper-primary-sticky-fold)", - upperSecondaryStickyFold: "var(--upper-secondary-sticky-fold)", - upperTertiaryStickyFold: "var(--upper-tertiary-sticky-fold)", - upperFourthStickyFold: "var(--upper-fourth-sticky-fold)", - upperMobilePrimaryStickyFold: "var(--upper-mobile-primary-sticky-fold)", - upperMobileSecondaryStickyFold: - "var(--upper-mobile-secondary-sticky-fold)", - upperMobileStickyFold: "var(--upper-mobile-sticky-fold)", - upperMobileTertiaryStickyFold: - "var(--upper-mobile-tertiary-sticky-fold)", - lowerPrimaryStickyFold: "var(--lower-primary-sticky-fold)", - lowerSecondaryStickyFold: "var(--lower-secondary-sticky-fold)", - lowerTertiaryStickyFold: "var(--lower-tertiary-sticky-fold)", - lowerFourthStickyFold: "var(--lower-fourth-sticky-fold)", - sidebarPrimaryStickyFold: "var(--sidebar-primary-sticky-fold)", - sidebarSecondaryStickyFold: "var(--line-height-body)", - }, - colors: { - primary: "var(--primary-color)", - primaryLight: "var(--primary-light-color)", - primaryDark: "var(--primary-dark-color)", - primaryContrast: "var(--primary-contrast-color)", - secondary: "var(--secondary-color)", - secondaryLight: "var(--secondary-light-color)", - secondaryDark: "var(--secondary-dark-color)", - accent: "var(--accent-color)", - accentLight: "var(--accent-light-color)", - accentDark: "var(--accent-dark-color)", - accentContrast: "var(--accent-contrast-color)", - divider: "var(--divider-color)", - dividerLight: "var(--divider-light-color)", - dividerDark: "var(--divider-dark-color)", - error: "var(--error-color)", - tooltip: "var(--tooltip-color)", - popover: "var(--popover-color)", - gradientFrom: "var(--gradient-from-color)", - gradientVia: "var(--gradient-via-color)", - gradientTo: "var(--gradient-to-color)", - }, - fontFamily: { - sans: "var(--font-sans)", - mono: "var(--font-mono)", - icon: "var(--font-icon)", - }, - fontSize: { - tiny: "var(--font-size-tiny)", - body: "var(--font-size-body)", - }, - lineHeight: { - body: "var(--line-height-body)", - }, - cursor: { - nsResize: "ns-resize", - grab: "grab", - grabbing: "grabbing", - }, - }, - }, -}) diff --git a/packages/hoppscotch-ui/src/components/smart/Checkbox.vue b/packages/hoppscotch-ui/src/components/smart/Checkbox.vue index 01c7a27a3..fe3c44e74 100644 --- a/packages/hoppscotch-ui/src/components/smart/Checkbox.vue +++ b/packages/hoppscotch-ui/src/components/smart/Checkbox.vue @@ -16,6 +16,9 @@ @@ -23,6 +26,8 @@