Skip to content

Commit ab52efc

Browse files
feat: improve documentation UI and add published docs indicators (hoppscotch#5620)
Co-authored-by: mirarifhasan <[email protected]>
1 parent 1e8edd2 commit ab52efc

File tree

19 files changed

+613
-195
lines changed

19 files changed

+613
-195
lines changed

packages/hoppscotch-backend/src/auth/auth.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ import { InfraConfigModule } from 'src/infra-config/infra-config.module';
3434
})
3535
export class AuthModule {
3636
static async register() {
37+
if (process.env.GENERATE_GQL_SCHEMA === 'true') {
38+
return { module: AuthModule };
39+
}
40+
3741
const isInfraConfigPopulated = await isInfraConfigTablePopulated();
3842
if (!isInfraConfigPopulated) {
3943
return { module: AuthModule };

packages/hoppscotch-backend/src/published-docs/published-docs.resolver.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,9 @@ export class PublishedDocsResolver {
119119
name: 'collectionID',
120120
type: () => ID,
121121
description: 'Id of the collection to add to',
122+
nullable: true,
122123
})
123-
collectionID: string,
124+
collectionID: string | undefined,
124125
@Args() args: OffsetPaginationArgs,
125126
) {
126127
const docs = await this.publishedDocsService.getAllTeamPublishedDocs(

packages/hoppscotch-backend/src/published-docs/published-docs.service.spec.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import {
2323
import { TeamAccessRole } from 'src/team/team.model';
2424
import { TreeLevel } from './published-docs.dto';
2525
import { ConfigService } from '@nestjs/config';
26-
import { right } from 'fp-ts/lib/EitherT';
2726

2827
const mockPrisma = mockDeep<PrismaService>();
2928
const mockUserCollectionService = mockDeep<UserCollectionService>();

packages/hoppscotch-backend/src/published-docs/published-docs.service.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import { OffsetPaginationArgs } from 'src/types/input-types.args';
2323
import { stringToJson } from 'src/utils';
2424
import { UserCollectionService } from 'src/user-collection/user-collection.service';
2525
import { TeamCollectionService } from 'src/team-collection/team-collection.service';
26-
import { CollectionFolder } from 'src/types/CollectionFolder';
2726
import { GetPublishedDocsQueryDto, TreeLevel } from './published-docs.dto';
2827
import { ConfigService } from '@nestjs/config';
2928

@@ -275,7 +274,7 @@ export class PublishedDocsService {
275274
*/
276275
async getAllTeamPublishedDocs(
277276
teamID: string,
278-
collectionID: string,
277+
collectionID: string | undefined,
279278
args: OffsetPaginationArgs,
280279
) {
281280
const docs = await this.prisma.publishedDocs.findMany({

packages/hoppscotch-backend/src/user-collection/user-collection.resolver.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
UserCollection,
1919
UserCollectionDuplicatedData,
2020
UserCollectionExportJSONData,
21-
UserCollectionImportResult,
2221
UserCollectionRemovedData,
2322
UserCollectionReorderData,
2423
} from './user-collections.model';

packages/hoppscotch-common/locales/en.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"more": "More",
4242
"new": "New",
4343
"no": "No",
44+
"open": "Open",
4445
"open_workspace": "Open workspace",
4546
"paste": "Paste",
4647
"prettify": "Prettify",
@@ -69,6 +70,7 @@
6970
"turn_off": "Turn off",
7071
"turn_on": "Turn on",
7172
"undo": "Undo",
73+
"unpublish": "Unpublish",
7274
"yes": "Yes",
7375
"verify": "Verify",
7476
"enable": "Enable",
@@ -504,13 +506,15 @@
504506
"auto_sync_description": "Automatically update published docs when collection changes",
505507
"button": "Publish",
506508
"copy_url": "Copy URL",
507-
"delete_published_doc": "Are you sure you want to delete the published documentation?",
509+
"delete": "Delete Documentation",
510+
"unpublish_doc": "Are you sure you want to unpublish the documentation?",
508511
"delete_success": "Published documentation deleted successfully",
509512
"doc_title": "Title",
510513
"doc_version": "Version",
511514
"edit_published_doc": "Edit Published Doc",
512515
"last_updated": "Last Updated",
513516
"metadata": "Metadata (JSON)",
517+
"open_published_doc": "Open Published Documentation in new tab",
514518
"publish_error": "Failed to publish documentation",
515519
"publish_success": "Documentation published successfully!",
516520
"published": "Published",
@@ -520,6 +524,7 @@
520524
"update_error": "Failed to update documentation",
521525
"update_published_docs": "Update Published Docs",
522526
"update_success": "Documentation updated successfully!",
527+
"unpublish": "Unpublish",
523528
"update_title": "Update Published Documentation",
524529
"url_copied": "URL copied to clipboard!",
525530
"view_published": "View Published Docs",

packages/hoppscotch-common/src/components/collections/Collection.vue

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,18 @@
7676
}"
7777
/>
7878
</span>
79+
<!-- Published Doc Status Indicator -->
80+
<span
81+
v-if="publishedDocStatus"
82+
v-tippy="{ theme: 'tooltip' }"
83+
:title="t('documentation.publish.published')"
84+
class="ml-2 flex items-center"
85+
>
86+
<component :is="IconGlobe" class="svg-icons text-green-500" />
87+
</span>
7988
</span>
8089
</div>
90+
8191
<div
8292
v-if="isCollectionLoading && !isOpen"
8393
class="flex items-center px-2"
@@ -179,6 +189,19 @@
179189
}
180190
"
181191
/>
192+
<HoppSmartItem
193+
v-if="isDocumentationVisible"
194+
ref="documentationAction"
195+
:icon="IconBook"
196+
:label="t('documentation.title')"
197+
:shortcut="['I']"
198+
@click="
199+
() => {
200+
handleDocumentationAction()
201+
hide()
202+
}
203+
"
204+
/>
182205
<HoppSmartItem
183206
v-if="
184207
!hasNoTeamAccess &&
@@ -250,19 +273,7 @@
250273
}
251274
"
252275
/>
253-
<HoppSmartItem
254-
v-if="isDocumentationVisible"
255-
ref="documentationAction"
256-
:icon="IconBook"
257-
:label="t('documentation.title')"
258-
:shortcut="['I']"
259-
@click="
260-
() => {
261-
handleDocumentationAction()
262-
hide()
263-
}
264-
"
265-
/>
276+
266277
<HoppSmartItem
267278
ref="propertiesAction"
268279
:icon="IconSettings2"
@@ -346,6 +357,8 @@ import { useMockServerStatus } from "~/composables/mockServer"
346357
import { useMockServerVisibility } from "~/composables/mockServerVisibility"
347358
import { platform } from "~/platform"
348359
import { invokeAction } from "~/helpers/actions"
360+
import { DocumentationService } from "~/services/documentation.service"
361+
import IconGlobe from "~icons/lucide/globe"
349362
350363
type CollectionType = "my-collections" | "team-collections"
351364
type FolderType = "collection" | "folder"
@@ -500,6 +513,19 @@ const mockServerStatus = computed(() => {
500513
return getMockServerStatus(collectionId || "")
501514
})
502515
516+
// Published Doc Status
517+
const documentationService = useService(DocumentationService)
518+
519+
const publishedDocStatus = computed(() => {
520+
const collectionId =
521+
props.collectionsType === "my-collections"
522+
? ((props.data as HoppCollection).id ??
523+
(props.data as HoppCollection)._ref_id)
524+
: (props.data as TeamCollection).id
525+
526+
return documentationService.getPublishedDocStatus(collectionId || "")
527+
})
528+
503529
// Determine if this is a root collection (not a child folder)
504530
const isRootCollection = computed(() => {
505531
return props.folderType === "collection"

packages/hoppscotch-common/src/components/collections/MyCollections.vue

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -875,18 +875,13 @@ const updateCollectionOrder = (
875875
}
876876
877877
const debouncedSorting = useDebounceFn(() => {
878-
sortCollection()
879-
}, 250)
880-
881-
const sortCollection = () => {
882878
currentSortOrder.value = currentSortOrder.value === "asc" ? "desc" : "asc"
883-
884879
emit("sort-collections", {
885880
collectionID: null,
886881
sortOrder: currentSortOrder.value,
887882
collectionRefID: "personal",
888883
})
889-
}
884+
}, 250)
890885
891886
type MyCollectionNode = Collection | Folder | Requests
892887

packages/hoppscotch-common/src/components/collections/documentation/MarkdownEditor.vue

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
<template>
2-
<div class="rounded-sm relative h-full" @click.stop>
2+
<div
3+
v-if="!(readOnly && isEmpty)"
4+
class="rounded-sm relative h-full"
5+
@click.stop
6+
>
37
<!-- Edit mode textarea -->
48
<template v-if="editMode && !readOnly">
59
<textarea
610
ref="textareaRef"
711
v-model="internalContent"
8-
class="text-wrap w-full p-4 rounded-sm text-sm font-mono text-secondaryLight outline-none resize-none focus:border focus:border-accent focus:bg-primaryLight transition"
12+
class="text-wrap w-full p-4 rounded-sm text-sm font-mono text-secondary outline-none resize-none focus:border focus:border-accent focus:bg-primaryLight transition placeholder:text-secondaryLight"
913
:style="{ height: textareaHeight + 'px' }"
1014
spellcheck="false"
1115
:placeholder="placeholder"
@@ -74,6 +78,11 @@ const textareaHeight = ref<number>(200)
7478
// Internal content that syncs with modelValue
7579
const internalContent = ref<string>(props.modelValue)
7680
81+
// Check if the content is empty
82+
const isEmpty = computed(
83+
() => !internalContent.value || internalContent.value.trim() === ""
84+
)
85+
7786
// Watch for external changes to modelValue
7887
watch(
7988
() => props.modelValue,
@@ -88,7 +97,7 @@ watch(
8897
// Render markdown content with DOMPurify sanitization
8998
const renderedMarkdown = computed(() => {
9099
try {
91-
if (!internalContent.value || internalContent.value.trim() === "") {
100+
if (isEmpty.value) {
92101
return DOMPurify.sanitize(
93102
`<p class='text-secondaryLight italic'>${props.placeholder || t("documentation.add_description_placeholder")}</p>`
94103
)
@@ -201,7 +210,7 @@ onMounted(() => {
201210
/* List styles */
202211
.markdown-content :deep(ul),
203212
.markdown-content :deep(ol) {
204-
@apply pl-6 my-3 text-sm text-secondaryLight space-y-1;
213+
@apply pl-6 my-3 text-sm text-secondary space-y-1;
205214
}
206215
207216
.markdown-content :deep(li > ul),
@@ -252,7 +261,7 @@ onMounted(() => {
252261
}
253262
254263
.markdown-content :deep(td) {
255-
@apply border border-divider px-3 py-1 text-secondaryLight;
264+
@apply border border-divider px-3 py-1 text-secondary;
256265
@apply bg-primaryDark;
257266
}
258267

packages/hoppscotch-common/src/components/collections/documentation/PublishDocModal.vue

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -70,21 +70,56 @@
7070
input-styles="floating-input"
7171
class="flex-1 opacity-80 cursor-not-allowed"
7272
/>
73-
<HoppButtonSecondary :icon="copyIcon" outline @click="copyUrl" />
73+
<HoppButtonSecondary
74+
v-if="publishedUrl"
75+
v-tippy="{ theme: 'tooltip' }"
76+
:title="t('documentation.publish.copy_url')"
77+
:icon="copyIcon"
78+
outline
79+
@click="copyUrl"
80+
/>
81+
<HoppButtonPrimary
82+
v-if="(mode === 'view' || mode === 'update') && publishedUrl"
83+
v-tippy="{ theme: 'tooltip' }"
84+
:title="t('documentation.publish.open_published_doc')"
85+
:label="t('action.open')"
86+
:icon="IconExternalLink"
87+
@click="viewPublished"
88+
/>
7489
</div>
7590
</div>
91+
</div>
92+
</template>
7693

77-
<div class="flex space-x-2">
94+
<template #footer>
95+
<div class="flex justify-between items-center flex-1">
96+
<div class="flex items-center w-full space-x-2">
7897
<HoppButtonPrimary
79-
v-if="mode === 'view' || mode === 'update'"
80-
:label="t('documentation.publish.view_published')"
81-
:icon="IconExternalLink"
82-
@click="viewPublished"
98+
v-if="mode === 'create' && !publishedUrl"
99+
:label="t('documentation.publish.button')"
100+
:disabled="!canPublish || loading"
101+
:loading="loading"
102+
@click="handlePublish"
103+
/>
104+
<HoppButtonPrimary
105+
v-else-if="mode === 'update'"
106+
:label="t('documentation.publish.update_button')"
107+
:disabled="!canPublish || loading || !hasChanges"
108+
:loading="loading"
109+
@click="handleUpdate"
83110
/>
111+
<HoppButtonSecondary
112+
:label="t('action.cancel')"
113+
outline
114+
filled
115+
@click="hideModal"
116+
/>
117+
</div>
118+
<div class="flex">
84119
<HoppButtonSecondary
85120
v-if="mode === 'update'"
86121
:icon="IconTrash2"
87-
label="Delete Documentation"
122+
:label="t('documentation.publish.unpublish')"
88123
class="!text-red-500"
89124
:loading="loading"
90125
:disabled="loading"
@@ -95,37 +130,12 @@
95130
</div>
96131
</div>
97132
</template>
98-
99-
<template #footer>
100-
<div class="flex justify-between items-center w-full">
101-
<HoppButtonSecondary
102-
:label="t('action.cancel')"
103-
outline
104-
filled
105-
@click="hideModal"
106-
/>
107-
<HoppButtonPrimary
108-
v-if="mode === 'create' && !publishedUrl"
109-
:label="t('documentation.publish.button')"
110-
:disabled="!canPublish || loading"
111-
:loading="loading"
112-
@click="handlePublish"
113-
/>
114-
<HoppButtonPrimary
115-
v-else-if="mode === 'update'"
116-
:label="t('documentation.publish.update_button')"
117-
:disabled="!canPublish || loading || !hasChanges"
118-
:loading="loading"
119-
@click="handleUpdate"
120-
/>
121-
</div>
122-
</template>
123133
</HoppSmartModal>
124134

125135
<HoppSmartConfirmModal
126136
:show="showDeleteConfirmModal"
127-
:title="t('documentation.publish.delete_published_doc')"
128-
:confirm="t('action.delete')"
137+
:title="t('documentation.publish.unpublish_doc')"
138+
:confirm="t('action.unpublish')"
129139
:loading-state="loading"
130140
@hide-modal="showDeleteConfirmModal = false"
131141
@resolve="confirmDelete"

0 commit comments

Comments
 (0)