Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow swapping handsontable with AG Grid Community in Rule Builder. #19322

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
"@types/jest": "^29.5.12",
"@vueuse/core": "^10.5.0",
"@vueuse/math": "^10.9.0",
"ag-grid-community": "^30",
"ag-grid-vue": "^30",
"assert": "^2.1.0",
"axios": "^1.6.2",
"babel-runtime": "^6.26.0",
Expand Down Expand Up @@ -106,11 +108,13 @@
"vega-embed": "^6.26.0",
"vega-lite": "^5.21.0",
"vue": "^2.7.14",
"vue-class-component": "^7.2.6",
"vue-echarts": "^7.0.3",
"vue-infinite-scroll": "^2.0.2",
"vue-multiselect": "^2.1.7",
"vue-observe-visibility": "^1.0.0",
"vue-prismjs": "^1.2.0",
"vue-property-decorator": "^9.1.2",
"vue-router": "^3.6.5",
"vue-rx": "^6.2.0",
"vue-virtual-scroll-list": "^2.3.5",
Expand Down
125 changes: 125 additions & 0 deletions client/src/components/RuleBuilder/RuleGrid.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<script lang="ts" setup>
import { useResizeObserver } from "@vueuse/core";
import { type ColDef, type IHeaderParams, type ValueGetterParams } from "ag-grid-community";
import { computed, ref, watch } from "vue";

import { useAgGrid } from "@/composables/useAgGrid";

interface Props {
data: string[][];
colHeaders: string[];
height?: string;
}

const props = withDefaults(defineProps<Props>(), {
height: "500px",
});

const agGrid = ref<HTMLDivElement | null>(null);
useResizeObserver(agGrid, () => {
resize();
});

// Default Column Properties
const defaultColDef = ref<ColDef>({
editable: false,
sortable: false,
filter: false,
resizable: false, // we add columns automatically, best if this is just off right?
suppressMovable: true,
});

const style = computed(() => {
return { width: "100%", height: props.height };
});

const agColumnHeaders = computed(() => {
return props.colHeaders.map((header: string, index: number) => {
return {
headerName: header,
headerComponent: CustomHeader,
valueGetter: (params: ValueGetterParams) => {
return params.data[index];
},
};
});
});

// Rule builder builds column headers with HTML (mix of b and i tags),
// this custom component renders HTML instead of text.
class CustomHeader {
private eGui: HTMLElement | undefined;

init(params: IHeaderParams) {
this.eGui = document.createElement("div");
this.eGui.style.cssText = "width: 100%; text-align: center";
this.eGui.innerHTML = `${params.displayName}`;
}

getGui() {
return this.eGui!;
}

refresh(params: IHeaderParams): boolean {
return false;
}
}

// this doesn't work but the idea is to increase the column widths to fill
// the horizontal space if they are too small after auto-sizing.
/*
function cleanUpColumnsIfNeeded() {
if(columnApi.value) {
const gridWidth = document.querySelector("#rules-ag-grid")?.clientWidth || 0;
const totalColumnWidth = (columnApi.value.getAllColumns() || []).reduce(
(sum: number, col: Column) => sum + (col.getActualWidth() || 0),
0
);
if (totalColumnWidth < gridWidth && gridApi.value) {
gridApi.value.sizeColumnsToFit();
}
}
}
*/

function resize() {
if (columnApi.value) {
columnApi.value.autoSizeAllColumns();
}
}

const { columnApi, AgGridVue, onGridReady, resizeOnNextTick, theme } = useAgGrid(resize);

watch(() => props.colHeaders, resizeOnNextTick);
</script>

<template>
<div :class="theme" :style="style">
<AgGridVue
id="rules-ag-grid"
ref="agGrid"
:rowData="data"
:columnDefs="agColumnHeaders"
:defaultColDef="defaultColDef"
:style="style"
:row-height="20"
:header-height="30"
:cell-selection="true"
@gridReady="onGridReady" />
</div>
</template>

<style>
/* Reduce padding and font size for compact rows */
.ag-theme-alpine .ag-row {
font-size: 12px;
line-height: 20px; /* Adjust line height to match rowHeight */
padding: 2px 5px; /* Adjust padding */
}

/* Adjust header font size and padding */
.ag-theme-alpine .ag-header-cell-label {
font-size: 13px;
padding: 3px 5px;
}
</style>
15 changes: 15 additions & 0 deletions client/src/components/RuleCollectionBuilder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -452,12 +452,20 @@
<!-- style="width: 70%;" -->
<div v-if="initialElements !== null" class="table-column" :class="orientation" style="width: 100%">
<HotTable
v-if="gridImplementation == 'hot'"
id="hot-table"
ref="hotTable"
:data="hotData.data"
:col-headers="colHeadersDisplay"
:read-only="true"
stretch-h="all"></HotTable>
<RuleGrid
v-else
id="hot-table"
ref="hotTable"
:data="hotData.data"
:col-headers="colHeadersDisplay"
stretch-h="all"></RuleGrid>
</div>
</div>
</RuleModalMiddle>
Expand Down Expand Up @@ -576,6 +584,7 @@ import RegularExpressionInput from "components/RuleBuilder/RegularExpressionInpu
import RuleDefs from "components/RuleBuilder/rule-definitions";
import RuleComponent from "components/RuleBuilder/RuleComponent";
import RuleDisplay from "components/RuleBuilder/RuleDisplay";
import RuleGrid from "components/RuleBuilder/RuleGrid";
import RuleModalFooter from "components/RuleBuilder/RuleModalFooter";
import RuleModalHeader from "components/RuleBuilder/RuleModalHeader";
import RuleModalMiddle from "components/RuleBuilder/RuleModalMiddle";
Expand Down Expand Up @@ -612,6 +621,7 @@ export default {
components: {
TooltipOnHover,
HotTable,
RuleGrid,
RuleComponent,
RuleTargetComponent,
SavedRulesSelector,
Expand Down Expand Up @@ -675,6 +685,11 @@ export default {
required: false,
default: null,
},
gridImplementation: {
type: String,
required: false,
default: "aggrid",
},
},
data: function () {
let orientation = "vertical";
Expand Down
27 changes: 27 additions & 0 deletions client/src/composables/useAgGrid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import "ag-grid-community/styles/ag-grid.min.css";
import "ag-grid-community/styles/ag-theme-alpine.min.css";

import { type ColumnApi, type GridApi, type GridReadyEvent } from "ag-grid-community";
import { defineAsyncComponent, nextTick, ref } from "vue";

export function useAgGrid(forceGridSize: () => void) {
const gridApi = ref<GridApi | null>(null);
const columnApi = ref<ColumnApi | null>(null);
const theme = "ag-theme-alpine";
function resizeOnNextTick() {
nextTick(forceGridSize);
}

function onGridReady(params: GridReadyEvent) {
gridApi.value = params.api;
columnApi.value = params.columnApi;
forceGridSize();
}

const AgGridVue = defineAsyncComponent(async () => {
const { AgGridVue } = await import(/* webpackChunkName: "agGrid" */ "ag-grid-vue");
return AgGridVue;
});

return { AgGridVue, gridApi, columnApi, resizeOnNextTick, onGridReady, theme };
}
20 changes: 20 additions & 0 deletions client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3183,6 +3183,16 @@ acorn@^8.1.0, acorn@^8.7.1, acorn@^8.8.0, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5"
integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==

ag-grid-community@^30:
version "30.2.1"
resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-30.2.1.tgz#a83d153ad1dbec46402ebe89f74ebb4b0710b3c7"
integrity sha512-1slonXskJbbI9ybhTx//4YKfJpZVAEnHL8dui1rQJRSXKByUi+/f7XtvkLsbgBkawoWbqvRAySjYtvz80+kBfA==

ag-grid-vue@^30:
version "30.2.1"
resolved "https://registry.yarnpkg.com/ag-grid-vue/-/ag-grid-vue-30.2.1.tgz#56395cf053ca2df70107123cf589618ddc3f84b3"
integrity sha512-dnyltXrVUPk0ALQ1PfwnjBtYk/GDOjRjyOMy8LVAiWxVQA6Tmnb/dTnS1yjym1uggu+dDKof2zgPxVKayIHtWg==

agent-base@6:
version "6.0.2"
resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
Expand Down Expand Up @@ -12355,6 +12365,11 @@ vinyl@^2.0.0:
remove-trailing-separator "^1.0.1"
replace-ext "^1.0.0"

vue-class-component@^7.2.6:
version "7.2.6"
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.2.6.tgz#8471e037b8e4762f5a464686e19e5afc708502e4"
integrity sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w==

vue-demi@>=0.14.5, vue-demi@>=0.14.6:
version "0.14.6"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.6.tgz#dc706582851dc1cdc17a0054f4fec2eb6df74c92"
Expand Down Expand Up @@ -12446,6 +12461,11 @@ vue-prismjs@^1.2.0:
dependencies:
prismjs "^1.6.0"

vue-property-decorator@^9.1.2:
version "9.1.2"
resolved "https://registry.yarnpkg.com/vue-property-decorator/-/vue-property-decorator-9.1.2.tgz#266a2eac61ba6527e2e68a6933cfb98fddab5457"
integrity sha512-xYA8MkZynPBGd/w5QFJ2d/NM0z/YeegMqYTphy7NJQXbZcuU6FC6AOdUAcy4SXP+YnkerC6AfH+ldg7PDk9ESQ==

vue-router@^3.6.5:
version "3.6.5"
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.6.5.tgz#95847d52b9a7e3f1361cb605c8e6441f202afad8"
Expand Down
Loading