mirror of https://github.com/nocodb/nocodb
Rohit T P
5 months ago
230 changed files with 9346 additions and 3985 deletions
@ -0,0 +1,55 @@
|
||||
name: Run BATS Tests |
||||
|
||||
on: |
||||
push: |
||||
paths: |
||||
- 'docker-compose/setup-script/noco.sh' |
||||
workflow_dispatch: |
||||
|
||||
jobs: |
||||
prepare: |
||||
runs-on: ubuntu-latest |
||||
outputs: |
||||
matrix: ${{ steps.set-matrix.outputs.matrix }} |
||||
steps: |
||||
- name: Checkout code |
||||
uses: actions/checkout@v4 |
||||
|
||||
- name: Install jq |
||||
run: | |
||||
sudo apt-get update |
||||
sudo apt-get install -y jq |
||||
|
||||
- name: Prepare matrix for test files |
||||
id: set-matrix |
||||
run: | |
||||
BATS_FILES=$(find docker-compose/setup-script/tests -name '*.bats') |
||||
MATRIX_JSON=$(echo $BATS_FILES | jq -Rsc 'split("\n") | map(select(. != ""))') |
||||
echo "matrix=$MATRIX_JSON" >> $GITHUB_ENV |
||||
|
||||
test: |
||||
needs: prepare |
||||
runs-on: ubuntu-latest |
||||
strategy: |
||||
fail-fast: false |
||||
matrix: |
||||
test: ${{fromJson(env.matrix)}} |
||||
steps: |
||||
- name: Checkout repository |
||||
uses: actions/checkout@v4 |
||||
|
||||
- name: Install BATS |
||||
run: | |
||||
sudo apt-get update |
||||
sudo apt-get install -y bats expect |
||||
|
||||
- name: Get working directory |
||||
run: | |
||||
WORKING_DIR="$(pwd)/docker-compose/setup-script/tests" |
||||
echo "WORKING_DIR=$WORKING_DIR" >> $GITHUB_ENV |
||||
|
||||
- name: Run BATS test |
||||
run: bats ${{ matrix.test }} |
||||
env: |
||||
WORKING_DIR: ${{ env.WORKING_DIR }} |
||||
SKIP_TARE_DOWN: true |
After Width: | Height: | Size: 377 B |
After Width: | Height: | Size: 597 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 732 B |
After Width: | Height: | Size: 257 B |
@ -0,0 +1,32 @@
|
||||
<script setup lang="ts"> |
||||
const { header, field, toggleSort } = defineProps<{ |
||||
header: string |
||||
activeSort: { field?: string; direction?: string } |
||||
field: UsersSortType['field'] |
||||
toggleSort: Function |
||||
}>() |
||||
</script> |
||||
|
||||
<template> |
||||
<div class="flex items-center space-x-2 cursor-pointer text-gray-700" @click="toggleSort(field)"> |
||||
<span> |
||||
{{ header }} |
||||
</span> |
||||
<div class="flex flex-col"> |
||||
<GeneralIcon |
||||
icon="arrowDropUp" |
||||
class="text-sm mb-[-10px] text-[16px]" |
||||
:class="{ |
||||
'text-primary': activeSort.field === field && activeSort.direction === 'asc', |
||||
}" |
||||
/> |
||||
<GeneralIcon |
||||
icon="arrowDropDown" |
||||
class="text-sm text-[16px]" |
||||
:class="{ |
||||
'text-primary': activeSort.field === field && activeSort.direction === 'desc', |
||||
}" |
||||
/> |
||||
</div> |
||||
</div> |
||||
</template> |
@ -1,79 +0,0 @@
|
||||
<script lang="ts" setup> |
||||
import { iconMap } from '#imports' |
||||
import type { UsersSortType } from '~/lib' |
||||
|
||||
const { field, direction, handleUserSort } = defineProps<{ |
||||
field: UsersSortType['field'] |
||||
direction?: UsersSortType['direction'] |
||||
handleUserSort: Function |
||||
}>() |
||||
|
||||
const isOpen = ref(false) |
||||
|
||||
const sortUserBy = (direction?: UsersSortType['direction']) => { |
||||
handleUserSort({ |
||||
field, |
||||
direction, |
||||
}) |
||||
isOpen.value = false |
||||
} |
||||
</script> |
||||
|
||||
<template> |
||||
<a-dropdown |
||||
v-model:visible="isOpen" |
||||
:trigger="['click']" |
||||
placement="bottomLeft" |
||||
overlay-class-name="nc-user-menu-column-operations !border-1 rounded-lg !shadow-xl" |
||||
@click.stop="isOpen = !isOpen" |
||||
> |
||||
<div> |
||||
<GeneralIcon |
||||
:icon="direction === 'asc' || direction === 'desc' ? 'sortDesc' : 'arrowDown'" |
||||
class="text-grey h-full text-grey nc-user-menu-trigger cursor-pointer outline-0 mr-2 transition-none" |
||||
:style="{ transform: direction === 'asc' ? 'rotate(180deg)' : undefined }" |
||||
/> |
||||
</div> |
||||
<template #overlay> |
||||
<NcMenu class="flex flex-col gap-1 border-gray-200 nc-user-menu-column-options"> |
||||
<NcMenuItem @click="sortUserBy('asc')"> |
||||
<div class="nc-column-insert-after nc-user-menu-item"> |
||||
<component |
||||
:is="iconMap.sortDesc" |
||||
class="text-gray-700 !rotate-180 !w-4.25 !h-4.25" |
||||
:style="{ |
||||
transform: 'rotate(180deg)', |
||||
}" |
||||
/> |
||||
|
||||
<!-- Sort Ascending --> |
||||
{{ $t('general.sortAsc') }} |
||||
</div> |
||||
</NcMenuItem> |
||||
<NcMenuItem @click="sortUserBy('desc')"> |
||||
<div class="nc-column-insert-before nc-user-menu-item"> |
||||
<component :is="iconMap.sortDesc" class="text-gray-700 !w-4.25 !h-4.25 ml-0.5 mr-0.25" /> |
||||
<!-- Sort Descending --> |
||||
{{ $t('general.sortDesc') }} |
||||
</div> |
||||
</NcMenuItem> |
||||
</NcMenu> |
||||
</template> |
||||
</a-dropdown> |
||||
</template> |
||||
|
||||
<style scoped> |
||||
.nc-user-menu-item { |
||||
@apply flex items-center gap-2; |
||||
} |
||||
|
||||
.nc-user-menu-column-options { |
||||
.nc-icons { |
||||
@apply !w-5 !h-5; |
||||
} |
||||
} |
||||
|
||||
:deep(.ant-dropdown-menu-item) { |
||||
@apply !hover:text-black text-gray-700; |
||||
} |
||||
</style> |
@ -0,0 +1,3 @@
|
||||
<template> |
||||
<span></span> |
||||
</template> |
@ -1,54 +0,0 @@
|
||||
<script lang="ts" setup> |
||||
const props = defineProps<{ |
||||
visible: boolean |
||||
workspaceId: string |
||||
}>() |
||||
|
||||
const emits = defineEmits(['update:visible']) |
||||
const visible = useVModel(props, 'visible', emits) |
||||
|
||||
const workspaceStore = useWorkspace() |
||||
|
||||
const { deleteWorkspace: _deleteWorkspace, loadWorkspaces, navigateToWorkspace } = workspaceStore |
||||
|
||||
const { workspaces, workspacesList } = storeToRefs(workspaceStore) |
||||
|
||||
const { refreshCommandPalette } = useCommandPalette() |
||||
|
||||
const workspace = computed(() => workspaces.value.get(props.workspaceId)) |
||||
|
||||
const onDelete = async () => { |
||||
if (!workspace.value) return |
||||
|
||||
try { |
||||
await _deleteWorkspace(workspace.value.id!) |
||||
await loadWorkspaces() |
||||
|
||||
if (!workspacesList.value?.[0]?.id) { |
||||
return await navigateToWorkspace() |
||||
} |
||||
|
||||
await navigateToWorkspace(workspacesList.value?.[0]?.id) |
||||
} catch (e: any) { |
||||
message.error(await extractSdkResponseErrorMsg(e)) |
||||
} finally { |
||||
refreshCommandPalette() |
||||
} |
||||
} |
||||
</script> |
||||
|
||||
<template> |
||||
<GeneralDeleteModal v-model:visible="visible" :entity-name="$t('objects.workspace')" :on-delete="onDelete"> |
||||
<template #entity-preview> |
||||
<div v-if="workspace" class="flex flex-row items-center py-2.25 px-2.75 bg-gray-50 rounded-lg text-gray-700 mb-4"> |
||||
<GeneralIcon icon="workspace" /> |
||||
<div |
||||
class="capitalize text-ellipsis overflow-hidden select-none w-full pl-2.25" |
||||
:style="{ wordBreak: 'keep-all', whiteSpace: 'nowrap', display: 'inline' }" |
||||
> |
||||
{{ workspace.title }} |
||||
</div> |
||||
</div> |
||||
</template> |
||||
</GeneralDeleteModal> |
||||
</template> |
@ -0,0 +1,26 @@
|
||||
<script setup lang="ts"> |
||||
import { useCopy } from '~/composables/useCopy' |
||||
|
||||
const props = defineProps<{ |
||||
content?: string |
||||
timeout?: number |
||||
}>() |
||||
|
||||
const { copy } = useCopy() |
||||
const copied = ref(false) |
||||
|
||||
const copyContent = async () => { |
||||
await copy(props.content || '') |
||||
copied.value = true |
||||
setTimeout(() => { |
||||
copied.value = false |
||||
}, props.timeout || 2000) |
||||
} |
||||
</script> |
||||
|
||||
<template> |
||||
<NcButton size="xsmall" type="text" @click="copyContent"> |
||||
<MdiCheck v-if="copied" class="h-3.5" /> |
||||
<component :is="iconMap.copy" v-else class="text-gray-800" /> |
||||
</NcButton> |
||||
</template> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,85 @@
|
||||
<script setup lang="ts"> |
||||
import { ref } from 'vue' |
||||
|
||||
interface Props { |
||||
isOpen: boolean |
||||
} |
||||
|
||||
const props = withDefaults(defineProps<Props>(), { |
||||
isOpen: false, |
||||
}) |
||||
|
||||
const emits = defineEmits(['update:isOpen']) |
||||
|
||||
const isOpen = useVModel(props, 'isOpen', emits) |
||||
|
||||
const ncLinksDropdownRef = ref<HTMLDivElement>() |
||||
|
||||
const randomClass = `link-records_${Math.floor(Math.random() * 99999)}` |
||||
|
||||
const addOrRemoveClass = (add: boolean = false) => { |
||||
const dropdownRoot = ncLinksDropdownRef.value?.parentElement?.parentElement?.parentElement?.parentElement as HTMLElement |
||||
if (dropdownRoot) { |
||||
if (add) { |
||||
dropdownRoot.classList.add('inset-0', 'nc-link-dropdown-root', `nc-root-${randomClass}`) |
||||
} else { |
||||
dropdownRoot.classList.remove('inset-0', 'nc-link-dropdown-root', `nc-root-${randomClass}`) |
||||
} |
||||
} |
||||
} |
||||
|
||||
watch( |
||||
isOpen, |
||||
(next) => { |
||||
if (next) { |
||||
onClickOutside(document.querySelector(`.${randomClass}`)! as HTMLDivElement, (e) => { |
||||
const targetEl = e?.target as HTMLElement |
||||
if (!targetEl?.classList.contains(`nc-root-${randomClass}`) || targetEl?.closest(`.nc-${randomClass}`)) { |
||||
return |
||||
} |
||||
isOpen.value = false |
||||
|
||||
addOrRemoveClass(false) |
||||
}) |
||||
} else { |
||||
addOrRemoveClass(false) |
||||
} |
||||
}, |
||||
{ flush: 'post' }, |
||||
) |
||||
|
||||
watch([ncLinksDropdownRef, isOpen], () => { |
||||
if (!ncLinksDropdownRef.value) return |
||||
|
||||
if (isOpen.value) { |
||||
addOrRemoveClass(true) |
||||
} else { |
||||
addOrRemoveClass(false) |
||||
} |
||||
}) |
||||
</script> |
||||
|
||||
<template> |
||||
<NcDropdown |
||||
:visible="isOpen" |
||||
placement="bottom" |
||||
overlay-class-name="nc-links-dropdown !min-w-[540px]" |
||||
:class="`.nc-${randomClass}`" |
||||
> |
||||
<slot /> |
||||
<template #overlay> |
||||
<div ref="ncLinksDropdownRef" class="h-[412px] w-[540px]" :class="`${randomClass}`"> |
||||
<slot name="overlay" /> |
||||
</div> |
||||
</template> |
||||
</NcDropdown> |
||||
</template> |
||||
|
||||
<style lang="scss"> |
||||
.nc-links-dropdown { |
||||
z-index: 1000 !important; |
||||
} |
||||
.nc-link-dropdown-root { |
||||
z-index: 1000; |
||||
} |
||||
</style> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue