-
+
{{ email }}
(inviteData.roles = role
:placeholder="$t('activity.enterEmail')"
class="w-full min-w-36 outline-none px-2"
data-testid="email-input"
- @keyup.enter="handleEnter"
@blur="isDivFocused = false"
+ @keyup.enter="handleEnter"
@paste.prevent="onPaste"
/>
{{
emailValidation.message
}}
+
+
+
+
+ {{ workspace.title }}
+
+
+
+
+
+
+
+
+ {{ workspace.title }}
+
+
+
+
+
+
{{ $t('labels.cancel') }}
- {{ $t('activity.inviteToBase') }}
+ {{ type === 'base' ? $t('activity.inviteToBase') : $t('activity.inviteToWorkspace') }}
+
+
diff --git a/packages/nc-gui/components/dlg/TableDelete.vue b/packages/nc-gui/components/dlg/TableDelete.vue
index 59f5d41dc2..3180b60f7a 100644
--- a/packages/nc-gui/components/dlg/TableDelete.vue
+++ b/packages/nc-gui/components/dlg/TableDelete.vue
@@ -79,8 +79,9 @@ const onDelete = async () => {
$e('a:table:delete')
if (oldActiveTableId === toBeDeletedTable.id) {
+ const sourceTables = tables.value.filter((t) => t.source_id === toBeDeletedTable.source_id)
// Navigate to base if no tables left or open first table
- if (tables.value.length === 0) {
+ if (sourceTables.length === 0) {
await navigateTo(
baseUrl({
id: props.baseId,
@@ -88,7 +89,7 @@ const onDelete = async () => {
}),
)
} else {
- await openTable(tables.value[0])
+ await openTable(sourceTables[0])
}
}
diff --git a/packages/nc-gui/components/dlg/WorkspaceDelete.vue b/packages/nc-gui/components/dlg/WorkspaceDelete.vue
deleted file mode 100644
index 3d1e543ef1..0000000000
--- a/packages/nc-gui/components/dlg/WorkspaceDelete.vue
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
- {{ workspace.title }}
-
-
-
-
-
diff --git a/packages/nc-gui/components/general/BaseIconColorPicker.vue b/packages/nc-gui/components/general/BaseIconColorPicker.vue
index d88ca36ebb..05d39a43b9 100644
--- a/packages/nc-gui/components/general/BaseIconColorPicker.vue
+++ b/packages/nc-gui/components/general/BaseIconColorPicker.vue
@@ -7,7 +7,7 @@ const props = withDefaults(
defineProps<{
type?: NcProjectType | string
modelValue?: string
- size?: 'small' | 'medium' | 'large' | 'xlarge'
+ size?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge'
readonly?: boolean
iconClass?: string
}>(),
@@ -62,6 +62,7 @@ watch(
:class="{
'hover:bg-gray-500 hover:bg-opacity-15 cursor-pointer': !readonly,
'bg-gray-500 bg-opacity-15': isOpen,
+ 'h-5 w-5 text-base': size === 'xsmall',
'h-6 w-6 text-lg': size === 'small',
'h-8 w-8 text-xl': size === 'medium',
'h-10 w-10 text-2xl': size === 'large',
diff --git a/packages/nc-gui/components/general/CopyButton.vue b/packages/nc-gui/components/general/CopyButton.vue
new file mode 100644
index 0000000000..cc2b1c6584
--- /dev/null
+++ b/packages/nc-gui/components/general/CopyButton.vue
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
diff --git a/packages/nc-gui/components/general/WorkspaceIcon.vue b/packages/nc-gui/components/general/WorkspaceIcon.vue
index e5d14087ce..963078eb3f 100644
--- a/packages/nc-gui/components/general/WorkspaceIcon.vue
+++ b/packages/nc-gui/components/general/WorkspaceIcon.vue
@@ -6,6 +6,7 @@ const props = defineProps<{
workspace: WorkspaceType | undefined
hideLabel?: boolean
size?: 'small' | 'medium' | 'large'
+ isRounded?: boolean
}>()
const workspaceColor = computed(() => {
@@ -24,6 +25,7 @@ const size = computed(() => props.size || 'medium')
'min-w-4 w-4 h-4 rounded': size === 'small',
'min-w-6 w-6 h-6 rounded-md': size === 'medium',
'min-w-10 w-10 h-10 rounded-lg !text-base': size === 'large',
+ '!rounded-[50%]': props.isRounded,
}"
:style="{ backgroundColor: workspaceColor }"
>
diff --git a/packages/nc-gui/components/nc/Badge.vue b/packages/nc-gui/components/nc/Badge.vue
index 4ba282e4a4..774b1eecbf 100644
--- a/packages/nc-gui/components/nc/Badge.vue
+++ b/packages/nc-gui/components/nc/Badge.vue
@@ -4,17 +4,18 @@ const props = withDefaults(
color?: string
border?: boolean
size?: 'sm' | 'md' | 'lg'
+ rounded?: 'sm' | 'md' | 'lg'
}>(),
{
border: true,
size: 'sm',
+ rounded: 'md',
},
)
diff --git a/packages/nc-gui/components/nc/ErrorBoundary.vue b/packages/nc-gui/components/nc/ErrorBoundary.vue
index cb3ce25abd..567a956f8a 100644
--- a/packages/nc-gui/components/nc/ErrorBoundary.vue
+++ b/packages/nc-gui/components/nc/ErrorBoundary.vue
@@ -20,7 +20,7 @@ export default {
onErrorCaptured((err) => {
if (import.meta.client && (!nuxtApp.isHydrating || !nuxtApp.payload.serverRendered)) {
- console.log('UI Error :', err)
+ console.error('UI Error :', err)
emit('error', err)
error.value = err
return false
diff --git a/packages/nc-gui/components/nc/Select.vue b/packages/nc-gui/components/nc/Select.vue
index bd109bdcf2..553501fee6 100644
--- a/packages/nc-gui/components/nc/Select.vue
+++ b/packages/nc-gui/components/nc/Select.vue
@@ -3,6 +3,7 @@ const props = defineProps<{
value?: string | string[]
placeholder?: string
mode?: 'multiple' | 'tags'
+ size?: 'small' | 'middle' | 'large'
dropdownClassName?: string
showSearch?: boolean
// filterOptions is a function
@@ -44,6 +45,7 @@ const onChange = (value: string) => {
-import {
- OrderedProjectRoles,
- OrgUserRoles,
- ProjectRoles,
- WorkspaceRolesToProjectRoles,
- extractRolesObj,
- parseStringDateTime,
- timeAgo,
-} from 'nocodb-sdk'
import type { Roles, WorkspaceUserRoles } from 'nocodb-sdk'
+import { OrderedProjectRoles, OrgUserRoles, ProjectRoles, WorkspaceRolesToProjectRoles } from 'nocodb-sdk'
import type { User } from '#imports'
import { isEeUI, storeToRefs, useUserSorts } from '#imports'
+const props = defineProps<{
+ baseId?: string
+}>()
+
const basesStore = useBases()
const { getBaseUsers, createProjectUser, updateProjectUser, removeProjectUser } = basesStore
-const { activeProjectId } = storeToRefs(basesStore)
+const { activeProjectId, bases } = storeToRefs(basesStore)
-const { orgRoles, baseRoles } = useRoles()
+const { orgRoles, baseRoles, loadRoles } = useRoles()
-const { sorts, sortDirection, loadSorts, saveOrUpdate, handleGetSortedData } = useUserSorts('Project')
+const { sorts, loadSorts, handleGetSortedData, toggleSort } = useUserSorts('Project')
const isSuper = computed(() => orgRoles.value?.[OrgUserRoles.SUPER_ADMIN])
+const orgStore = useOrg()
+const { orgId } = storeToRefs(orgStore)
+
+const isAdminPanel = inject(IsAdminPanelInj, ref(false))
+
+const { $api } = useNuxtApp()
+
+const currentBase = computedAsync(async () => {
+ let base
+ if (props.baseId) {
+ await loadRoles(props.baseId)
+ base = bases.value.get(props.baseId)
+ if (!base) {
+ base = await $api.base.read(props.baseId!)
+ }
+ } else {
+ base = bases.value.get(activeProjectId.value)
+ }
+ return base
+})
+
const isInviteModalVisible = ref(false)
interface Collaborators {
@@ -56,8 +73,9 @@ const sortedCollaborators = computed(() => {
const loadCollaborators = async () => {
try {
+ if (!currentBase.value) return
const { users, totalRows } = await getBaseUsers({
- baseId: activeProjectId.value!,
+ baseId: currentBase.value.id!,
...(!userSearchText.value ? {} : ({ searchText: userSearchText.value } as any)),
force: true,
})
@@ -69,12 +87,11 @@ const loadCollaborators = async () => {
.map((user: any) => ({
...user,
base_roles: user.roles,
- roles: extractRolesObj(user.main_roles)?.[OrgUserRoles.SUPER_ADMIN]
- ? OrgUserRoles.SUPER_ADMIN
- : user.roles ??
- (user.workspace_roles
- ? WorkspaceRolesToProjectRoles[user.workspace_roles as WorkspaceUserRoles] ?? ProjectRoles.NO_ACCESS
- : ProjectRoles.NO_ACCESS),
+ roles:
+ user.roles ??
+ (user.workspace_roles
+ ? WorkspaceRolesToProjectRoles[user.workspace_roles as WorkspaceUserRoles] ?? ProjectRoles.NO_ACCESS
+ : ProjectRoles.NO_ACCESS),
})),
]
} catch (e: any) {
@@ -93,7 +110,7 @@ const updateCollaborator = async (collab: any, roles: ProjectRoles) => {
WorkspaceRolesToProjectRoles[currentCollaborator.workspace_roles as WorkspaceUserRoles] === roles &&
isEeUI)
) {
- await removeProjectUser(activeProjectId.value!, currentCollaborator as unknown as User)
+ await removeProjectUser(currentBase.value.id!, currentCollaborator as unknown as User)
if (
currentCollaborator.workspace_roles &&
WorkspaceRolesToProjectRoles[currentCollaborator.workspace_roles as WorkspaceUserRoles] === roles &&
@@ -105,11 +122,11 @@ const updateCollaborator = async (collab: any, roles: ProjectRoles) => {
}
} else if (currentCollaborator.base_roles) {
currentCollaborator.roles = roles
- await updateProjectUser(activeProjectId.value!, currentCollaborator as unknown as User)
+ await updateProjectUser(currentBase.value.id!, currentCollaborator as unknown as User)
} else {
currentCollaborator.roles = roles
currentCollaborator.base_roles = roles
- await createProjectUser(activeProjectId.value!, currentCollaborator as unknown as User)
+ await createProjectUser(currentBase.value.id!, currentCollaborator as unknown as User)
}
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
@@ -142,24 +159,50 @@ watch(isInviteModalVisible, () => {
loadCollaborators()
}
})
+
+watch(currentBase, () => {
+ loadCollaborators()
+})
-
-
+
+
+
+
+
+ {{ $t('objects.projects') }}
+
+
+ /
+
+
+ {{ currentBase?.title }}
+
+
+
+
-
-
+
+
-
+
{{ $t('activity.addMembers') }}
@@ -172,26 +215,29 @@ watch(isInviteModalVisible, () => {
-
-
- {{ $t('objects.users') }}
-
-
-
+
+
+
-
-
- {{ $t('general.access') }}
-
-
-
{{ $t('title.dateJoined') }}
@@ -203,17 +249,16 @@ watch(isInviteModalVisible, () => {
>
-
-
+
+
+
+ {{ collab.display_name || collab.email.slice(0, collab.email.indexOf('@')) }}
+
+
+
{{ collab.email }}
-
-
- {{ collab.display_name }}
-
-
- {{ collab.email }}
-
+
@@ -230,7 +275,7 @@ watch(isInviteModalVisible, () => {
/>
-
+
@@ -252,6 +297,18 @@ watch(isInviteModalVisible, () => {
diff --git a/packages/nc-gui/components/virtual-cell/components/LinkedItems.vue b/packages/nc-gui/components/virtual-cell/components/LinkedItems.vue
index 5762c2c0d6..6be91be7a1 100644
--- a/packages/nc-gui/components/virtual-cell/components/LinkedItems.vue
+++ b/packages/nc-gui/components/virtual-cell/components/LinkedItems.vue
@@ -1,5 +1,6 @@
-
-
-
-
-
-
{
- if (e.key === 'Escape') {
- filterQueryRef?.blur()
+