Skip to content

Commit 629386c

Browse files
authored
Merge pull request #63 from rtucek/max-depth-for-groups
Restrict maximum nesting of groups
2 parents dc52e55 + 2fcf689 commit 629386c

File tree

10 files changed

+802
-90
lines changed

10 files changed

+802
-90
lines changed

dev/App.vue

Lines changed: 139 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,82 @@
11
<template>
2-
<div id="app">
2+
<div class="container">
3+
<div class="container-config">
4+
<div class="container-config-item" >
5+
<label for="ctrlEnableDragNDrop">
6+
Allow Drag'n'drop
7+
</label>
8+
<input
9+
type="checkbox"
10+
v-model="ctrlEnableDragNDrop"
11+
id="ctrlEnableDragNDrop"
12+
>
13+
</div>
14+
<div class="container-config-item config-max-depth">
15+
<div>
16+
<label for="ctrlEnableMaxDepth">
17+
Enable max depth
18+
</label>
19+
<input
20+
type="checkbox"
21+
v-model="ctrlEnableMaxDepth"
22+
id="ctrlEnableMaxDepth"
23+
>
24+
</div>
25+
<div>
26+
<label for="ctrlMaxDepth">
27+
Max Depth:
28+
</label>
29+
<input
30+
v-model.number="ctrlMaxDepth"
31+
type="number"
32+
min="0"
33+
:disabled="! ctrlEnableMaxDepth"
34+
id="ctrlMaxDepth"
35+
>
36+
</div>
37+
</div>
38+
<div class="container-config-item config-slots">
39+
<div>
40+
<label for="ctrlEnableGroupOperatorSlot">
41+
Enable Group Operator Slot
42+
</label>
43+
<input
44+
type="checkbox"
45+
v-model="ctrlEnableGroupOperatorSlot"
46+
id="ctrlEnableGroupOperatorSlot"
47+
>
48+
</div>
49+
<div>
50+
<label for="ctrlEnableGroupControlSlot">
51+
Enable Group Control Slot
52+
</label>
53+
<input
54+
type="checkbox"
55+
v-model="ctrlEnableGroupControlSlot"
56+
id="ctrlEnableGroupControlSlot"
57+
>
58+
</div>
59+
<div>
60+
<label for="ctrlEnableRuleSlot">
61+
Enable Rule Slot
62+
</label>
63+
<input
64+
type="checkbox"
65+
v-model="ctrlEnableRuleSlot"
66+
id="ctrlEnableRuleSlot"
67+
>
68+
</div>
69+
</div>
70+
</div>
371
<query-builder
4-
:config="config"
72+
:config="getConfig"
573
v-model="query"
74+
class ="query-builder"
675
>
7-
<template #groupOperator="props">
76+
<template
77+
v-if="ctrlEnableGroupOperatorSlot"
78+
#groupOperator="props"
79+
>
880
<div class="query-builder-group-slot__group-selection">
981
<span class="query-builder-group-slot__group-operator">SLOT #groupOperator</span>
1082
<select
@@ -22,11 +94,17 @@
2294
</div>
2395
</template>
2496

25-
<template #groupControl="props">
97+
<template
98+
v-if="ctrlEnableGroupControlSlot"
99+
#groupControl="props"
100+
>
26101
<group-ctrl-slot :group-ctrl="props"/>
27102
</template>
28103

29-
<template #rule="props">
104+
<template
105+
v-if="ctrlEnableRuleSlot"
106+
#rule="props"
107+
>
30108
<rule-slot :ruleCtrl="props"/>
31109
</template>
32110
</query-builder>
@@ -52,9 +130,25 @@ import RuleSlot from './RuleSlot.vue';
52130
},
53131
})
54132
export default class App extends Vue {
133+
ctrlEnableDragNDrop: boolean = true;
134+
135+
ctrlEnableMaxDepth: boolean = false;
136+
137+
ctrlMaxDepth: number = 3;
138+
139+
ctrlEnableGroupOperatorSlot: boolean = true;
140+
141+
ctrlEnableGroupControlSlot: boolean = true;
142+
143+
ctrlEnableRuleSlot: boolean = true;
144+
55145
query: RuleSet | null = {
56146
operatorIdentifier: 'OR',
57147
children: [
148+
{
149+
identifier: 'txt',
150+
value: 'A',
151+
},
58152
{
59153
operatorIdentifier: 'AND',
60154
children: [
@@ -143,6 +237,7 @@ export default class App extends Vue {
143237
initialValue: 10,
144238
},
145239
],
240+
maxDepth: undefined,
146241
colors: [
147242
'hsl(88, 50%, 55%)',
148243
'hsl(187, 100%, 45%)',
@@ -154,6 +249,22 @@ export default class App extends Vue {
154249
ghostClass: 'ghost',
155250
},
156251
}
252+
253+
get getConfig(): QueryBuilderConfig {
254+
const config: QueryBuilderConfig = { ...this.config };
255+
256+
if (!config.dragging) {
257+
config.dragging = {};
258+
}
259+
config.dragging.disabled = !this.ctrlEnableDragNDrop;
260+
261+
config.maxDepth = Math.abs(this.ctrlMaxDepth || 0);
262+
if (!this.ctrlEnableMaxDepth) {
263+
config.maxDepth = undefined;
264+
}
265+
266+
return config;
267+
}
157268
}
158269
</script>
159270

@@ -167,9 +278,30 @@ body {
167278
font-size: 16px;
168279
}
169280
170-
#app {
171-
margin: 30px auto;
281+
.container {
172282
width: 90%;
283+
margin: 30px auto;
284+
display: flex;
285+
flex-direction: column;
286+
}
287+
288+
.container-config {
289+
border: 1px solid hsl(0, 0%, 75%);
290+
margin-bottom: 30px;
291+
padding: 10px;
292+
display: grid;
293+
grid-template-columns: 1fr 1fr 1fr;
294+
}
295+
296+
// .container-config-item {
297+
//
298+
// }
299+
300+
.config-max-depth #ctrlMaxDepth {
301+
width: 70px;
302+
}
303+
304+
.query-builder {
173305
border: 1px solid hsl(0, 0%, 75%);
174306
}
175307

dev/GroupCtrlSlot.vue

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ export default class GroupCtrlSlot extends Vue {
3232
>
3333
Add Rule
3434
</button>
35-
<div class="query-builder-group-slot__spacer"/>
36-
<button
37-
@click="groupCtrl.newGroup"
38-
class="query-builder-group-slot__group-adding-button"
39-
>
40-
Add Group
41-
</button>
35+
<template v-if="! groupCtrl.maxDepthExeeded">
36+
<div class="query-builder-group-slot__spacer"/>
37+
<button
38+
@click="groupCtrl.newGroup"
39+
class="query-builder-group-slot__group-adding-button"
40+
>
41+
Add Group
42+
</button>
43+
</template>
4244
</div>
4345
</template>
4446

docs/configuration.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ Vue.component('NumberSelection', {
155155

156156
## Colors
157157

158-
A complex, deep nested query can quickly become confusing. In order to keep an overview, nested
158+
A complex, deep nested query, can quickly become confusing. In order to keep an overview, nested
159159
groups may be emphasized with colorful hints.
160160

161-
The colors property should be a string array with a minimum length of at least 2, containing any
161+
The `colors` property should be a string array with a minimum length of at least 2, containing any
162162
valid CSS color definition.
163163

164164

@@ -222,3 +222,37 @@ for allowing nested dragging.
222222
allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb"
223223
sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"
224224
></iframe>
225+
226+
227+
## Max-Depth
228+
229+
If `typeof maxDepth === 'undefined'`, users may have an arbitrary depth of nested groups.
230+
231+
For `typeof maxDepth === 'number' and 0 <= n <= maxDepth`, users are only allowed to create up to n
232+
nested groups. If n is 0, users are effectively not allowed to create any groups at all.
233+
234+
235+
### Runtime change
236+
237+
It is possible and valid to change `maxDepth` at runtime.
238+
As a special chase, if the given query has a higher nested depth and a config change restricts the
239+
`maxDepth` to a lower depth, the library (intentionally) removes any child groups, exceeding the
240+
present config limit. This ensures consistency with the `maxDepth` policy. It's the component user's
241+
responsibility of checking if setting `maxDepth` may not result in an unwanted side-effect of
242+
removing any child-groups from the given query tree.
243+
244+
245+
### Usage of Sortable
246+
247+
If drag'n'drop is activated via [Sortable](#sortable) config:
248+
Prior dropping a dragged group into another group, the library checks if the max depth policy would
249+
be violated and prevents dropping. The user will notice that the drag'n'drop preview will not adjust
250+
as usually expected.
251+
252+
253+
### Usage of groupCtrlSlotProps
254+
255+
For the slot of type [`groupCtrlSlotProps`](styling.html#groupcontrol-slot), the `newGroup()`
256+
callback, passed as slot prop, becomes a noop, if a group has exceeded the `maxDepth` policy.
257+
Additionally, a boolean flag with a `maxDepthExeeded` property is provided to the slot prop object,
258+
so the slot can check and hide a create-new-group handler.

docs/styling.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Often, you'll have to use `v-bind:value` and `v-on:input` instead.
2323
The `groupOperator` slot may be used for changing the markup of a group's operator.
2424

2525
The slot receives an object with the shape of the [GroupOperatorSlotProps
26-
object](https://github.com/rtucek/vue-query-builder/blob/master/types/index.d.ts#L33).
26+
object](https://github.com/rtucek/vue-query-builder/blob/master/types/index.d.ts#L34).
2727

2828
```vue
2929
<template>
@@ -73,7 +73,7 @@ object](https://github.com/rtucek/vue-query-builder/blob/master/types/index.d.ts
7373
The `groupControl` slot allows for creating a new group or adding a new rule.
7474

7575
The slot receives an object with the shape of the [GroupCtrlSlotProps
76-
object](https://github.com/rtucek/vue-query-builder/blob/master/types/index.d.ts#L39).
76+
object](https://github.com/rtucek/vue-query-builder/blob/master/types/index.d.ts#L40).
7777

7878
<iframe
7979
src="https://codesandbox.io/embed/groupcontrol-slot-8thx1?fontsize=14&hidenavigation=1&module=%2Fsrc%2FApp.vue&theme=dark"
@@ -89,7 +89,7 @@ object](https://github.com/rtucek/vue-query-builder/blob/master/types/index.d.ts
8989
The `rule` slot allows for customizing markup around each rule component.
9090

9191
The slot receives an object with the shape of the [RuleSlotProps
92-
object](https://github.com/rtucek/vue-query-builder/blob/master/types/index.d.ts#L45).
92+
object](https://github.com/rtucek/vue-query-builder/blob/master/types/index.d.ts#L47).
9393

9494
You'll have to use Vue's [Dynamic
9595
Component](https://vuejs.org/v2/guide/components.html#Dynamic-Components) feature for displaying the

0 commit comments

Comments
 (0)