Skip to content

Commit

Permalink
Allow swapping handsontable with AG Grid Community in Rule Builder.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmchilton committed Dec 13, 2024
1 parent 3c82972 commit 3438ca2
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 0 deletions.
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, // maybe should be true?
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];
},
};
});
});
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;
}
}
defineExpose({ CustomHeader });
// 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

0 comments on commit 3438ca2

Please sign in to comment.