Skip to content

Commit

Permalink
Merge pull request #44 from moevm/server_side_pagination
Browse files Browse the repository at this point in the history
Server side pagination
  • Loading branch information
vladDotH committed Dec 16, 2023
2 parents bb2e786 + 8a587db commit 4fe6dbf
Show file tree
Hide file tree
Showing 22 changed files with 464 additions and 159 deletions.
34 changes: 34 additions & 0 deletions client/src/ag-grid/datasource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { api } from '@/api';
import { IDatasource, IGetRowsParams } from 'ag-grid-community'
import { MapInfo } from "@/types/maps";


export class DataSource implements IDatasource {
dataFetchURL: string;

constructor(dataFetchURL: string) {
this.dataFetchURL = dataFetchURL;
}

getRows(params: IGetRowsParams) {
console.log(JSON.stringify(params));

let getParams = {
start: params.startRow,
end: params.endRow,
sort: JSON.stringify(params.sortModel),
filter: JSON.stringify(params.filterModel)
}

api.get<{ rowData: MapInfo[], end: number }>(this.dataFetchURL, {
params: getParams,
}).then((response) => {
let data = response.data;
console.log(data);
if (data.end === params.endRow) data.end = -1;
params.successCallback(data.rowData, data.end);
}).catch(() => {
params.failCallback();
});
}
};
56 changes: 53 additions & 3 deletions client/src/ag-grid/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,46 @@ import ActionsRenderer from "@/components/renderers/ActionsRenderer.vue";

export function getDefaultColDef(): ColDef {
return {
filter: true,
sortable: true,
editable: false,
resizable: true,
filterParams: {
buttons: ["reset", "apply"],
closeOnApply: true,
},
};
}

export function getColDefFilterText(): ColDef {
return {
filter: "agTextColumnFilter",
filterParams: {
filterOptions: ["contains", "notContains"],
debounce: 1000,
maxNumConditions: 1,
},
};
}

export function getColDefFilterId(): ColDef {
return {
filter: "agTextColumnFilter",
filterParams: {
filterOptions: ["equals"],
debounce: 1000,
maxNumConditions: 1,
},
};
}

export function getColDefFilterDate(): ColDef {
return {
filter: "agDateColumnFilter",
filterParams: {
filterOptions: ["equals", "lessThan", "greaterThan"],
debounce: 1000,
maxNumConditions: 1,
},
};
}

Expand All @@ -22,6 +58,18 @@ export function getDefaultGridOptions(): GridOptions {
};
}

export function getGridOptionsForSSDM(): GridOptions {
return {
...getDefaultGridOptions(),
domLayout: "autoHeight",
animateRows: true,
rowModelType: "infinite",
cacheBlockSize: defaultPageSize,
pagination: true,
paginationPageSize: defaultPageSize,
};
}

export function getActionsColDef<T>(actions: Action<T>[]): ColDef<T> {
return {
colId: "actions",
Expand All @@ -32,12 +80,14 @@ export function getActionsColDef<T>(actions: Action<T>[]): ColDef<T> {
},
sortable: false,
filter: false,
resizable: false,
resizable: true,
pinned: "right",
suppressMovable: true,
};
}

export const defaultPageSize = 10;

export function fitActionsColumn({ columnApi }: { columnApi: ColumnApi }) {
columnApi.autoSizeColumn("actions", true);
columnApi.autoSizeColumn("actions", false);
}
2 changes: 2 additions & 0 deletions client/src/ag-grid/localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,6 @@ export const agGridLocalization = {
ctrlC: "Ctrl+C",
paste: "Вставить",
ctrlV: "Ctrl+V",

resetFilter: "Сброс",
};
19 changes: 0 additions & 19 deletions client/src/api/websocket/images.ts

This file was deleted.

2 changes: 1 addition & 1 deletion client/src/components/common/map/MapDisplay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const toaster = useToaster();
// Данные текущего пользователя.
const userStore = useUserStore();
const userId = userStore.user ? userStore.user._id.$oid : "-1";
const userId = userStore.user ? userStore.user._id.$oid : "undefined";
// Для выбора имени и типа объекта.
const objectTypes = Array.from(objectTypesColors.keys());
Expand Down
9 changes: 4 additions & 5 deletions client/src/components/common/map/api.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import axios from "axios";
import { Ref } from "vue";
import L, { LatLngExpression } from "leaflet";
import "leaflet/dist/leaflet.css";
import "@/components/common/map/customIcon.css";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";

import { baseURL, map_zoom } from "@/api";
import { baseURL, api, map_zoom } from "@/api";
import { MapInfo } from "@/types/maps";
import { ObjectInfo } from "@/types/objects";
import { objectTypesColors } from "@/api";
Expand All @@ -19,7 +18,7 @@ export async function getMaps(
r: number
): Promise<MapInfo[] | void> {
return (
await axios.get<MapInfo[]>(baseURL + "/images/near/" + y + "/" + x + "/" + r)
await api.get<MapInfo[]>("/images/near/" + y + "/" + x + "/" + r)
).data;
}

Expand All @@ -30,7 +29,7 @@ export async function getObjects(
r: number
): Promise<ObjectInfo[]> {
return (
await axios.get<ObjectInfo[]>(baseURL + "/objects/near/" + y + "/" + x + "/" + r)
await api.get<ObjectInfo[]>("/objects/near/" + y + "/" + x + "/" + r)
).data;
}

Expand Down Expand Up @@ -460,7 +459,7 @@ function sendObjects(
drawLayersList.deleted.forEach(listFormation(deleted));

// Отправляем на сервер.
axios.post(baseURL + "/objects/update", {
api.post("/objects/update", {
edited: edited,
created: created,
deleted: deleted
Expand Down
17 changes: 4 additions & 13 deletions client/src/components/routes/map/MapComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
:row-data="objectsInfo"
:column-defs="columnDefs"
:grid-options="options"
@grid-ready="fitActionsColumn"
@first-data-rendered="fitActionsColumn"
/>
<div class="d-flex justify-content-center mt-3">
<MapDisplay :x="x" :y="y" ref="mapDisplay" @objects-updated="objectsShow"/>
Expand Down Expand Up @@ -40,30 +40,21 @@ const mapDisplay = ref<InstanceType<typeof MapDisplay>>();
let lastMarker: L.Marker | undefined = undefined;
// Надеюсь, никто не заметит этот костыль, чтобы прогружались action-ы сразу :)
const objectsInfo = ref<ObjectInfo[]>([{
id: "-",
type: "-",
name: "-",
color: "-",
updateUserId: "-",
updateDatetime: "-",
center: [0, 0],
coordinates: [[0, 0]]
}]);
const objectsInfo = ref<ObjectInfo[]>([]);
const columnDefs: ColDef<ObjectInfo>[] = [
{ headerName: "Id", field: "id", flex: 2, minWidth: 120 },
{ headerName: "Тип", field: "type", flex: 4, minWidth: 80 },
{ headerName: "Название", field: "name", flex: 4, minWidth: 80 },
{
headerName: "Дата загрузки",
headerName: "Дата изменения",
field: "updateDatetime",
flex: 5,
minWidth: 180,
valueFormatter: dateFormatter
},
{
headerName: "Id загрузившего пользователя",
headerName: "Id изменившего пользователя",
field: "updateUserId",
flex: 5,
minWidth: 200,
Expand Down
68 changes: 48 additions & 20 deletions client/src/components/routes/maps/MapsListComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<AgGridVue
class="ag-theme-alpine"
:column-defs="columnDefs"
:row-data="images"
:grid-options="options"
@grid-ready="fitActionsColumn"
@grid-ready="onGridReady"
@first-data-rendered="fitActionsColumn"
/>
</div>

Expand All @@ -33,55 +33,78 @@

<script setup lang="ts">
import { AgGridVue } from "ag-grid-vue3";
import { ColDef, GridOptions } from "ag-grid-community";
import {
ColDef,
GridApi,
GridOptions,
GridReadyEvent,
} from "ag-grid-community";
import {
fitActionsColumn,
getActionsColDef,
getDefaultGridOptions,
getGridOptionsForSSDM,
getColDefFilterId,
getColDefFilterText,
getColDefFilterDate,
} from "@/ag-grid/factory";
import { DataSource } from "@/ag-grid/datasource";
import { deleteMap } from "@/components/routes/maps/api";
import { MapInfo } from "@/types/maps";
import { dateFormatter } from "@/ag-grid/formatters";
import { useRouter } from "vue-router";
import { routeNames } from "@/router";
import FlagRenderer from "@/components/renderers/FlagRenderer.vue";
import Modal from "@/components/common/Modal.vue";
import { useImages } from "@/api/websocket/images";
import { ref } from "vue";
import { useUserStore } from "@/store/user";
const router = useRouter();
const userStore = useUserStore();
let gridApi: GridApi;
const columnDefs: ColDef<MapInfo>[] = [
{ headerName: "Id", field: "id", flex: 2, minWidth: 80 },
{ headerName: "Имя", field: "name", flex: 3, minWidth: 180 },
{
headerName: "Id",
field: "id",
flex: 2,
minWidth: 80,
...getColDefFilterId(),
},
{
headerName: "Имя",
field: "name",
flex: 3,
minWidth: 180,
...getColDefFilterText(),
},
{
headerName: "Дата загрузки",
field: "updateDatetime",
flex: 5,
minWidth: 180,
valueFormatter: dateFormatter,
...getColDefFilterDate(),
},
{
headerName: "Id загрузившего пользователя",
field: "updateUserId",
flex: 5,
minWidth: 100,
...getColDefFilterId(),
},
{
headerName: "Обработано",
field: "ready",
flex: 3,
minWidth: 200,
minWidth: 100,
cellRenderer: FlagRenderer,
},
{
headerName: "Нарезано",
field: "sliced",
flex: 3,
minWidth: 200,
minWidth: 100,
cellRenderer: FlagRenderer,
},
{
Expand All @@ -90,41 +113,46 @@ const columnDefs: ColDef<MapInfo>[] = [
tooltip: "Открыть карту",
icon: "bi bi-map",
button: "btn-secondary",
hide: (data) => !(data.ready && data.sliced),
hide: (data) => !(data && data.ready && data.sliced),
onClicked: (action, data) => {
router.push({ name: routeNames.Map, params: { y: data.center[0],
x: data.center[1] } })
}
router.push({
name: routeNames.Map,
params: { y: data.center[0], x: data.center[1] },
});
},
},
{
tooltip: "Удалить карту",
icon: "bi bi-trash",
button: "btn-danger",
hide: (data) => !(data.ready && data.sliced) || !userStore.isAuthed,
hide: (data) =>
!(data && data.ready && data.sliced) || !userStore.isAuthed,
onClicked: (action, data) => {
delElement.value = data.id;
modal.value?.open();
},
},
]),
minWidth: 140,
},
];
const options: GridOptions<MapInfo> = {
...getDefaultGridOptions(),
domLayout: "autoHeight",
animateRows: true,
...getGridOptionsForSSDM(),
};
const { images } = await useImages();
function onGridReady(params: GridReadyEvent) {
gridApi = params.api;
gridApi.setDatasource(new DataSource("/images/table"));
}
// Для модального окна удаления.
const modal = ref<InstanceType<typeof Modal> | null>(null),
delElement = ref<string | null>(null);
function acceptDelDialog() {
modal.value?.close();
if (delElement.value) deleteMap(delElement.value);
if (delElement.value) deleteMap(delElement.value, gridApi);
}
</script>

Expand Down
Loading

0 comments on commit 4fe6dbf

Please sign in to comment.