Browse Source

Merge pull request #6498 from nocodb/nc-fix/ws-dropdown-fix

Mobile UI fixes
pull/6431/head
Muhammed Mustafa 11 months ago committed by GitHub
parent
commit
7971c22491
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/nc-gui/assets/nc-icons/download.svg
  2. 6
      packages/nc-gui/components/dashboard/Sidebar.vue
  3. 2
      packages/nc-gui/components/dashboard/Sidebar/TopSection.vue
  4. 5
      packages/nc-gui/components/dashboard/TreeView/TableNode.vue
  5. 18
      packages/nc-gui/components/dashboard/TreeView/ViewsList.vue
  6. 9
      packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue
  7. 9
      packages/nc-gui/components/dashboard/View.vue
  8. 2
      packages/nc-gui/components/nc/MenuItem.vue
  9. 2
      packages/nc-gui/components/nc/Pagination.vue
  10. 2
      packages/nc-gui/components/project/AllTables.vue
  11. 1
      packages/nc-gui/components/smartsheet/Toolbar.vue
  12. 14
      packages/nc-gui/components/smartsheet/expanded-form/Comments.vue
  13. 32
      packages/nc-gui/components/smartsheet/expanded-form/index.vue
  14. 32
      packages/nc-gui/components/smartsheet/grid/index.vue
  15. 6
      packages/nc-gui/components/smartsheet/header/Cell.vue
  16. 53
      packages/nc-gui/components/smartsheet/toolbar/OpenViewSidebarBtn.vue
  17. 3
      packages/nc-gui/lang/en.json
  18. 22
      packages/nc-gui/store/sidebar.ts
  19. 9
      tests/playwright/pages/Dashboard/Form/index.ts
  20. 4
      tests/playwright/pages/Dashboard/Kanban/index.ts
  21. 19
      tests/playwright/pages/Dashboard/common/LeftSidebar/index.ts
  22. 10
      tests/playwright/pages/Dashboard/common/WorkspaceMenu/index.ts
  23. 3
      tests/playwright/pages/Dashboard/index.ts
  24. 8
      tests/playwright/tests/db/columns/columnAttachments.spec.ts
  25. 16
      tests/playwright/tests/db/features/baseShare.spec.ts
  26. 2
      tests/playwright/tests/db/features/verticalFillHandle.spec.ts

2
packages/nc-gui/assets/nc-icons/download.svg

@ -1,5 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 10V12.6667C14 13.0203 13.8595 13.3594 13.6095 13.6095C13.3594 13.8595 13.0203 14 12.6667 14H3.33333C2.97971 14 2.64057 13.8595 2.39052 13.6095C2.14048 13.3594 2 13.0203 2 12.6667V10" stroke="#1F293A" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M4.66675 6.66663L8.00008 9.99996L11.3334 6.66663" stroke="#1F293A" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 10V2" stroke="#4A5268" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 10V2" stroke="#1F293A" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 643 B

After

Width:  |  Height:  |  Size: 643 B

6
packages/nc-gui/components/dashboard/Sidebar.vue

@ -5,11 +5,15 @@ const { isWorkspaceLoading } = storeToRefs(workspaceStore)
const { isSharedBase } = storeToRefs(useProject())
const { isMobileMode } = useGlobal()
const treeViewDom = ref<HTMLElement>()
const isTreeViewOnScrollTop = ref(false)
const checkScrollTopMoreThanZero = () => {
if (isMobileMode.value) return
if (treeViewDom.value) {
if (treeViewDom.value.scrollTop > 0) {
isTreeViewOnScrollTop.value = true
@ -43,7 +47,7 @@ onUnmounted(() => {
</div>
<div
ref="treeViewDom"
class="flex flex-col nc-scrollbar-dark-md flex-grow"
class="flex flex-col nc-scrollbar-dark-md flex-grow xs:(border-transparent pt-2)"
:class="{
'border-t-1': !isSharedBase,
'border-transparent': !isTreeViewOnScrollTop,

2
packages/nc-gui/components/dashboard/Sidebar/TopSection.vue

@ -43,7 +43,7 @@ const navigateToSettings = () => {
</div>
</template>
<template v-else-if="!isSharedBase">
<div class="flex flex-col p-1 gap-y-0.5 mt-0.25 mb-0.5 truncate">
<div class="xs:hidden flex flex-col p-1 gap-y-0.5 mt-0.25 mb-0.5 truncate">
<DashboardSidebarTopSectionHeader />
<NcButton

5
packages/nc-gui/components/dashboard/TreeView/TableNode.vue

@ -46,6 +46,7 @@ const { setMenuContext, openRenameTableDialog, duplicateTable } = inject(TreeVie
const { loadViews: _loadViews } = useViewsStore()
const { activeView } = storeToRefs(useViewsStore())
const { isLeftSidebarOpen } = storeToRefs(useSidebarStore())
// todo: temp
const { projectTables } = storeToRefs(useTablesStore())
@ -108,6 +109,10 @@ const onOpenTable = async () => {
isLoading.value = true
try {
await _openTable(table.value)
if (isMobileMode.value) {
isLeftSidebarOpen.value = false
}
} catch (e) {
message.error(await extractSdkResponseErrorMsg(e))
} finally {

18
packages/nc-gui/components/dashboard/TreeView/ViewsList.vue

@ -31,6 +31,8 @@ const emits = defineEmits<Emits>()
const project = inject(ProjectInj)!
const table = inject(SidebarTableInj)!
const { isLeftSidebarOpen } = storeToRefs(useSidebarStore())
const { isMobileMode } = useGlobal()
const { $e } = useNuxtApp()
@ -190,13 +192,17 @@ const initSortable = (el: HTMLElement) => {
onMounted(() => menuRef.value && initSortable(menuRef.value.$el))
/** Navigate to view by changing url param */
function changeView(view: ViewType) {
navigateToView({
async function changeView(view: ViewType) {
await navigateToView({
view,
tableId: table.value.id!,
projectId: project.value.id!,
hardReload: view.type === ViewTypes.FORM && selected.value[0] === view.id,
})
if (isMobileMode.value) {
isLeftSidebarOpen.value = false
}
}
/** Rename a view */
@ -351,13 +357,13 @@ function onOpenModal({
<template>
<div
v-if="!views.length"
class="text-gray-500 my-1.75"
class="text-gray-500 my-1.75 xs:(my-2.5 text-base)"
:class="{
'ml-19.25': isDefaultBase,
'ml-24.75': !isDefaultBase,
'ml-19.25 xs:ml-22.25': isDefaultBase,
'ml-24.75 xs:ml-30': !isDefaultBase,
}"
>
No Views
{{ $t('labels.noViews') }}
</div>
<a-menu

9
packages/nc-gui/components/dashboard/TreeView/ViewsNode.vue

@ -53,8 +53,6 @@ const activeView = inject(ActiveViewInj, ref())
const isLocked = inject(IsLockedInj, ref(false))
const { rightSidebarState } = storeToRefs(useSidebarStore())
const isDefaultBase = computed(() => {
const base = project.value?.bases?.find((b) => b.id === vModel.value.base_id)
if (!base) return false
@ -82,6 +80,7 @@ const onClick = useDebounceFn(() => {
/** Enable editing view name on dbl click */
function onDblClick() {
if (isMobileMode.value) return
if (!isUIAllowed('viewCreateOrEdit')) return
if (!isEditing.value) {
@ -193,12 +192,6 @@ function onStopEdit() {
}, 250)
}
watch(rightSidebarState, () => {
if (rightSidebarState.value === 'peekCloseEnd') {
isDropdownOpen.value = false
}
})
function onRef(el: HTMLElement) {
if (activeViewTitleOrId.value === vModel.value.id) {
nextTick(() => {

9
packages/nc-gui/components/dashboard/View.vue

@ -12,6 +12,7 @@ const {
leftSidebarWidthPercent,
leftSideBarSize: sideBarSize,
leftSidebarState: sidebarState,
mobileNormalizedSidebarSize,
} = storeToRefs(useSidebarStore())
const wrapperRef = ref<HTMLDivElement>()
@ -31,14 +32,6 @@ const { handleSidebarOpenOnMobileForNonViews } = useConfigStore()
const contentSize = computed(() => 100 - sideBarSize.value.current)
const mobileNormalizedSidebarSize = computed(() => {
if (isMobileMode.value) {
return isLeftSidebarOpen.value ? 100 : 0
}
return currentSidebarSize.value
})
const mobileNormalizedContentSize = computed(() => {
if (isMobileMode.value) {
return isLeftSidebarOpen.value ? 0 : 100

2
packages/nc-gui/components/nc/MenuItem.vue

@ -18,7 +18,7 @@
.nc-menu-item > .ant-dropdown-menu-title-content {
// Not Icon
:not(.nc-icon):not(.material-symbols) {
line-height: 0.95;
line-height: 1.5;
}
@apply flex flex-row items-center;

2
packages/nc-gui/components/nc/Pagination.vue

@ -13,7 +13,7 @@ const current = useVModel(props, 'current', emits)
const pageSize = useVModel(props, 'pageSize', emits)
const totalPages = computed(() => Math.ceil(total.value / pageSize.value))
const totalPages = computed(() => Math.max(Math.ceil(total.value / pageSize.value), 1))
const { isMobileMode } = useGlobal()

2
packages/nc-gui/components/project/AllTables.vue

@ -119,7 +119,7 @@ function openTableCreateDialog(baseIndex?: number | undefined) {
<style lang="scss" scoped>
.nc-project-view-all-table-btn {
@apply flex flex-col gap-y-6 p-4 bg-gray-100 rounded-xl w-56 cursor-pointer text-gray-600 hover:(bg-gray-100 !text-black);
@apply flex flex-col gap-y-6 p-4 bg-gray-100 rounded-xl w-56 cursor-pointer text-gray-600 hover:(bg-gray-200 !text-black);
.nc-icon {
@apply h-10 w-10;

1
packages/nc-gui/components/smartsheet/Toolbar.vue

@ -58,7 +58,6 @@ const { allowCSVDownload } = useSharedView()
:show-system-fields="false"
/>
</template>
<LazySmartsheetToolbarOpenViewSidebarBtn v-if="isViewSidebarAvailable" />
</template>
</div>
</template>

14
packages/nc-gui/components/smartsheet/expanded-form/Comments.vue

@ -153,7 +153,7 @@ const processedAudit = (log: string) => {
</div>
<div class="font-medium text-center my-6 text-gray-500">{{ $t('activity.startCommenting') }}</div>
</div>
<div v-else class="flex flex-col h-full p-2 space-y-2 nc-scrollbar-md">
<div v-else class="flex flex-col h-full py-2 pl-2 pr-1 space-y-2 nc-scrollbar-md">
<div v-for="log of comments" :key="log.id">
<div class="bg-white rounded-xl group border-1 gap-2 border-gray-200">
<div class="flex flex-col p-4 gap-3">
@ -198,14 +198,12 @@ const processedAudit = (log: string) => {
</div>
</div>
</div>
<div v-if="hasEditPermission" class="h-16.5 p-2 rounded-b-xl bg-gray-50 gap-2 flex">
<div class="flex flex-row items-end">
<GeneralUserIcon size="base" />
</div>
<div class="flex flex-row bg-white py-2.75 px-1.5 items-center rounded-lg border-1 border-gray-200">
<div v-if="hasEditPermission" class="p-2 bg-gray-50 gap-2 flex">
<div class="h-14 flex flex-row w-full bg-white py-2.75 px-1.5 items-center rounded-xl border-1 border-gray-200">
<GeneralUserIcon size="base" class="!w-10" />
<a-input
v-model:value="comment"
class="!rounded-lg border-1 bg-white !px-2 !py-2 !border-gray-200 nc-comment-box !outline-none"
class="!rounded-lg border-1 bg-white !px-2.5 !py-2 !border-gray-200 nc-comment-box !outline-none"
placeholder="Start typing..."
:bordered="false"
@keyup.enter.prevent="saveComment"
@ -217,7 +215,7 @@ const processedAudit = (log: string) => {
</div>
</div>
</div>
<div v-else ref="commentsWrapperEl" class="flex flex-col h-full pl-1.5 pr-1 pt-1 nc-scrollbar-md space-y-2">
<div v-else ref="commentsWrapperEl" class="flex flex-col h-full pl-2 pr-1 pt-2 nc-scrollbar-md space-y-2">
<template v-if="audits.length === 0">
<div class="flex flex-col text-center justify-center h-full">
<div class="text-center text-3xl text-gray-600">

32
packages/nc-gui/components/smartsheet/expanded-form/index.vue

@ -367,20 +367,32 @@ export default {
:width="commentsDrawer && isUIAllowed('commentList') ? 'min(80vw,1280px)' : 'min(80vw,1280px)'"
:body-style="{ padding: 0 }"
:closable="false"
size="large"
size="small"
class="nc-drawer-expanded-form"
:class="{ active: isExpanded }"
>
<div class="h-[75vh] xs:(h-[95vh] max-h-full) max-h-215 flex flex-col p-6">
<div class="h-[85vh] xs:(max-h-full) max-h-215 flex flex-col p-6">
<div class="flex h-8 flex-shrink-0 w-full items-center nc-expanded-form-header relative mb-4 justify-between">
<template v-if="!isMobileMode">
<div class="flex gap-3">
<div class="flex gap-2">
<NcButton v-if="props.showNextPrevIcons" type="secondary" class="nc-prev-arrow !w-10" @click="$emit('prev')">
<MdiChevronUp class="text-md text-gray-700" />
<NcButton
v-if="props.showNextPrevIcons"
:disabled="props.firstRow"
type="secondary"
class="nc-prev-arrow !w-10"
@click="$emit('prev')"
>
<MdiChevronUp class="text-md" />
</NcButton>
<NcButton v-if="!props.lastRow" type="secondary" class="nc-next-arrow !w-10" @click="onNext">
<MdiChevronDown class="text-md text-gray-700" />
<NcButton
v-if="props.showNextPrevIcons"
:disabled="props.lastRow"
type="secondary"
class="nc-next-arrow !w-10"
@click="onNext"
>
<MdiChevronDown class="text-md" />
</NcButton>
</div>
<div v-if="displayValue" class="flex items-center truncate max-w-32 font-bold text-gray-800 text-xl">
@ -455,8 +467,8 @@ export default {
</div>
</template>
</div>
<div ref="wrapper" class="flex flex-grow flex-row h-[calc(100%-3rem)] w-full gap-4">
<div class="flex w-full flex-col border-1 rounded-xl overflow-hidden border-gray-200 xs:(border-0 rounded-none)">
<div ref="wrapper" class="flex flex-grow flex-row h-[calc(100%-4rem)] w-full gap-4">
<div class="flex w-2/3 xs:w-full flex-col border-1 rounded-xl overflow-hidden border-gray-200 xs:(border-0 rounded-none)">
<div
class="flex flex-col flex-grow mt-2 h-full max-h-full nc-scrollbar-md !pb-2 items-center w-full bg-white p-4 xs:p-0"
>
@ -543,7 +555,7 @@ export default {
</div>
<div
v-if="isUIAllowed('dataEdit')"
class="w-full h-14 border-t-1 border-gray-200 bg-white flex items-center justify-end p-2 xs:(p-0 mt-4 border-t-0 gap-x-4 justify-between)"
class="w-full h-16 border-t-1 border-gray-200 bg-white flex items-center justify-end p-3 xs:(p-0 mt-4 border-t-0 gap-x-4 justify-between)"
>
<NcDropdown v-if="!isNew && isMobileMode">
<NcButton type="secondary" class="nc-expand-form-more-actions w-10">
@ -598,7 +610,7 @@ export default {
</div>
<div
v-if="!isNew && commentsDrawer && isUIAllowed('commentList')"
class="nc-comments-drawer border-1 relative border-gray-200 w-[380px] bg-gray-50 rounded-xl min-w-0 overflow-hidden h-full xs:hidden"
class="nc-comments-drawer border-1 relative border-gray-200 w-1/3 max-w-125 bg-gray-50 rounded-xl min-w-0 overflow-hidden h-full xs:hidden"
:class="{ active: commentsDrawer && isUIAllowed('commentList') }"
>
<LazySmartsheetExpandedFormComments />

32
packages/nc-gui/components/smartsheet/grid/index.vue

@ -237,23 +237,21 @@ onMounted(() => {
/>
</Suspense>
<Suspense>
<LazySmartsheetExpandedForm
v-if="expandedFormOnRowIdDlg"
:key="routeQuery.rowId"
v-model="expandedFormOnRowIdDlg"
:row="{ row: {}, oldRow: {}, rowMeta: {} }"
:meta="meta"
:state="expandedFormRowState"
:row-id="routeQuery.rowId"
:view="view"
show-next-prev-icons
:first-row="getExpandedRowIndex() === 0"
:last-row="getExpandedRowIndex() === data.length - 1"
@next="navigateToSiblingRow(NavigateDir.NEXT)"
@prev="navigateToSiblingRow(NavigateDir.PREV)"
/>
</Suspense>
<SmartsheetExpandedForm
v-if="expandedFormOnRowIdDlg"
:key="routeQuery.rowId"
v-model="expandedFormOnRowIdDlg"
:row="{ row: {}, oldRow: {}, rowMeta: {} }"
:meta="meta"
:state="expandedFormRowState"
:row-id="routeQuery.rowId"
:view="view"
show-next-prev-icons
:first-row="getExpandedRowIndex() === 0"
:last-row="getExpandedRowIndex() === data.length - 1"
@next="navigateToSiblingRow(NavigateDir.NEXT)"
@prev="navigateToSiblingRow(NavigateDir.PREV)"
/>
<Suspense>
<LazyDlgBulkUpdate

6
packages/nc-gui/components/smartsheet/header/Cell.vue

@ -11,6 +11,8 @@ interface Props {
const props = defineProps<Props>()
const { isMobileMode } = useGlobal()
const hideMenu = toRef(props, 'hideMenu')
const isForm = inject(IsFormInj, ref(false))
@ -42,13 +44,13 @@ const closeAddColumnDropdown = () => {
}
const openHeaderMenu = () => {
if (!isForm.value && !isExpandedForm.value && isUIAllowed('fieldEdit')) {
if (!isForm.value && !isExpandedForm.value && isUIAllowed('fieldEdit') && !isMobileMode.value) {
editColumnDropdown.value = true
}
}
const openDropDown = () => {
if (isForm.value || isExpandedForm.value || !isUIAllowed('fieldEdit')) return
if (isForm.value || isExpandedForm.value || (!isUIAllowed('fieldEdit') && !isMobileMode.value)) return
isDropDownOpen.value = !isDropDownOpen.value
}
</script>

53
packages/nc-gui/components/smartsheet/toolbar/OpenViewSidebarBtn.vue

@ -1,53 +0,0 @@
<script lang="ts" setup>
const { isRightSidebarOpen: _isRightSidebarOpen } = storeToRefs(useSidebarStore())
const isRightSidebarOpen = ref(_isRightSidebarOpen.value)
watch(_isRightSidebarOpen, (val) => {
if (val) {
isRightSidebarOpen.value = true
} else {
setTimeout(() => {
isRightSidebarOpen.value = false
}, 300)
}
})
const onClick = () => {
if (_isRightSidebarOpen.value) return
_isRightSidebarOpen.value = !_isRightSidebarOpen.value
}
</script>
<template>
<NcTooltip
placement="bottomLeft"
hide-on-click
class="transition-all duration-100"
:class="{
'!w-0 !opacity-0': isRightSidebarOpen,
'!w-8 !opacity-100 mr-2': !isRightSidebarOpen,
}"
>
<template #title>
{{
isRightSidebarOpen
? `${$t('general.hide')} ${$t('objects.sidebar').toLowerCase()}`
: `${$t('general.show')} ${$t('objects.sidebar').toLowerCase()}`
}}
</template>
<NcButton
type="text"
size="small"
class="nc-sidebar-right-toggle-icon !text-gray-600 !hover:text-gray-800"
:class="{
'invisible !w-0': isRightSidebarOpen,
}"
@click="onClick"
>
<div class="flex items-center text-inherit">
<GeneralIcon icon="doubleLeftArrow" class="duration-150 transition-all !text-lg -mt-0.25" />
</div>
</NcButton>
</NcTooltip>
</template>

3
packages/nc-gui/lang/en.json

@ -408,7 +408,8 @@
"addRowGrid": "Manually add data in grid view",
"addRowForm": "Enter record data through a form",
"noAccess": "No access",
"restApis": "Rest APIs"
"restApis": "Rest APIs",
"noViews": "No Views"
},
"activity": {
"moveProject": "Move Project",

22
packages/nc-gui/store/sidebar.ts

@ -4,6 +4,7 @@ import { MAX_WIDTH_FOR_MOBILE_MODE } from '~/lib'
export const useSidebarStore = defineStore('sidebarStore', () => {
const { width } = useWindowSize()
const isViewPortMobile = () => width.value < MAX_WIDTH_FOR_MOBILE_MODE
const { isMobileMode } = useGlobal()
const isLeftSidebarOpen = ref(!isViewPortMobile())
const isRightSidebarOpen = ref(true)
@ -15,27 +16,28 @@ export const useSidebarStore = defineStore('sidebarStore', () => {
current: leftSidebarWidthPercent.value,
})
const rightSidebarSize = ref({
old: 17.5,
current: 17.5,
})
const leftSidebarState = ref<
'openStart' | 'openEnd' | 'hiddenStart' | 'hiddenEnd' | 'peekOpenStart' | 'peekOpenEnd' | 'peekCloseOpen' | 'peekCloseEnd'
>(isLeftSidebarOpen.value ? 'openEnd' : 'hiddenEnd')
const rightSidebarState = ref<
'openStart' | 'openEnd' | 'hiddenStart' | 'hiddenEnd' | 'peekOpenStart' | 'peekOpenEnd' | 'peekCloseOpen' | 'peekCloseEnd'
>(isRightSidebarOpen.value ? 'openEnd' : 'hiddenEnd')
const mobileNormalizedSidebarSize = computed(() => {
if (isMobileMode.value) {
return isLeftSidebarOpen.value ? 100 : 0
}
return leftSideBarSize.value.current
})
const leftSidebarWidth = computed(() => (width.value * mobileNormalizedSidebarSize.value) / 100)
return {
isLeftSidebarOpen,
isRightSidebarOpen,
rightSidebarSize,
leftSidebarWidthPercent,
leftSideBarSize,
leftSidebarState,
rightSidebarState,
leftSidebarWidth,
mobileNormalizedSidebarSize,
}
})

9
tests/playwright/pages/Dashboard/Form/index.ts

@ -244,15 +244,6 @@ export class FormPage extends BasePage {
async verifyStatePostSubmit(param: { message?: string; submitAnotherForm?: boolean; showBlankForm?: boolean }) {
if (undefined !== param.message) {
let retryCounter = 0;
while (retryCounter <= 5) {
const msg = await this.getFormAfterSubmit().innerText();
if (msg.includes('Form submitted successfully')) {
break;
}
await this.rootPage.waitForTimeout(100 * retryCounter);
retryCounter++;
}
await expect(this.getFormAfterSubmit()).toContainText(param.message);
}
if (true === param.submitAnotherForm) {

4
tests/playwright/pages/Dashboard/Kanban/index.ts

@ -100,9 +100,13 @@ export class KanbanPage extends BasePage {
async verifyCardOrder(param: { order: string[]; stackIndex: number }) {
const { order, stackIndex } = param;
const stack = this.get().locator(`.nc-kanban-stack`).nth(stackIndex);
for (let i = 0; i < order.length; i++) {
const card = stack.locator(`.nc-kanban-item`).nth(i);
await (await card.elementHandle())?.waitForElementState('stable');
await card.scrollIntoViewIfNeeded();
const cardTitle = card.locator(`.nc-cell`);
await expect(cardTitle).toHaveText(order[i]);

19
tests/playwright/pages/Dashboard/common/LeftSidebar/index.ts

@ -1,4 +1,4 @@
import { Locator } from '@playwright/test';
import { expect, Locator } from '@playwright/test';
import { DashboardPage } from '../../index';
import BasePage from '../../../Base';
import { getTextExcludeIconText } from '../../../../tests/utils/general';
@ -20,7 +20,7 @@ export class LeftSidebarPage extends BasePage {
super(dashboard.rootPage);
this.dashboard = dashboard;
this.btn_workspace = this.get().locator('.nc-sidebar-header');
this.btn_workspace = this.get().locator('.nc-workspace-menu');
this.btn_newProject = this.get().locator('[data-testid="nc-sidebar-create-project-btn"]');
this.btn_cmdK = this.get().locator('[data-testid="nc-sidebar-search-btn"]');
this.btn_teamAndSettings = this.get().locator('[data-testid="nc-sidebar-team-settings-btn"]');
@ -57,6 +57,10 @@ export class LeftSidebarPage extends BasePage {
return await this.btn_workspace.getAttribute('data-workspace-title');
}
async verifyWorkspaceName({ title }: { title: string }) {
await expect(this.btn_workspace.locator('.nc-workspace-title')).toHaveText(title);
}
async createWorkspace({ title }: { title: string }) {
await this.clickWorkspace();
await this.modal_workspace.locator('.ant-dropdown-menu-item:has-text("Create New Workspace")').waitFor();
@ -69,6 +73,13 @@ export class LeftSidebarPage extends BasePage {
await inputModal.locator('button.ant-btn-primary').click();
}
async verifyWorkspaceCount({ count }: { count: number }) {
await this.clickWorkspace();
// TODO: THere is one extra html attribute
await expect(this.rootPage.getByTestId('nc-workspace-list')).toHaveCount(count + 1);
}
async getWorkspaceList() {
const ws = [];
await this.clickWorkspace();
@ -88,6 +99,8 @@ export class LeftSidebarPage extends BasePage {
await this.clickWorkspace();
const nodes = this.modal_workspace.locator('[data-testid="nc-workspace-list"]');
await this.rootPage.waitForTimeout(2000);
for (let i = 0; i < (await nodes.count()); i++) {
const text = await getTextExcludeIconText(nodes.nth(i));
if (text.toLowerCase() === param.title.toLowerCase()) {
@ -96,5 +109,7 @@ export class LeftSidebarPage extends BasePage {
}
}
await this.rootPage.keyboard.press('Escape');
await this.rootPage.waitForTimeout(3500);
}
}

10
tests/playwright/pages/Dashboard/common/WorkspaceMenu/index.ts

@ -17,6 +17,16 @@ export class WorkspaceMenuObject extends BasePage {
await this.rootPage.locator('[data-testid="nc-workspace-menu"]').click();
}
async switchWorkspace({ workspaceTitle }: { workspaceTitle: string }) {
await this.toggle();
await this.rootPage.waitForTimeout(2500);
await this.rootPage.getByTestId('nc-workspace-list').getByText(workspaceTitle).click({
force: true,
});
await this.rootPage.keyboard.press('Escape');
await this.rootPage.waitForTimeout(4000);
}
async click({ menu, subMenu }: { menu: string; subMenu: string }) {
const pMenu = this.rootPage.locator(`.nc-dropdown-workspace-menu:visible`);
await pMenu.locator(`div.nc-workspace-menu-item:has-text("${menu}"):visible`).click();

3
tests/playwright/pages/Dashboard/index.ts

@ -189,8 +189,11 @@ export class DashboardPage extends BasePage {
async signOut() {
await this.sidebar.userMenu.click();
await this.rootPage.waitForTimeout(1000);
await this.rootPage.getByTestId('nc-sidebar-user-logout').waitFor({ state: 'visible' });
await this.sidebar.userMenu.clickLogout();
await this.rootPage.waitForTimeout(1000);
await this.rootPage.locator('[data-testid="nc-form-signin"]:visible').waitFor();
await new Promise(resolve => setTimeout(resolve, 150));

8
tests/playwright/tests/db/columns/columnAttachments.spec.ts

@ -31,6 +31,9 @@ test.describe('Attachment column', () => {
columnHeader: 'testAttach',
filePath: filepath,
});
await dashboard.rootPage.waitForTimeout(500);
await dashboard.grid.cell.attachment.verifyFile({
index: i,
columnHeader: 'testAttach',
@ -41,6 +44,9 @@ test.describe('Attachment column', () => {
columnHeader: 'testAttach',
filePath: [`${process.cwd()}/fixtures/sampleFiles/sampleImage.jpeg`],
});
await dashboard.rootPage.waitForTimeout(1000);
await dashboard.grid.cell.attachment.verifyFile({
index: 4,
columnHeader: 'testAttach',
@ -74,7 +80,7 @@ test.describe('Attachment column', () => {
filePath: [`${process.cwd()}/fixtures/sampleFiles/1.json`],
});
await sharedForm.rootPage.waitForTimeout(500);
await sharedForm.rootPage.waitForTimeout(1000);
await sharedForm.submit();
await sharedForm.verifySuccessMessage();
await newPage.close();

16
tests/playwright/tests/db/features/baseShare.spec.ts

@ -1,15 +1,16 @@
import { test } from '@playwright/test';
import { DashboardPage } from '../../../pages/Dashboard';
import setup, { unsetup } from '../../../setup';
import setup, { NcContext, unsetup } from '../../../setup';
import { ToolbarPage } from '../../../pages/Dashboard/common/Toolbar';
import { LoginPage } from '../../../pages/LoginPage';
import { getDefaultPwd } from '../../../tests/utils/general';
import { isEE } from '../../../setup/db';
// To be enabled after shared base is implemented
test.describe('Shared base', () => {
let dashboard: DashboardPage;
let toolbar: ToolbarPage;
let context: any;
let context: NcContext;
let loginPage: LoginPage;
async function roleTest(role: string) {
@ -83,8 +84,17 @@ test.describe('Shared base', () => {
withoutPrefix: true,
});
// await dashboard.treeView.openProject({ title: context.project.title });
await dashboard.rootPage.waitForTimeout(1000);
if (isEE()) {
await dashboard.grid.workspaceMenu.switchWorkspace({
workspaceTitle: context.workspace.title,
});
}
await dashboard.treeView.openProject({ title: context.project.title, context });
await dashboard.treeView.openTable({ title: 'Country' });
url = await dashboard.grid.topbar.getSharedBaseUrl({ role: 'viewer', enableSharedBase: false });
await dashboard.rootPage.waitForTimeout(2000);

2
tests/playwright/tests/db/features/verticalFillHandle.spec.ts

@ -212,7 +212,7 @@ test.describe('Fill Handle', () => {
await unsetup(p.context);
});
test('Miscellaneous (Checkbox, attachment) @flaky', async () => {
test('Miscellaneous (Checkbox, attachment)', async () => {
const fields = [
{ title: 'Checkbox', value: 'true', type: 'checkbox' },
{ title: 'Attachment', value: `${process.cwd()}/fixtures/sampleFiles/1.json`, type: 'attachment' },

Loading…
Cancel
Save