Browse Source

fix: revise undo/redo scopes

Signed-off-by: mertmit <mertmit99@gmail.com>
pull/5332/head
mertmit 2 years ago
parent
commit
565af37583
  1. 4
      packages/nc-gui/components/dlg/TableRename.vue
  2. 4
      packages/nc-gui/components/smartsheet/Kanban.vue
  3. 10
      packages/nc-gui/components/smartsheet/header/Menu.vue
  4. 8
      packages/nc-gui/components/smartsheet/sidebar/MenuTop.vue
  5. 12
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  6. 4
      packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue
  7. 6
      packages/nc-gui/composables/useExpandedFormStore.ts
  8. 4
      packages/nc-gui/composables/useGridViewColumnWidth.ts
  9. 8
      packages/nc-gui/composables/useKanbanViewStore.ts
  10. 6
      packages/nc-gui/composables/useLTARStore.ts
  11. 114
      packages/nc-gui/composables/useUndoRedo.ts
  12. 8
      packages/nc-gui/composables/useViewData.ts
  13. 2
      packages/nc-gui/lib/types.ts

4
packages/nc-gui/components/dlg/TableRename.vue

@ -44,7 +44,7 @@ const projectStore = useProject()
const { loadTables, isMysql, isMssql, isPg } = projectStore
const { tables, project } = storeToRefs(projectStore)
const { addUndo } = useUndoRedo()
const { addUndo, defineProjectScope } = useUndoRedo()
const inputEl = $ref<ComponentPublicInstance>()
@ -145,7 +145,7 @@ const renameTable = async (undo = false) => {
},
args: [tableMeta.title],
},
scope: tableMeta.project_id,
scope: defineProjectScope({ model: tableMeta }),
})
}

4
packages/nc-gui/components/smartsheet/Kanban.vue

@ -85,7 +85,7 @@ const { isUIAllowed } = useUIPermission()
const { appInfo } = $(useGlobal())
const { addUndo } = useUndoRedo()
const { addUndo, defineViewScope } = useUndoRedo()
provide(IsFormInj, ref(false))
@ -244,7 +244,7 @@ async function onMoveStack(event: any, undo = false) {
},
args: [{ moved: { oldIndex, newIndex } }, true],
},
scope: view.value?.title,
scope: defineViewScope({ view: view.value }),
})
}
}

10
packages/nc-gui/components/smartsheet/header/Menu.vue

@ -20,7 +20,7 @@ import {
useSmartsheetStoreOrThrow,
useUndoRedo,
} from '#imports'
import { UndoRedoAction } from '~~/lib';
import type { UndoRedoAction } from '~~/lib'
const { virtual = false } = defineProps<{ virtual?: boolean }>()
@ -44,7 +44,7 @@ const { t } = useI18n()
const { getMeta } = useMetas()
const { addUndo } = useUndoRedo()
const { addUndo, defineModelScope, defineViewScope } = useUndoRedo()
const deleteColumn = () =>
Modal.confirm({
@ -113,7 +113,7 @@ const setAsDisplayValue = async () => {
},
args: [currentDisplayValue?.id],
},
scope: meta.value?.id,
scope: defineModelScope({ model: meta.value }),
})
} catch (e) {
message.error(t('msg.error.primaryColumnUpdateFailed'))
@ -151,7 +151,7 @@ const sortByColumn = async (direction: 'asc' | 'desc') => {
},
args: [data.id],
},
scope: view.value?.title,
scope: defineViewScope({ view: view.value }),
})
eventBus.emit(SmartsheetStoreEvents.SORT_RELOAD)
@ -287,7 +287,7 @@ const hideField = async () => {
},
args: [currentColumn!.id],
},
scope: view.value?.title,
scope: defineViewScope({ view: view.value }),
})
}
</script>

8
packages/nc-gui/components/smartsheet/sidebar/MenuTop.vue

@ -47,7 +47,7 @@ const { api } = useApi()
const router = useRouter()
const { addUndo } = useUndoRedo()
const { addUndo, defineModelScope } = useUndoRedo()
/** Selected view(s) for menu */
const selected = ref<string[]>([])
@ -87,6 +87,8 @@ function validate(view: ViewType) {
return true
}
let sortable: Sortable
function onSortStart(evt: SortableEvent) {
evt.stopImmediatePropagation()
evt.preventDefault()
@ -138,8 +140,6 @@ async function onSortEnd(evt: SortableEvent) {
$e('a:view:reorder')
}
let sortable: Sortable
const initSortable = (el: HTMLElement) => {
if (sortable) sortable.destroy()
@ -199,7 +199,7 @@ async function onRename(view: ViewType, originalTitle?: string, undo = false) {
},
args: [view, originalTitle],
},
scope: activeView.value?.fk_model_id,
scope: defineModelScope({ view: activeView.value }),
})
}

12
packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue

@ -57,7 +57,7 @@ const {
const { eventBus } = useSmartsheetStoreOrThrow()
const { addUndo } = useUndoRedo()
const { addUndo, defineViewScope } = useUndoRedo()
eventBus.on((event) => {
if (event === SmartsheetStoreEvents.FIELD_RELOAD) {
@ -117,7 +117,7 @@ const onMove = (_event: { moved: { newIndex: number; oldIndex: number } }, undo
},
args: [],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
}
@ -220,7 +220,7 @@ const toggleFieldVisibility = (e: CheckboxChangeEvent, field: any, index: number
},
args: [e.target.checked],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
saveOrUpdate(field, index)
}
@ -239,7 +239,7 @@ const toggleSystemFields = (e: CheckboxChangeEvent) => {
},
args: [e.target.checked],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
}
@ -257,7 +257,7 @@ const onShowAll = () => {
},
args: [],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
showAll()
}
@ -276,7 +276,7 @@ const onHideAll = () => {
},
args: [],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
hideAll()
}

4
packages/nc-gui/components/smartsheet/toolbar/RowHeight.vue

@ -12,7 +12,7 @@ const isLocked = inject(IsLockedInj, ref(false))
const { $api } = useNuxtApp()
const { addUndo } = useUndoRedo()
const { addUndo, defineViewScope } = useUndoRedo()
const open = ref(false)
@ -30,7 +30,7 @@ const updateRowHeight = async (rh: number, undo = false) => {
fn: (r: number) => updateRowHeight(r, true),
args: [(view.value.view as GridType).row_height || 0],
},
scope: view.value?.title,
scope: defineViewScope({ view: view.value }),
})
}

6
packages/nc-gui/composables/useExpandedFormStore.ts

@ -52,7 +52,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
const { sharedView } = useSharedView()
const { addUndo, clone } = useUndoRedo()
const { addUndo, clone, defineViewScope } = useUndoRedo()
const reloadTrigger = inject(ReloadRowDataHookInj, createEventHook())
@ -198,7 +198,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
},
args: [id],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
}
@ -250,7 +250,7 @@ const [useProvideExpandedFormStore, useExpandedFormStore] = useInjectionState((m
},
args: [id, clone(undoObject)],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
}

4
packages/nc-gui/composables/useGridViewColumnWidth.ts

@ -22,7 +22,7 @@ export function useGridViewColumnWidth(view: Ref<ViewType | undefined>) {
const { metas } = useMetas()
const { addUndo } = useUndoRedo()
const { addUndo, defineViewScope } = useUndoRedo()
const gridViewCols = ref<Record<string, GridColumnType>>({})
const resizingCol = ref('')
@ -78,7 +78,7 @@ export function useGridViewColumnWidth(view: Ref<ViewType | undefined>) {
fn: (w: string) => updateWidth(id, w, true),
args: [gridViewCols.value[id].width],
},
scope: view.value?.title,
scope: defineViewScope({ view: view.value }),
})
}

8
packages/nc-gui/composables/useKanbanViewStore.ts

@ -60,7 +60,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
const { search } = useFieldQuery()
const { addUndo, clone } = useUndoRedo()
const { addUndo, clone, defineViewScope } = useUndoRedo()
// save history of stack changes for undo/redo
const moveHistory = ref<{ op: 'added' | 'removed'; pk: string; stack: string; index: number }[]>([])
@ -367,7 +367,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
},
args: [id],
},
scope: viewMeta.value?.title,
scope: defineViewScope({ view: viewMeta.value as ViewType }),
})
formattedData.value.get(null)?.splice(rowIndex ?? 0, 1, {
@ -444,7 +444,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
},
args: [clone(toUpdate), property],
},
scope: viewMeta.value?.title,
scope: defineViewScope({ view: viewMeta.value as ViewType }),
})
/** update row data(to sync formula and other related columns) */
@ -650,7 +650,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
},
args: [clone(row)],
},
scope: viewMeta.value?.title,
scope: defineViewScope({ view: viewMeta.value as ViewType }),
})
}

6
packages/nc-gui/composables/useLTARStore.ts

@ -45,7 +45,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
const activeView = inject(ActiveViewInj, ref())
const { addUndo, clone } = useUndoRedo()
const { addUndo, clone, defineViewScope } = useUndoRedo()
const sharedViewPassword = inject(SharedViewPasswordInj, ref(null))
@ -286,7 +286,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
fn: (row: Record<string, any>) => link(row, {}, true),
args: [clone(row)],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
}
} catch (e: any) {
@ -332,7 +332,7 @@ const [useProvideLTARStore, useLTARStore] = useInjectionState(
fn: (row: Record<string, any>) => unlink(row, {}, true),
args: [clone(row)],
},
scope: activeView.value?.title,
scope: defineViewScope({ view: activeView.value }),
})
}
} catch (e: any) {

114
packages/nc-gui/composables/useUndoRedo.ts

@ -1,5 +1,6 @@
import type { Ref } from 'vue'
import rfdc from 'rfdc'
import type { ProjectType, TableType, ViewType } from 'nocodb-sdk'
import { createSharedComposable, ref, useRouter } from '#imports'
import type { UndoRedoAction } from '~/lib'
@ -10,33 +11,37 @@ export const useUndoRedo = createSharedComposable(() => {
const route = $(router.currentRoute)
const activeView = inject(ActiveViewInj, ref())
const scope = computed<string[]>(() => {
let tempScope = ['root']
for (const param of Object.values(route.params)) {
// keys: projectType | projectId | type | title | viewTitle
const scope = computed<{ key: string; param: string }[]>(() => {
const tempScope: { key: string; param: string }[] = [{ key: 'root', param: 'root' }]
for (const [key, param] of Object.entries(route.params)) {
if (Array.isArray(param)) {
tempScope = tempScope.concat(param)
tempScope.push({ key, param: param.join(',') })
} else {
tempScope.push(param)
tempScope.push({ key, param })
}
}
// if the current view is the default view, add it to the scope (as viewTitle might be missing)
if (activeView.value?.is_default) {
tempScope.push(activeView.value.title)
}
return tempScope
})
const isSameScope = (sc: { key: string; param: string }[]) => {
return sc.every((s) => {
return scope.value.some(
// viewTitle is optional for default view
(s2) =>
(s.key === 'viewTitle' && s2.key === 'viewTitle' && s2.param === '') || (s.key === s2.key && s.param === s2.param),
)
})
}
const undoQueue: Ref<UndoRedoAction[]> = ref([])
const redoQueue: Ref<UndoRedoAction[]> = ref([])
const addUndo = (action: UndoRedoAction, fromRedo = false) => {
// remove all redo actions that are in the same scope
if (!fromRedo) redoQueue.value = redoQueue.value.filter((a) => a.scope !== action.scope)
if (!fromRedo) redoQueue.value = redoQueue.value.filter((a) => !isSameScope(a.scope || []))
undoQueue.value.push(action)
}
@ -47,16 +52,10 @@ export const useUndoRedo = createSharedComposable(() => {
const undo = async () => {
let actionIndex = -1
for (let i = undoQueue.value.length - 1; i >= 0; i--) {
if (Array.isArray(undoQueue.value[i].scope)) {
if (scope.value.some((s) => undoQueue.value[i].scope?.includes(s))) {
actionIndex = i
break
}
} else {
if (scope.value.includes((undoQueue.value[i].scope as string) || 'root')) {
actionIndex = i
break
}
const elScope = undoQueue.value[i].scope || [{ key: 'root', param: 'root' }]
if (isSameScope(elScope)) {
actionIndex = i
break
}
}
@ -76,16 +75,10 @@ export const useUndoRedo = createSharedComposable(() => {
const redo = async () => {
let actionIndex = -1
for (let i = redoQueue.value.length - 1; i >= 0; i--) {
if (Array.isArray(redoQueue.value[i].scope)) {
if (scope.value.some((s) => redoQueue.value[i].scope?.includes(s))) {
actionIndex = i
break
}
} else {
if (scope.value.includes((redoQueue.value[i].scope as string) || 'root')) {
actionIndex = i
break
}
const elScope = redoQueue.value[i].scope || [{ key: 'root', param: 'root' }]
if (isSameScope(elScope)) {
actionIndex = i
break
}
}
@ -102,6 +95,57 @@ export const useUndoRedo = createSharedComposable(() => {
}
}
const defineRootScope = () => {
return [{ key: 'root', param: 'root' }]
}
const defineProjectScope = (param: { project?: ProjectType; model?: TableType; view?: ViewType; project_id?: string }) => {
if (param.project) {
return [{ key: 'projectId', param: param.project.id! }]
} else if (param.model) {
return [{ key: 'projectId', param: param.model.project_id! }]
} else if (param.view) {
return [{ key: 'projectId', param: param.view.project_id! }]
} else {
return [{ key: 'projectId', param: param.project_id! }]
}
}
const defineModelScope = (param: { model?: TableType; view?: ViewType; project_id?: string; model_id?: string }) => {
if (param.model) {
return [
{ key: 'projectId', param: param.model.project_id! },
{ key: 'title', param: param.model.id! },
]
} else if (param.view) {
return [
{ key: 'projectId', param: param.view.project_id! },
{ key: 'title', param: param.view.fk_model_id! },
]
} else {
return [
{ key: 'projectId', param: param.project_id! },
{ key: 'title', param: param.model_id! },
]
}
}
const defineViewScope = (param: { view?: ViewType; project_id?: string; model_id?: string; title?: string }) => {
if (param.view) {
return [
{ key: 'projectId', param: param.view.project_id! },
{ key: 'title', param: param.view.fk_model_id! },
{ key: 'viewTitle', param: param.view.title! },
]
} else {
return [
{ key: 'projectId', param: param.project_id! },
{ key: 'title', param: param.model_id! },
{ key: 'viewTitle', param: param.title! },
]
}
}
useEventListener(document, 'keydown', async (e: KeyboardEvent) => {
const cmdOrCtrl = isMac() ? e.metaKey : e.ctrlKey
if (cmdOrCtrl && !e.altKey) {
@ -128,5 +172,9 @@ export const useUndoRedo = createSharedComposable(() => {
addUndo,
undo,
clone,
defineRootScope,
defineProjectScope,
defineModelScope,
defineViewScope,
}
})

8
packages/nc-gui/composables/useViewData.ts

@ -56,7 +56,7 @@ export function useViewData(
const { getMeta } = useMetas()
const { addUndo, clone } = useUndoRedo()
const { addUndo, clone, defineViewScope } = useUndoRedo()
const appInfoDefaultLimit = appInfo.defaultLimit || 25
@ -303,7 +303,7 @@ export function useViewData(
},
args: [id],
},
scope: viewMeta.value?.title,
scope: defineViewScope({ view: viewMeta.value }),
})
Object.assign(currentRow, {
@ -402,7 +402,7 @@ export function useViewData(
},
args: [clone(toUpdate), property, { page: paginationData.value.page, pageSize: paginationData.value.pageSize }],
},
scope: viewMeta.value?.title,
scope: defineViewScope({ view: viewMeta.value }),
})
/** update row data(to sync formula and other related columns)
@ -534,7 +534,7 @@ export function useViewData(
},
args: [clone(row), {}, { page: paginationData.value.page, pageSize: paginationData.value.pageSize }],
},
scope: viewMeta.value?.title,
scope: defineViewScope({ view: viewMeta.value }),
})
}

2
packages/nc-gui/lib/types.ts

@ -108,5 +108,5 @@ export type Nullable<T> = { [K in keyof T]: T[K] | null }
export interface UndoRedoAction {
undo: { fn: Function; args: any[] }
redo: { fn: Function; args: any[] }
scope?: string | string[]
scope?: { key: string; param: string }[]
}

Loading…
Cancel
Save