@adminforth/quick-filters 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build.log CHANGED
@@ -7,5 +7,5 @@ custom/
7
7
  custom/FiltersArea.vue
8
8
  custom/tsconfig.json
9
9
 
10
- sent 11,566 bytes received 58 bytes 23,248.00 bytes/sec
11
- total size is 11,351 speedup is 0.98
10
+ sent 12,836 bytes received 58 bytes 25,788.00 bytes/sec
11
+ total size is 12,621 speedup is 0.98
@@ -77,8 +77,6 @@
77
77
 
78
78
  <CustomRangePicker
79
79
  v-else-if="['integer', 'decimal', 'float'].includes(c.type) && c.allowMinMaxQuery"
80
- :min="getFilterMinValue(c.name)"
81
- :max="getFilterMaxValue(c.name)"
82
80
  :valueStart="getFilterItem({ column: c, operator: 'gte' })"
83
81
  @update:valueStart="onFilterInput[c.name]({ column: c, operator: 'gte', value: ($event !== '' && $event !== null) ? $event : undefined })"
84
82
  :valueEnd="getFilterItem({ column: c, operator: 'lte' })"
@@ -105,21 +103,27 @@
105
103
  </div>
106
104
  </div>
107
105
  </div>
108
- </div>
109
- <div v-if="isExpanded" class="flex w-full justify-end">
106
+ <template v-if="freeCells > 0" v-for="n in freeCells-1" :key="'free-cell-' + n">
107
+ <div></div>
108
+ </template>
109
+ <template v-if="freeCells === 0" v-for="n in cols-1" :key="'free-cell2-' + n">
110
+ <div></div>
111
+ </template>
112
+ <div class="flex items-end justify-end">
110
113
  <Button
111
- class="mt-4 max-w-24"
114
+ class="mt-6 max-w-24"
112
115
  @click="filtersStore.filters = [...filtersStore.filters.filter(f => filtersStore.shouldFilterBeHidden(f.field))]"
113
116
  :disabled="filtersStore.filters.length === 0"
114
117
  >
115
118
  Clear all
116
119
  </Button>
120
+ </div>
117
121
  </div>
118
122
  </div>
119
123
  </template>
120
124
 
121
125
  <script lang="ts" setup>
122
- import { onMounted, computed, ref, reactive } from 'vue';
126
+ import { onMounted, onUnmounted, computed, ref, reactive, watch } from 'vue';
123
127
  import { useFiltersStore } from '@/stores/filters';
124
128
  import { callAdminForthApi, loadMoreForeignOptions, searchForeignOptions, createSearchInputHandlers } from '@/utils';
125
129
  import { useRouter } from 'vue-router';
@@ -136,7 +140,10 @@ const columnOffsets = reactive({});
136
140
  const columnEmptyResultsCount = reactive({});
137
141
  const filtersStore = useFiltersStore();
138
142
  const columnsMinMax = ref({});
139
- const isExpanded = ref(false);
143
+ const isExpanded = ref(true);
144
+ const freeCells = ref(0);
145
+ const currentBreakpoint = ref("base");
146
+ const cols = ref(1);
140
147
 
141
148
  const props = defineProps<{
142
149
  meta: any,
@@ -146,37 +153,37 @@ const props = defineProps<{
146
153
 
147
154
  const columnOptions = ref({});
148
155
  const columnsWithFilter = computed(
149
- () => props.resource.columns?.filter(column => column.showIn.filter && props.meta.options.columns.some(c => c.column === column.name)) || []
156
+ () => sortFilters(props.resource.columns?.filter(column => column.showIn.filter && props.meta.options.columns.some(c => c.column === column.name)), props.meta.options.columns) || []
150
157
  );
151
158
 
152
159
  onMounted(async () => {
153
- console.log('FiltersArea mounted', props.resource);
154
- columnsMinMax.value = await callAdminForthApi({
155
- path: '/get_min_max_for_columns',
156
- method: 'POST',
157
- body: {
158
- resourceId: route.params.resourceId
160
+ // columnsMinMax.value = await callAdminForthApi({
161
+ // path: '/get_min_max_for_columns',
162
+ // method: 'POST',
163
+ // body: {
164
+ // resourceId: route.params.resourceId
165
+ // }
166
+ // });
167
+ currentBreakpoint.value = getBreakpoint(window.innerWidth);
168
+ calculateGridCols();
169
+ window.addEventListener('resize', () => {
170
+ const newBreakpoint = getBreakpoint(window.innerWidth)
171
+ if (newBreakpoint !== currentBreakpoint.value) {
172
+ currentBreakpoint.value = newBreakpoint;
173
+ calculateGridCols();
159
174
  }
160
- });
161
- console.log('Fetched columnsMinMax:', columnsMinMax.value);
175
+ })
162
176
  });
163
177
 
178
+ onUnmounted(() => {
179
+ window.removeEventListener('resize', getBreakpoint)
180
+ })
181
+
164
182
  function getFilterItem({ column, operator }) {
165
183
  const filterValue = filtersStore.filters.find(f => f.field === column.name && f.operator === operator)?.value;
166
184
  return filterValue !== undefined ? filterValue : '';
167
185
  }
168
186
 
169
- function getFilterMinValue(columnName) {
170
- if(columnsMinMax.value && columnsMinMax.value[columnName]) {
171
- return columnsMinMax.value[columnName]?.min
172
- }
173
- }
174
-
175
- function getFilterMaxValue(columnName) {
176
- if(columnsMinMax.value && columnsMinMax.value[columnName]) {
177
- return columnsMinMax.value[columnName]?.max
178
- }
179
- }
180
187
  async function loadMoreOptions(columnName, searchTerm = '') {
181
188
  return loadMoreForeignOptions({
182
189
  columnName,
@@ -244,4 +251,47 @@ function setFilterItem({ column, operator, value }) {
244
251
  }
245
252
  }
246
253
 
254
+
255
+ function getBreakpoint(width) {
256
+ if (width >= 1536) return '2xl'
257
+ if (width >= 1280) return 'xl'
258
+ if (width >= 1024) return 'lg'
259
+ if (width >= 768) return 'md'
260
+ if (width >= 640) return 'sm'
261
+ return 'base'
262
+ }
263
+
264
+ function calculateGridCols() {
265
+ const size = currentBreakpoint.value;
266
+ switch (size) {
267
+ case '2xl':
268
+ cols.value = 6;
269
+ break;
270
+ case 'xl':
271
+ cols.value = 3;
272
+ break;
273
+ case 'lg':
274
+ cols.value = 2;
275
+ break;
276
+ case 'md':
277
+ cols.value = 1;
278
+ break;
279
+ default:
280
+ cols.value = 1;
281
+ }
282
+ const rows = Math.ceil(columnsWithFilter.value.length / cols.value);
283
+ freeCells.value = (cols.value * rows) - columnsWithFilter.value.length;
284
+ }
285
+
286
+ function sortFilters(array, fieldsObject) {
287
+ let desiredOrder = [];
288
+ fieldsObject.forEach(element => {
289
+ desiredOrder.push(element.column);
290
+ });
291
+ const sortedObjects = array.sort(
292
+ (a, b) => desiredOrder.indexOf(a.name) - desiredOrder.indexOf(b.name)
293
+ );
294
+ return sortedObjects;
295
+ }
296
+
247
297
  </script>
@@ -77,8 +77,6 @@
77
77
 
78
78
  <CustomRangePicker
79
79
  v-else-if="['integer', 'decimal', 'float'].includes(c.type) && c.allowMinMaxQuery"
80
- :min="getFilterMinValue(c.name)"
81
- :max="getFilterMaxValue(c.name)"
82
80
  :valueStart="getFilterItem({ column: c, operator: 'gte' })"
83
81
  @update:valueStart="onFilterInput[c.name]({ column: c, operator: 'gte', value: ($event !== '' && $event !== null) ? $event : undefined })"
84
82
  :valueEnd="getFilterItem({ column: c, operator: 'lte' })"
@@ -105,21 +103,27 @@
105
103
  </div>
106
104
  </div>
107
105
  </div>
108
- </div>
109
- <div v-if="isExpanded" class="flex w-full justify-end">
106
+ <template v-if="freeCells > 0" v-for="n in freeCells-1" :key="'free-cell-' + n">
107
+ <div></div>
108
+ </template>
109
+ <template v-if="freeCells === 0" v-for="n in cols-1" :key="'free-cell2-' + n">
110
+ <div></div>
111
+ </template>
112
+ <div class="flex items-end justify-end">
110
113
  <Button
111
- class="mt-4 max-w-24"
114
+ class="mt-6 max-w-24"
112
115
  @click="filtersStore.filters = [...filtersStore.filters.filter(f => filtersStore.shouldFilterBeHidden(f.field))]"
113
116
  :disabled="filtersStore.filters.length === 0"
114
117
  >
115
118
  Clear all
116
119
  </Button>
120
+ </div>
117
121
  </div>
118
122
  </div>
119
123
  </template>
120
124
 
121
125
  <script lang="ts" setup>
122
- import { onMounted, computed, ref, reactive } from 'vue';
126
+ import { onMounted, onUnmounted, computed, ref, reactive, watch } from 'vue';
123
127
  import { useFiltersStore } from '@/stores/filters';
124
128
  import { callAdminForthApi, loadMoreForeignOptions, searchForeignOptions, createSearchInputHandlers } from '@/utils';
125
129
  import { useRouter } from 'vue-router';
@@ -136,7 +140,10 @@ const columnOffsets = reactive({});
136
140
  const columnEmptyResultsCount = reactive({});
137
141
  const filtersStore = useFiltersStore();
138
142
  const columnsMinMax = ref({});
139
- const isExpanded = ref(false);
143
+ const isExpanded = ref(true);
144
+ const freeCells = ref(0);
145
+ const currentBreakpoint = ref("base");
146
+ const cols = ref(1);
140
147
 
141
148
  const props = defineProps<{
142
149
  meta: any,
@@ -146,37 +153,37 @@ const props = defineProps<{
146
153
 
147
154
  const columnOptions = ref({});
148
155
  const columnsWithFilter = computed(
149
- () => props.resource.columns?.filter(column => column.showIn.filter && props.meta.options.columns.some(c => c.column === column.name)) || []
156
+ () => sortFilters(props.resource.columns?.filter(column => column.showIn.filter && props.meta.options.columns.some(c => c.column === column.name)), props.meta.options.columns) || []
150
157
  );
151
158
 
152
159
  onMounted(async () => {
153
- console.log('FiltersArea mounted', props.resource);
154
- columnsMinMax.value = await callAdminForthApi({
155
- path: '/get_min_max_for_columns',
156
- method: 'POST',
157
- body: {
158
- resourceId: route.params.resourceId
160
+ // columnsMinMax.value = await callAdminForthApi({
161
+ // path: '/get_min_max_for_columns',
162
+ // method: 'POST',
163
+ // body: {
164
+ // resourceId: route.params.resourceId
165
+ // }
166
+ // });
167
+ currentBreakpoint.value = getBreakpoint(window.innerWidth);
168
+ calculateGridCols();
169
+ window.addEventListener('resize', () => {
170
+ const newBreakpoint = getBreakpoint(window.innerWidth)
171
+ if (newBreakpoint !== currentBreakpoint.value) {
172
+ currentBreakpoint.value = newBreakpoint;
173
+ calculateGridCols();
159
174
  }
160
- });
161
- console.log('Fetched columnsMinMax:', columnsMinMax.value);
175
+ })
162
176
  });
163
177
 
178
+ onUnmounted(() => {
179
+ window.removeEventListener('resize', getBreakpoint)
180
+ })
181
+
164
182
  function getFilterItem({ column, operator }) {
165
183
  const filterValue = filtersStore.filters.find(f => f.field === column.name && f.operator === operator)?.value;
166
184
  return filterValue !== undefined ? filterValue : '';
167
185
  }
168
186
 
169
- function getFilterMinValue(columnName) {
170
- if(columnsMinMax.value && columnsMinMax.value[columnName]) {
171
- return columnsMinMax.value[columnName]?.min
172
- }
173
- }
174
-
175
- function getFilterMaxValue(columnName) {
176
- if(columnsMinMax.value && columnsMinMax.value[columnName]) {
177
- return columnsMinMax.value[columnName]?.max
178
- }
179
- }
180
187
  async function loadMoreOptions(columnName, searchTerm = '') {
181
188
  return loadMoreForeignOptions({
182
189
  columnName,
@@ -244,4 +251,47 @@ function setFilterItem({ column, operator, value }) {
244
251
  }
245
252
  }
246
253
 
254
+
255
+ function getBreakpoint(width) {
256
+ if (width >= 1536) return '2xl'
257
+ if (width >= 1280) return 'xl'
258
+ if (width >= 1024) return 'lg'
259
+ if (width >= 768) return 'md'
260
+ if (width >= 640) return 'sm'
261
+ return 'base'
262
+ }
263
+
264
+ function calculateGridCols() {
265
+ const size = currentBreakpoint.value;
266
+ switch (size) {
267
+ case '2xl':
268
+ cols.value = 6;
269
+ break;
270
+ case 'xl':
271
+ cols.value = 3;
272
+ break;
273
+ case 'lg':
274
+ cols.value = 2;
275
+ break;
276
+ case 'md':
277
+ cols.value = 1;
278
+ break;
279
+ default:
280
+ cols.value = 1;
281
+ }
282
+ const rows = Math.ceil(columnsWithFilter.value.length / cols.value);
283
+ freeCells.value = (cols.value * rows) - columnsWithFilter.value.length;
284
+ }
285
+
286
+ function sortFilters(array, fieldsObject) {
287
+ let desiredOrder = [];
288
+ fieldsObject.forEach(element => {
289
+ desiredOrder.push(element.column);
290
+ });
291
+ const sortedObjects = array.sort(
292
+ (a, b) => desiredOrder.indexOf(a.name) - desiredOrder.indexOf(b.name)
293
+ );
294
+ return sortedObjects;
295
+ }
296
+
247
297
  </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adminforth/quick-filters",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",