|
76 | 76 | </template> |
77 | 77 | </template> |
78 | 78 |
|
79 | | - <div class="filter-group-list"> |
| 79 | + <div v-if="childFilters.length" class="filter-group-list"> |
80 | 80 | <DataViewFilterNode v-for="(child, index) in childFilters" |
81 | 81 | :key="child.guid" |
82 | 82 | :modelValue="child" |
|
87 | 87 | @update:modelValue="onUpdateChild(index, $event)" |
88 | 88 | @delete="removeChild(index)" /> |
89 | 89 | </div> |
| 90 | + |
| 91 | + <p v-else class="text-muted">No filters. Click "Add Filter" or "Add Group" to get started.</p> |
90 | 92 | </Panel> |
91 | 93 |
|
92 | 94 | <Panel v-else |
|
214 | 216 | import NotificationBox from "@Obsidian/Controls/notificationBox.obs"; |
215 | 217 | import Panel from "@Obsidian/Controls/panel.obs"; |
216 | 218 | import RockButton from "@Obsidian/Controls/rockButton.obs"; |
217 | | - import { |
218 | | - cloneFilterNode, |
219 | | - createFilterNode, |
220 | | - createGroupNode, |
221 | | - getGroupJoinType, |
222 | | - getGroupTruthType, |
223 | | - isFilterNode, |
224 | | - setGroupJoinType, |
225 | | - setGroupTruthType |
226 | | - } from "@Obsidian/Core/Reporting/dataViewFilterEditor"; |
227 | 219 | import { FilterExpressionType } from "@Obsidian/Enums/Reporting/filterExpressionType"; |
228 | | - import { FilterGroupJoinType } from "@Obsidian/Enums/Reporting/filterGroupJoinType"; |
229 | | - import { FilterGroupTruthType } from "@Obsidian/Enums/Reporting/filterGroupTruthType"; |
230 | 220 | import { FilterMode } from "@Obsidian/Enums/Reporting/filterMode"; |
231 | 221 | import type { Guid } from "@Obsidian/Types"; |
| 222 | + import { useSecurityGrantToken } from "@Obsidian/Utility/block"; |
232 | 223 | import { useHttp } from "@Obsidian/Utility/http"; |
233 | 224 | import { Enumerable } from "@Obsidian/Utility/linq"; |
234 | 225 | import { toNumberOrNull } from "@Obsidian/Utility/numberUtils"; |
|
237 | 228 | import { DataViewFilterBag } from "@Obsidian/ViewModels/Reporting/dataViewFilterBag"; |
238 | 229 | import { DataFilterGetComponentResultsBag } from "@Obsidian/ViewModels/Rest/Controls/dataFilterGetComponentResultsBag"; |
239 | 230 | import { DataFilterGetSelectionResultsBag } from "@Obsidian/ViewModels/Rest/Controls/dataFilterGetSelectionResultsBag"; |
| 231 | + import { DataFilterExecuteComponentRequestOptionsBag } from "@Obsidian/ViewModels/Rest/Controls/dataFilterExecuteComponentRequestOptionsBag"; |
240 | 232 | import type { ListItemBag } from "@Obsidian/ViewModels/Utility/listItemBag"; |
| 233 | + import { newGuid } from "@Obsidian/Utility/guid"; |
241 | 234 |
|
242 | 235 | defineOptions({ |
243 | 236 | name: "DataViewFilterNode" |
244 | 237 | }); |
245 | 238 |
|
| 239 | + // #region Types |
| 240 | + |
| 241 | + enum FilterGroupJoinType { |
| 242 | + All = 0, |
| 243 | + Any = 1 |
| 244 | + } |
| 245 | + |
| 246 | + enum FilterGroupTruthType { |
| 247 | + True = 0, |
| 248 | + False = 1 |
| 249 | + } |
| 250 | + |
| 251 | + // #endregion Types |
| 252 | + |
246 | 253 | const props = defineProps({ |
247 | 254 | modelValue: { |
248 | 255 | type: Object as PropType<DataViewFilterBag>, |
|
272 | 279 | }>(); |
273 | 280 |
|
274 | 281 | const http = useHttp(); |
| 282 | + const securityGrantToken = useSecurityGrantToken(); |
275 | 283 | const node = ref<DataViewFilterBag>(cloneFilterNode(props.modelValue)); |
276 | 284 | const isNodeExpanded = ref<boolean>(props.isRoot || props.isExpanded); |
277 | 285 | const componentDefinition = ref<DataFilterGetComponentResultsBag["componentDefinition"]>(); |
|
346 | 354 | const result = await http.post<DataFilterGetComponentResultsBag>("/api/v2/Controls/DataFilterGetComponent", undefined, { |
347 | 355 | entityTypeGuid: props.entityTypeGuid, |
348 | 356 | filterTypeGuid: selectedFilterTypeGuidOrEmptyString.value, |
349 | | - selection: node.value.selection |
| 357 | + selection: node.value.selection, |
| 358 | + securityGrantToken: securityGrantToken.value |
350 | 359 | }); |
351 | 360 |
|
352 | 361 | if (result.isSuccess && result.data) { |
|
380 | 389 | const result = await http.post<DataFilterGetSelectionResultsBag>("/api/v2/Controls/DataFilterGetSelection", undefined, { |
381 | 390 | entityTypeGuid: props.entityTypeGuid, |
382 | 391 | filterTypeGuid: selectedFilterTypeGuidOrEmptyString.value, |
383 | | - componentData: componentData.value |
| 392 | + componentData: componentData.value, |
| 393 | + securityGrantToken: securityGrantToken.value |
384 | 394 | }); |
385 | 395 |
|
386 | 396 | if (result.isSuccess && result.data) { |
|
405 | 415 | } |
406 | 416 |
|
407 | 417 | async function executeComponentRequest(request: Record<string, string>): Promise<Record<string, string> | null> { |
408 | | - if (!selectedFilterTypeGuidOrEmptyString.value) { |
| 418 | + if (!selectedFilterTypeGuidOrEmptyString.value || !props.entityTypeGuid) { |
409 | 419 | return null; |
410 | 420 | } |
411 | 421 |
|
412 | | - const result = await http.post<Record<string, string>>("/api/v2/Controls/DataFilterExecuteComponentRequest", undefined, { |
| 422 | + const options: DataFilterExecuteComponentRequestOptionsBag = { |
413 | 423 | entityTypeGuid: props.entityTypeGuid, |
414 | 424 | filterTypeGuid: selectedFilterTypeGuidOrEmptyString.value, |
415 | | - request |
416 | | - }); |
| 425 | + request, |
| 426 | + securityGrantToken: securityGrantToken.value |
| 427 | + }; |
| 428 | + |
| 429 | + const result = await http.post<Record<string, string>>("/api/v2/Controls/DataFilterExecuteComponentRequest", undefined, options); |
417 | 430 |
|
418 | 431 | if (result.isSuccess) { |
419 | 432 | return result.data ?? null; |
|
499 | 512 | emit("update:modelValue", nextNode); |
500 | 513 | } |
501 | 514 |
|
| 515 | + function cloneFilterNode(node: DataViewFilterBag | null | undefined): DataViewFilterBag { |
| 516 | + return JSON.parse(JSON.stringify(node ?? createDefaultDataViewFilter())); |
| 517 | + } |
| 518 | + |
| 519 | + function createFilterNode(): DataViewFilterBag { |
| 520 | + return { |
| 521 | + guid: newGuid(), |
| 522 | + expressionType: FilterExpressionType.Filter, |
| 523 | + filterTypeGuid: null, |
| 524 | + selection: null, |
| 525 | + componentData: {}, |
| 526 | + childFilters: [] |
| 527 | + }; |
| 528 | + } |
| 529 | + |
| 530 | + function createGroupNode(expressionType: FilterExpressionType = FilterExpressionType.GroupAll): DataViewFilterBag { |
| 531 | + return { |
| 532 | + guid: newGuid(), |
| 533 | + expressionType, |
| 534 | + childFilters: [createFilterNode()] |
| 535 | + }; |
| 536 | + } |
| 537 | + |
| 538 | + function createDefaultDataViewFilter(): DataViewFilterBag { |
| 539 | + return createGroupNode(FilterExpressionType.GroupAll); |
| 540 | + } |
| 541 | + |
| 542 | + function isFilterNode(node: DataViewFilterBag): boolean { |
| 543 | + return node.expressionType === FilterExpressionType.Filter; |
| 544 | + } |
| 545 | + |
| 546 | + function getGroupJoinType(expressionType: FilterExpressionType): FilterGroupJoinType { |
| 547 | + return expressionType === FilterExpressionType.GroupAny || expressionType === FilterExpressionType.GroupAnyFalse |
| 548 | + ? FilterGroupJoinType.Any |
| 549 | + : FilterGroupJoinType.All; |
| 550 | + } |
| 551 | + |
| 552 | + function getGroupTruthType(expressionType: FilterExpressionType): FilterGroupTruthType { |
| 553 | + return expressionType === FilterExpressionType.GroupAllFalse || expressionType === FilterExpressionType.GroupAnyFalse |
| 554 | + ? FilterGroupTruthType.False |
| 555 | + : FilterGroupTruthType.True; |
| 556 | + } |
| 557 | + |
| 558 | + function setGroupJoinType(node: DataViewFilterBag, joinType: FilterGroupJoinType): void { |
| 559 | + const isFalse = node.expressionType === FilterExpressionType.GroupAllFalse || node.expressionType === FilterExpressionType.GroupAnyFalse; |
| 560 | + |
| 561 | + if (joinType === FilterGroupJoinType.All) { |
| 562 | + node.expressionType = isFalse ? FilterExpressionType.GroupAllFalse : FilterExpressionType.GroupAll; |
| 563 | + } |
| 564 | + else { |
| 565 | + node.expressionType = isFalse ? FilterExpressionType.GroupAnyFalse : FilterExpressionType.GroupAny; |
| 566 | + } |
| 567 | + } |
| 568 | + |
| 569 | + function setGroupTruthType(node: DataViewFilterBag, truthType: FilterGroupTruthType): void { |
| 570 | + const isAll = node.expressionType === FilterExpressionType.GroupAll || node.expressionType === FilterExpressionType.GroupAllFalse; |
| 571 | + |
| 572 | + if (truthType === FilterGroupTruthType.True) { |
| 573 | + node.expressionType = isAll ? FilterExpressionType.GroupAll : FilterExpressionType.GroupAny; |
| 574 | + } |
| 575 | + else { |
| 576 | + node.expressionType = isAll ? FilterExpressionType.GroupAllFalse : FilterExpressionType.GroupAnyFalse; |
| 577 | + } |
| 578 | + } |
| 579 | + |
502 | 580 | watch(() => props.modelValue, async () => { |
503 | 581 | const incomingNode = cloneFilterNode(props.modelValue); |
504 | 582 |
|
|
0 commit comments