Browse Source

fix(nc-gui): custom url support in shared base

Ramesh Mane 6 days ago
parent
commit
6b2c5a59e2
  1. 45
      packages/nc-gui/components/dlg/share-and-collaborate/ShareBase.vue
  2. 2
      packages/nc-gui/components/dlg/share-and-collaborate/SharePage.vue
  3. 2
      packages/nocodb/src/controllers/shared-bases.controller.ts
  4. 2
      packages/nocodb/src/models/Base.ts
  5. 3
      packages/nocodb/src/models/View.ts
  6. 18
      packages/nocodb/src/schema/swagger-v2.json
  7. 14
      packages/nocodb/src/schema/swagger.json
  8. 52
      packages/nocodb/src/services/shared-bases.service.ts

45
packages/nc-gui/components/dlg/share-and-collaborate/ShareBase.vue

@ -3,6 +3,7 @@ interface ShareBase {
uuid?: string
url?: string
role?: string
fk_custom_url_id?: string
}
enum ShareBaseRole {
@ -14,6 +15,8 @@ const { dashboardUrl } = useDashboard()
const { $api, $e } = useNuxtApp()
const { copy } = useCopy()
const sharedBase = ref<null | ShareBase>(null)
const { base } = storeToRefs(useBase())
@ -22,18 +25,21 @@ const { getBaseUrl, appInfo } = useGlobal()
const workspaceStore = useWorkspace()
const url = computed(() => {
if (!sharedBase.value || !sharedBase.value.uuid) return ''
const dashboardBaseUrl = computed(() => {
// get base url for workspace
const baseUrl = getBaseUrl(workspaceStore.activeWorkspaceId)
let dashboardUrl1 = dashboardUrl.value
if (baseUrl) {
dashboardUrl1 = `${baseUrl}${appInfo.value?.dashboardPath}`
return `${baseUrl}${appInfo.value?.dashboardPath}`
}
return encodeURI(`${dashboardUrl1}#/base/${sharedBase.value.uuid}`)
return dashboardUrl.value
})
const url = computed(() => {
if (!sharedBase.value || !sharedBase.value.uuid) return ''
return encodeURI(`${dashboardBaseUrl.value}#/base/${sharedBase.value.uuid}`)
})
const loadBase = async () => {
@ -46,24 +52,32 @@ const loadBase = async () => {
uuid: res.uuid,
url: res.url,
role: res.roles,
fk_custom_url_id: res?.fk_custom_url_id,
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
const createShareBase = async (role = ShareBaseRole.Viewer) => {
const createShareBase = async (role = ShareBaseRole.Viewer, custUrl = undefined) => {
try {
if (!base.value.id) return
const res = await $api.base.sharedBaseUpdate(base.value.id, {
roles: role,
original_url: url.value,
...(custUrl !== undefined ? { custom_url_path: custUrl ?? null } : {}),
})
sharedBase.value = res ?? {}
sharedBase.value!.role = role
base.value.uuid = res.uuid
if (custUrl !== undefined) {
sharedBase.value!.fk_custom_url_id = res.fk_custom_url_id
base.value.fk_custom_url_id = res.fk_custom_url_id
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
@ -126,6 +140,10 @@ const onRoleToggle = async () => {
isRoleToggleLoading.value = false
}
}
const copyCustomUrl = async (custUrl = '') => {
return await copy(`${dashboardBaseUrl.value}#/p/${encodeURIComponent(custUrl)}`)
}
</script>
<template>
@ -141,11 +159,18 @@ const onRoleToggle = async () => {
@click="toggleSharedBase"
/>
</div>
<div v-if="isSharedBaseEnabled" class="flex flex-col w-full mt-3 border-t-1 pt-3 border-gray-100">
<div v-if="isSharedBaseEnabled" class="flex flex-col gap-3 w-full mt-3 border-t-1 pt-3 border-gray-100">
<GeneralCopyUrl v-model:url="url" />
<DlgShareAndCollaborateCustomUrl
v-if="sharedBase?.uuid"
:id="sharedBase.fk_custom_url_id"
:dashboard-url="dashboardBaseUrl"
:copy-custom-url="copyCustomUrl"
@update-custom-url="createShareBase(undefined, $event)"
/>
<div
v-if="!appInfo.ee && sharedBase?.role === ShareBaseRole.Editor"
class="flex flex-row justify-between mt-3 bg-gray-50 px-3 py-2 rounded-md"
class="flex flex-row justify-between bg-gray-50 px-3 py-2 rounded-md"
>
<div class="text-black">{{ $t('activity.editingAccess') }}</div>
<a-switch

2
packages/nc-gui/components/dlg/share-and-collaborate/SharePage.vue

@ -358,7 +358,7 @@ const copyCustomUrl = async (custUrl = '') => {
:dashboard-url="dashboardBaseUrl"
:copy-custom-url="copyCustomUrl"
:search-query="preFillFormSearchParams && activeView?.type === ViewTypes.FORM ? `?${preFillFormSearchParams}` : ''"
@update-shared-view="updateSharedView"
@update-custom-url="updateSharedView"
/>
<div class="flex flex-col justify-between mt-1 py-2 px-3 bg-gray-50 rounded-md">
<div class="flex flex-row items-center justify-between">

2
packages/nocodb/src/controllers/shared-bases.controller.ts

@ -67,6 +67,8 @@ export class SharedBasesController {
password: body?.password,
siteUrl: req.ncSiteUrl,
req,
custom_url_path: body.custom_url_path,
original_url: body.original_url,
},
);

2
packages/nocodb/src/models/Base.ts

@ -38,6 +38,7 @@ export default class Base implements BaseType {
uuid?: string;
password?: string;
roles?: string;
fk_custom_url_id?: string;
constructor(base: Partial<Base>) {
Object.assign(this, base);
@ -344,6 +345,7 @@ export default class Base implements BaseType {
'uuid',
'password',
'roles',
'fk_custom_url_id',
]);
// get existing cache

3
packages/nocodb/src/models/View.ts

@ -102,7 +102,6 @@ export default class View implements ViewType {
show_system_fields?: boolean;
meta?: any;
fk_custom_url_id?: string;
custom_url_path?: string;
constructor(data: View) {
Object.assign(this, data);
@ -1247,6 +1246,7 @@ export default class View implements ViewType {
MetaTable.VIEWS,
{
uuid: null,
fk_custom_url_id: null,
},
viewId,
);
@ -1255,6 +1255,7 @@ export default class View implements ViewType {
await NocoCache.update(`${CacheScope.VIEW}:${viewId}`, {
uuid: null,
fk_custom_url_id: null,
});
}

18
packages/nocodb/src/schema/swagger-v2.json

@ -19240,6 +19240,10 @@
"description": "Base Title",
"example": "my-base",
"type": "string"
},
"fk_custom_url_id": {
"$ref": "#/components/schemas/StringOrNull",
"description": "ID of custom url"
}
},
"x-stoplight": {
@ -19695,6 +19699,14 @@
"type": "string",
"description": "The role given the target user",
"example": "editor"
},
"original_url": {
"$ref": "#/components/schemas/StringOrNull",
"description": "Original url user to redirect from custom url path"
},
"custom_url_path": {
"$ref": "#/components/schemas/StringOrNull",
"description": "Custom url path"
}
},
"x-stoplight": {
@ -19856,6 +19868,10 @@
"$ref": "#/components/schemas/StringOrNull",
"description": "Password to restrict access"
},
"original_url": {
"$ref": "#/components/schemas/StringOrNull",
"description": "Original url user to redirect from custom url path"
},
"custom_url_path": {
"$ref": "#/components/schemas/StringOrNull",
"description": "Custom url path"
@ -21217,7 +21233,7 @@
},
"fk_custom_url_id": {
"$ref": "#/components/schemas/StringOrNull",
"description": "Custom url id of view"
"description": "ID of custom url"
}
},
"required": [

14
packages/nocodb/src/schema/swagger.json

@ -24327,6 +24327,10 @@
"description": "Base Title",
"example": "my-base",
"type": "string"
},
"fk_custom_url_id": {
"$ref": "#/components/schemas/StringOrNull",
"description": "ID of custom url"
}
},
"x-stoplight": {
@ -24814,6 +24818,14 @@
"type": "string",
"description": "The role given the target user",
"example": "editor"
},
"original_url": {
"$ref": "#/components/schemas/StringOrNull",
"description": "Original url user to redirect from custom url path"
},
"custom_url_path": {
"$ref": "#/components/schemas/StringOrNull",
"description": "Custom url path"
}
},
"x-stoplight": {
@ -26367,7 +26379,7 @@
},
"fk_custom_url_id": {
"$ref": "#/components/schemas/StringOrNull",
"description": "Custom url id of view"
"description": "ID of custom url"
}
},
"required": ["fk_model_id", "show", "title", "type"],

52
packages/nocodb/src/services/shared-bases.service.ts

@ -6,7 +6,7 @@ import type { AppConfig, NcContext, NcRequest } from '~/interface/config';
import { AppHooksService } from '~/services/app-hooks/app-hooks.service';
import { validatePayload } from '~/helpers';
import { NcError } from '~/helpers/catchError';
import { Base } from '~/models';
import { Base, CustomUrl } from '~/models';
// todo: load from config
const config = {
@ -80,6 +80,8 @@ export class SharedBasesService {
password: string;
siteUrl: string;
req: NcRequest;
custom_url_path?: string;
original_url?: string;
},
): Promise<any> {
validatePayload('swagger.json#/components/schemas/SharedBaseReq', param);
@ -99,10 +101,51 @@ export class SharedBasesService {
NcError.badRequest('Only viewer role is supported');
}
let customUrl: CustomUrl | undefined = base.fk_custom_url_id
? await CustomUrl.get({
id: base.fk_custom_url_id,
})
: undefined;
// Update an existing custom URL if it exists
if (customUrl?.id) {
if (param.custom_url_path || param.original_url) {
// Prepare updated fields conditionally
const updates: Partial<CustomUrl> = {};
if (param.custom_url_path !== undefined) {
updates.custom_path = param.custom_url_path;
}
if (customUrl.original_path !== param.original_url) {
updates.original_path = param.original_url;
}
// Perform the update if there are changes
if (Object.keys(updates).length > 0) {
await CustomUrl.update(base.fk_custom_url_id, updates);
}
} else if (param.custom_url_path !== undefined) {
// Delete the custom URL if only the custom path is undefined
await CustomUrl.delete({ id: base.fk_custom_url_id as string });
customUrl = undefined;
}
} else if (param.custom_url_path) {
// Insert a new custom URL if it doesn't exist
customUrl = await CustomUrl.insert({
fk_workspace_id: base.fk_workspace_id,
base_id: base.id,
original_path: param.original_url,
custom_path: param.custom_url_path,
});
}
const data: any = {
uuid: base.uuid || uuidv4(),
password: param.password,
roles,
fk_custom_url_id: customUrl?.id ?? null,
};
await Base.update(context, base.id, data);
@ -150,10 +193,15 @@ export class SharedBasesService {
}
const data: any = {
uuid: null,
fk_custom_url_id: null,
};
await Base.update(context, base.id, data);
if (base.fk_custom_url_id) {
await CustomUrl.delete({ id: base.fk_custom_url_id });
}
this.appHooksService.emit(AppEvents.SHARED_BASE_DELETE_LINK, {
base,
req: param.req,
@ -173,9 +221,11 @@ export class SharedBasesService {
if (!base) {
NcError.baseNotFound(param.baseId);
}
const data: any = {
uuid: base.uuid,
roles: base.roles,
fk_custom_url_id: base.fk_custom_url_id,
};
if (data.uuid)
data.url = `${param.siteUrl}${config.dashboardPath}#/base/${data.shared_base_id}`;

Loading…
Cancel
Save