mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
feat(editor): Use n8n date time picker in data tables (no-changelog) (#19060)
This commit is contained in:
@@ -689,6 +689,7 @@
|
||||
|
||||
/* Ag Grid */
|
||||
--grid-row-selected-background: var(--p-color-secondary-070);
|
||||
--grid-cell-editing-border: 2px solid var(--color-secondary);
|
||||
}
|
||||
|
||||
:root {
|
||||
|
||||
@@ -24,8 +24,8 @@ import type {
|
||||
CellEditingStartedEvent,
|
||||
CellEditingStoppedEvent,
|
||||
CellKeyDownEvent,
|
||||
ValueFormatterParams,
|
||||
SortDirection,
|
||||
SortChangedEvent,
|
||||
} from 'ag-grid-community';
|
||||
import {
|
||||
ModuleRegistry,
|
||||
@@ -67,11 +67,10 @@ import AddColumnButton from '@/features/dataStore/components/dataGrid/AddColumnB
|
||||
import AddRowButton from '@/features/dataStore/components/dataGrid/AddRowButton.vue';
|
||||
import { isDataStoreValue } from '@/features/dataStore/typeGuards';
|
||||
import NullEmptyCellRenderer from '@/features/dataStore/components/dataGrid/NullEmptyCellRenderer.vue';
|
||||
import ElDatePickerCellEditor from '@/features/dataStore/components/dataGrid/ElDatePickerCellEditor.vue';
|
||||
import { onClickOutside } from '@vueuse/core';
|
||||
import type { SortChangedEvent } from 'ag-grid-community';
|
||||
import { useClipboard } from '@/composables/useClipboard';
|
||||
import { reorderItem } from '@/features/dataStore/utils';
|
||||
import { convertToDisplayDate } from '@/utils/formatters/dateFormatter';
|
||||
|
||||
// Register only the modules we actually use
|
||||
ModuleRegistry.registerModules([
|
||||
@@ -359,8 +358,14 @@ const createColumnDef = (col: DataStoreColumn, extraProps: Partial<ColDef> = {})
|
||||
}
|
||||
// Setup date editor
|
||||
if (col.type === 'date') {
|
||||
columnDef.cellEditor = 'agDateCellEditor';
|
||||
columnDef.cellEditorPopup = false;
|
||||
columnDef.cellEditorSelector = () => ({
|
||||
component: ElDatePickerCellEditor,
|
||||
});
|
||||
columnDef.valueFormatter = (params) => {
|
||||
const value = params.value as Date | null | undefined;
|
||||
if (value === null || value === undefined) return '';
|
||||
return value.toISOString();
|
||||
};
|
||||
}
|
||||
return {
|
||||
...columnDef,
|
||||
@@ -433,11 +438,6 @@ const initColumnDefinitions = () => {
|
||||
headerComponentParams: {
|
||||
allowMenuActions: false,
|
||||
},
|
||||
valueFormatter: (params: ValueFormatterParams<DataStoreRow>) => {
|
||||
if (!params.value) return '';
|
||||
const { date, time } = convertToDisplayDate(params.value as Date | string | number);
|
||||
return `${date}, ${time}`;
|
||||
},
|
||||
};
|
||||
colDefs.value = [
|
||||
// Always add the ID column, it's not returned by the back-end but all data stores have it
|
||||
@@ -876,8 +876,6 @@ defineExpose({
|
||||
--ag-input-background-color: var(--color-text-xlight);
|
||||
--ag-focus-shadow: none;
|
||||
|
||||
--cell-editing-border: 2px solid var(--color-secondary);
|
||||
|
||||
:global(.ag-cell) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -949,7 +947,7 @@ defineExpose({
|
||||
padding-top: var(--spacing-xs);
|
||||
|
||||
&:where(:focus-within, :active) {
|
||||
border: var(--cell-editing-border);
|
||||
border: var(--grid-cell-editing-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -968,7 +966,7 @@ defineExpose({
|
||||
box-shadow: none;
|
||||
|
||||
&:global(.boolean-cell) {
|
||||
border: var(--cell-editing-border) !important;
|
||||
border: var(--grid-cell-editing-border) !important;
|
||||
|
||||
&:global(.ag-cell-focus) {
|
||||
background-color: var(--grid-cell-active-background);
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, nextTick } from 'vue';
|
||||
import type { ICellEditorParams } from 'ag-grid-community';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
const props = defineProps<{
|
||||
params: ICellEditorParams;
|
||||
}>();
|
||||
|
||||
const pickerRef = ref<HTMLElement | null>(null);
|
||||
const dateValue = ref<Date | null>(null);
|
||||
const initialValue = ref<Date | null>(null);
|
||||
|
||||
const inputWidth = ref(props.params.column.getActualWidth() - 4); // -4 for the border
|
||||
|
||||
onMounted(async () => {
|
||||
const initial = props.params.value as unknown;
|
||||
if (initial === null || initial === undefined) {
|
||||
dateValue.value = null;
|
||||
} else if (initial instanceof Date) {
|
||||
const dt = DateTime.fromJSDate(initial);
|
||||
// the date editor shows local time but we want the UTC so we need to offset the value here
|
||||
dateValue.value = dt.minus({ minutes: dt.offset }).toJSDate();
|
||||
}
|
||||
initialValue.value = dateValue.value;
|
||||
|
||||
await nextTick();
|
||||
try {
|
||||
// Focus to open the calendar popover
|
||||
// Element Plus exposes a focus() method on the picker instance
|
||||
// Using any to avoid tying to internal types
|
||||
(pickerRef.value as unknown as { focus?: () => void })?.focus?.();
|
||||
} catch {}
|
||||
});
|
||||
|
||||
function onChange() {
|
||||
props.params.stopEditing();
|
||||
}
|
||||
|
||||
function onClear() {
|
||||
dateValue.value = null;
|
||||
props.params.stopEditing();
|
||||
}
|
||||
|
||||
function onKeydown(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape') {
|
||||
e.stopPropagation();
|
||||
dateValue.value = initialValue.value;
|
||||
props.params.stopEditing();
|
||||
} else if (e.key === 'Enter') {
|
||||
e.stopPropagation();
|
||||
props.params.stopEditing();
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
getValue: () => {
|
||||
if (dateValue.value === null) return null;
|
||||
const dt = DateTime.fromJSDate(dateValue.value);
|
||||
// the editor returns local time but we initially offset the value to UTC so we need to add the offset back here
|
||||
return dt.plus({ minutes: dt.offset }).toJSDate();
|
||||
},
|
||||
isPopup: () => true,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="datastore-datepicker-wrapper">
|
||||
<el-date-picker
|
||||
ref="pickerRef"
|
||||
v-model="dateValue"
|
||||
type="datetime"
|
||||
:style="{ width: `${inputWidth}px` }"
|
||||
:clearable="true"
|
||||
:editable="false"
|
||||
:teleported="false"
|
||||
:placeholder="''"
|
||||
@change="onChange"
|
||||
@clear="onClear"
|
||||
@keydown="onKeydown"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.datastore-datepicker-wrapper {
|
||||
border-radius: var(--border-radius-base);
|
||||
|
||||
.el-input__prefix {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.el-input__suffix {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
color: var(--color-foreground-dark);
|
||||
}
|
||||
|
||||
.el-input__inner {
|
||||
border: none !important;
|
||||
padding-left: var(--ag-input-padding-start);
|
||||
}
|
||||
|
||||
&:where(:focus-within, :active) {
|
||||
box-shadow: none;
|
||||
border: var(--grid-cell-editing-border);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user