Skip to content

Commit

Permalink
Merge pull request #202 from nocodb/feat/docs-acl
Browse files Browse the repository at this point in the history
Docs: ACL
  • Loading branch information
mustafapc19 committed Mar 7, 2023
2 parents 6724f73 + 20d2d50 commit ab5bff4
Show file tree
Hide file tree
Showing 18 changed files with 125 additions and 57 deletions.
10 changes: 5 additions & 5 deletions packages/nc-gui/components/dlg/ShareAndCollaborate.vue
Expand Up @@ -58,12 +58,12 @@ watch(formStatus, (val) => {
:centered="true"
:width="formStatus === 'manageCollaborators' ? '60rem' : '40rem'"
>
<div v-if="formStatus === 'collaborateSaving'" class="flex flex-row w-full px-5 justify-between">
<div class="flex text-lg" :style="{ fontWeight: 500 }">Adding Collaborators</div>
<div v-if="formStatus === 'collaborateSaving'" class="flex flex-row w-full px-5 justify-between items-center py-0.5">
<div class="flex text-base" :style="{ fontWeight: 500 }">Adding Collaborators</div>
<a-spin :indicator="indicator" />
</div>
<div v-else-if="formStatus === 'collaborateSaved'" class="flex flex-row w-full px-5 justify-between items-center">
<div class="flex text-lg" :style="{ fontWeight: 500 }">Collaborators added</div>
<div v-else-if="formStatus === 'collaborateSaved'" class="flex flex-row w-full px-5 justify-between items-center py-0.5">
<div class="flex text-base" :style="{ fontWeight: 500 }">Collaborators added</div>
<div class="flex"><MdiCheck /></div>
</div>
<div v-else class="flex flex-col">
Expand Down Expand Up @@ -109,7 +109,7 @@ watch(formStatus, (val) => {
<style lang="scss">
.nc-modal-share-collaborate {
.ant-modal-content {
@apply !rounded-2xl;
@apply !rounded-lg;
}
.ant-modal-body {
@apply !py-2.5 !px-1;
Expand Down
Expand Up @@ -83,7 +83,7 @@ onMounted(async () => {
class="!rounded-md p-0.5 !bg-gray-200"
dropdown-class-name="nc-dropdown-user-role !rounded-md"
>
<a-select-option v-for="(role, index) in projectRoles" :key="index" :value="role" class="nc-role-option">
<a-select-option v-for="(role, index) in docsProjectRoles" :key="index" :value="role" class="nc-role-option">
<div class="flex flex-row h-full justify-start items-center">
<div
class="px-2 py-1 flex rounded-full text-xs capitalize"
Expand Down
Expand Up @@ -75,7 +75,7 @@ const loadListData = async ($state: any) => {
dropdown-class-name="nc-dropdown-user-role !rounded-md"
placeholder="Select role"
>
<a-select-option v-for="(role, index) in projectRoles" :key="index" :value="role" class="nc-role-option">
<a-select-option v-for="(role, index) in docsProjectRoles" :key="index" :value="role" class="nc-role-option">
<div class="flex flex-row h-full justify-start items-center">
<div
class="px-2 py-1 flex rounded-full text-xs capitalize"
Expand Down
4 changes: 2 additions & 2 deletions packages/nc-gui/components/docs/Page/Title.vue
Expand Up @@ -5,7 +5,7 @@ const emit = defineEmits(['focusEditor'])
const MAX_TITLE_LENGTH = 150
const { updatePage, isPublic, openedPage, findPage, nestedPages } = useDocs()
const { updatePage, isPublic, openedPage, findPage, nestedPages, isEditAllowed } = useDocs()
const titleInputRef = ref<HTMLInputElement>()
Expand Down Expand Up @@ -64,7 +64,7 @@ const setIcon = async (icon: string) => {
watchDebounced(
() => [openedPage.value?.id, openedPage.value?.title],
async ([oldPageId], [newPageId]) => {
if (isPublic.value) return
if (!isEditAllowed.value) return
if (!openedPage.value) return
if (oldPageId !== newPageId) return
Expand Down
21 changes: 17 additions & 4 deletions packages/nc-gui/components/docs/Page/View.vue
Expand Up @@ -17,6 +17,7 @@ const {
openPage,
openedPageId,
isPublic,
isEditAllowed,
nestedPublicParentPage,
isFetching,
findPage,
Expand Down Expand Up @@ -63,7 +64,7 @@ const editor = useEditor({
return false
},
},
editable: !isPublic.value,
editable: isEditAllowed.value,
})
const focusEditor = () => {
Expand All @@ -77,6 +78,18 @@ const removeNewFlagFromNewPage = (pageId: string) => {
}
}
watch(
isEditAllowed,
() => {
editor.value?.setOptions({
editable: isEditAllowed.value,
})
},
{
immediate: true,
},
)
watch(
() => content.value,
() => {
Expand All @@ -95,7 +108,7 @@ watch(
watchDebounced(
() => [openedPage.value?.id, openedPage.value?.content],
([newId, newContent], [oldId, oldContent]) => {
if (!isPublic.value && openedPage.value?.id && newId === oldId && newContent !== oldContent) {
if (isEditAllowed && openedPage.value?.id && newId === oldId && newContent !== oldContent) {
updateContent({ pageId: openedPage.value?.id, content: openedPage.value!.content })
}
},
Expand Down Expand Up @@ -196,8 +209,8 @@ watch(
:editor="editor"
class="px-2"
:class="{
'-ml-1': isPublic,
'-ml-12.5': !isPublic,
'-ml-1': !isEditAllowed,
'-ml-12.5': isEditAllowed,
}"
/>
<div
Expand Down
9 changes: 5 additions & 4 deletions packages/nc-gui/components/docs/SideBar.vue
Expand Up @@ -21,6 +21,7 @@ const {
projectUrl,
expandTabOfOpenedPage,
isPublic,
isEditAllowed,
} = useDocs()
const deleteModalOpen = ref(false)
Expand Down Expand Up @@ -160,7 +161,7 @@ onKeyStroke('Enter', () => {
{{ project.title }}
</div>
</div>
<div v-if="project.title" class="flex flex-row justify-between items-center">
<div v-if="project.title && isEditAllowed" class="flex flex-row justify-between items-center">
<div
class="flex select-none p-1 rounded-md hover:(text-primary/100 !bg-gray-200 !bg-opacity-60) cursor-pointer pop-in-animation"
@click="() => addNewPage()"
Expand All @@ -175,7 +176,7 @@ onKeyStroke('Enter', () => {
v-model:selectedKeys="openPageTabKeys"
:load-data="onLoadData"
:tree-data="(nestedPages as any)"
:draggable="!isPublic"
:draggable="isEditAllowed"
:on-drop="onDrop"
class="!w-full h-full overflow-y-scroll !overflow-x-hidden pb-20"
@dragenter="onDragEnter"
Expand All @@ -190,7 +191,7 @@ onKeyStroke('Enter', () => {
<div class="flex flex-shrink-0">
<a-popover placement="bottom" overlay-class-name="docs-page-icon-change-popover" color="#000000">
<template #content> Change Icon </template>
<a-dropdown v-if="!isPublic" placement="bottom" trigger="click">
<a-dropdown v-if="isEditAllowed" placement="bottom" trigger="click">
<div class="flex px-0.5 pt-0.75 text-gray-500 rounded-md hover:bg-gray-200 cursor-pointer">
<IconifyIcon
v-if="icon"
Expand Down Expand Up @@ -227,7 +228,7 @@ onKeyStroke('Enter', () => {
{{ title }}
</span>
</div>
<div v-if="!isPublic" class="flex flex-row justify-start items-center pl-2 gap-x-1 h-3">
<div v-if="isEditAllowed" class="flex flex-row justify-start items-center pl-2 gap-x-1 h-3">
<a-dropdown placement="bottom" trigger="click">
<div
class="nc-docs-sidebar-page-options flex px-0.5 hover:( !bg-gray-300 !bg-opacity-30 rounded-md) cursor-pointer select-none hidden group-hover:block"
Expand Down
5 changes: 3 additions & 2 deletions packages/nc-gui/components/docs/book/View.vue
Expand Up @@ -17,6 +17,7 @@ const {
openPage,
isFetching,
openChildPageTabsOfRootPages,
isEditAllowed,
} = useDocs()
const indicator = h(Loading3QuartersOutlined, {
Expand Down Expand Up @@ -252,7 +253,7 @@ const closeMagicModal = () => {
<div class="flex flex-row justify-between mt-2 items-center">
<div class="flex flex-row gap-x-6 items-center">
<div class="flex text-4xl font-semibold">{{ project?.title }}</div>
<a-dropdown overlay-class-name="nc-docs-menu" trigger="click">
<a-dropdown v-if="isEditAllowed" overlay-class-name="nc-docs-menu" trigger="click">
<div
class="flex flex-row !bg-gray-50 rounded-md hover:( !bg-gray-200 !bg-opacity-60) cursor-pointer select-none p-1.5 h-8 items-center"
@click.prevent
Expand All @@ -272,7 +273,7 @@ const closeMagicModal = () => {
</template>
</a-dropdown>
</div>
<div class="flex flex-row gap-x-1 h-10 justify-end">
<div v-if="isEditAllowed" class="flex flex-row gap-x-1 h-10 justify-end">
<a-dropdown trigger="click" placement="bottomLeft">
<div
class="my-1 pl-3 pr-1.5 rounded-md border-gray-100 border-1 flex flex-row max-w-28 mr-2 justify-between items-center gap-x-1 hover:cursor-pointer hover:bg-gray-100"
Expand Down
62 changes: 31 additions & 31 deletions packages/nc-gui/components/docs/utils.ts
@@ -1,42 +1,42 @@
import { onKeyStroke } from '@vueuse/core'

const useShortcuts = () => {
const { openedPage, addNewPage, getParentOfPage, isPublic } = useDocs()

const shortCuts = !isPublic.value
? [
{
condition: (e: KeyboardEvent) => e.code === 'KeyN' && e.altKey,
action: (e: KeyboardEvent) => {
e.preventDefault()

addNewPage(openedPage.value?.parent_page_id)
},
},
{
condition: (e: KeyboardEvent) => e.code === 'KeyM' && e.altKey,
action: (e: KeyboardEvent) => {
e.preventDefault()

addNewPage(openedPage.value?.id)
},
},
{
condition: (e: KeyboardEvent) => e.code === 'KeyB' && e.altKey,
action: (e: KeyboardEvent) => {
e.preventDefault()

const parentPage = openedPage.value?.parent_page_id ? getParentOfPage(openedPage.value.parent_page_id) : null
addNewPage(parentPage?.id)
},
},
]
: []
const { openedPage, addNewPage, getParentOfPage, isEditAllowed } = useDocs()

const shortCuts = [
{
condition: (e: KeyboardEvent) => e.code === 'KeyN' && e.altKey,
action: (e: KeyboardEvent) => {
e.preventDefault()

addNewPage(openedPage.value?.parent_page_id)
},
},
{
condition: (e: KeyboardEvent) => e.code === 'KeyM' && e.altKey,
action: (e: KeyboardEvent) => {
e.preventDefault()

addNewPage(openedPage.value?.id)
},
},
{
condition: (e: KeyboardEvent) => e.code === 'KeyB' && e.altKey,
action: (e: KeyboardEvent) => {
e.preventDefault()

const parentPage = openedPage.value?.parent_page_id ? getParentOfPage(openedPage.value.parent_page_id) : null
addNewPage(parentPage?.id)
},
},
]

// Listen to shortcuts
onKeyStroke(
(e) => shortCuts.some((shortCut) => shortCut.condition(e)),
(e) => {
if (!isEditAllowed.value) return

const shortCut = shortCuts.find((shortCut) => shortCut.condition(e))
shortCut?.action(e)
},
Expand Down
1 change: 1 addition & 0 deletions packages/nc-gui/components/general/ShareProject.vue
Expand Up @@ -26,6 +26,7 @@ useEventListener(document, 'keydown', async (e: KeyboardEvent) => {

<template>
<div
v-if="visibility !== 'none'"
class="my-auto h-7.5 flex flex-row items-center gap-x-1.5 bg-primary text-white hover:bg-opacity-80 py-1.5 px-2.5 rounded-md mr-2 cursor-pointer"
@click="showModal = true"
>
Expand Down
13 changes: 13 additions & 0 deletions packages/nc-gui/composables/useDocs/index.ts
Expand Up @@ -3,14 +3,26 @@ import type { DocsPageType } from 'nocodb-sdk'
import gh from 'parse-github-url'
import { extractSdkResponseErrorMsg, useNuxtApp } from '#imports'
import type { PageSidebarNode } from '~~/lib'
import { ProjectRole } from '~/lib/enums'

export const PAGES_PER_PAGE_LIST = 10

const [setup, use] = useInjectionState(() => {
const route = useRoute()
const { $api } = useNuxtApp()
const { appInfo } = $(useGlobal())
const { projectRoles } = useRoles()

const isPublic = computed<boolean>(() => !!route.meta.public)
const isEditAllowed = computed<boolean>(
() =>
!isPublic.value &&
!!(
projectRoles.value[ProjectRole.Creator] ||
projectRoles.value[ProjectRole.Owner] ||
projectRoles.value[ProjectRole.Editor]
),
)

const projectId = $(computed(() => route.params.projectId as string))

Expand Down Expand Up @@ -625,6 +637,7 @@ const [setup, use] = useInjectionState(() => {
nestedPublicParentPage,
parentWhichIsNestedPublished,
findPage,
isEditAllowed,
}
}, 'useDocs')

Expand Down
6 changes: 6 additions & 0 deletions packages/nc-gui/composables/useManageUsers.ts
Expand Up @@ -85,12 +85,18 @@ const [setup, use] = useInjectionState(() => {
await Promise.all(
_editedUsers.map(async (user) => {
await api.auth.projectUserUpdate(project.value!.id!, user.id, {
email: user.email,
roles: user.roles,
project_id: project.value.id,
projectName: project.value.title,
})
const savedUser = users.value?.find((u) => u.id === user.id)
if (savedUser) {
savedUser.roles = user.roles
}
}),
)
lastFetchedUsers.value = JSON.parse(JSON.stringify(users.value))
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
} finally {
Expand Down
1 change: 1 addition & 0 deletions packages/nc-gui/composables/useProject.ts
Expand Up @@ -124,6 +124,7 @@ export const useProject = createSharedComposable(() => {
if (projectId) {
project.value = await api.project.read(projectId)
}
await loadProjectRoles(project.value.id!)
}

async function loadBookPublicProject(projectId?: string) {
Expand Down
13 changes: 9 additions & 4 deletions packages/nc-gui/composables/useShare.ts
@@ -1,7 +1,7 @@
const [setup, use] = useInjectionState(() => {
const visibility = ref<'public' | 'private'>('private')
const visibility = ref<'public' | 'private' | 'none'>('none')
const { project } = useProject()
const { openedPage, parentWhichIsNestedPublished } = useDocs()
const { openedPage, parentWhichIsNestedPublished, isEditAllowed } = useDocs()

const isPublic = computed(() => {
const projectMeta = project.value?.meta as any
Expand All @@ -16,11 +16,16 @@ const [setup, use] = useInjectionState(() => {
})

watch(
isPublic,
[isPublic, isEditAllowed],
() => {
if (!isEditAllowed.value) {
visibility.value = 'none'
return
}

visibility.value = isPublic.value ? 'public' : 'private'
},
{ immediate: true },
{ immediate: true, deep: true },
)

return {
Expand Down
2 changes: 2 additions & 0 deletions packages/nc-gui/utils/userUtils.ts
Expand Up @@ -11,3 +11,5 @@ export const projectRoleTagColors = {
}

export const projectRoles = [ProjectRole.Creator, ProjectRole.Editor, ProjectRole.Commenter, ProjectRole.Viewer]

export const docsProjectRoles = [ProjectRole.Editor, ProjectRole.Viewer]
6 changes: 3 additions & 3 deletions packages/nocodb/src/lib/controllers/docs/page.ctl.ts
Expand Up @@ -206,16 +206,16 @@ router.post(
router.get(
'/api/v1/docs/pages/paginate',
apiMetrics,
ncMetaAclMw(paginate, 'paginate')
ncMetaAclMw(paginate, 'pagePaginate')
);
router.post(
'/api/v1/docs/pages/magic',
apiMetrics,
ncMetaAclMw(magicCreatePages, 'magicCreatePages')
ncMetaAclMw(magicCreatePages, 'pageMagicCreate')
);
router.post(
'/api/v1/docs/pages/import',
apiMetrics,
ncMetaAclMw(directoryImport, 'directoryImport')
ncMetaAclMw(directoryImport, 'pageDirectoryImport')
);
export default router;
@@ -1,9 +1,11 @@
import publicDataController from './publicData.ctl';
import publicDataExportController from './publicDataExport.ctl';
import publicMetaController from './publicMeta.ctl';
import publicDocsPagesController from './publicDocsPages.ctl';

export {
publicDataController,
publicDataExportController,
publicMetaController,
publicDocsPagesController,
};

0 comments on commit ab5bff4

Please sign in to comment.