Skip to content

Commit

Permalink
Merge pull request #18074 from hujambo-dunia/enhance-form-drilldown
Browse files Browse the repository at this point in the history
Enhance form drilldown
  • Loading branch information
dannon authored May 20, 2024
2 parents 9843034 + 1edab2f commit 1d345d6
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 62 deletions.
36 changes: 24 additions & 12 deletions client/src/components/Form/Elements/FormDrilldown/FormDrilldown.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed, type ComputedRef } from "vue";
import { getAllValues, type Option, type Value } from "./utilities";
import { findDescendants, flattenValues, getAllValues, type Option, type Value } from "./utilities";
import FormDrilldownList from "./FormDrilldownList.vue";
Expand Down Expand Up @@ -53,29 +53,41 @@ const selectAllIndeterminate: ComputedRef<boolean> = computed(() => {
});
// Handle click on individual check/radio element
function handleClick(value: string): void {
function handleClick(clickedElement: string, value: string): void {
if (props.multiple) {
const newValue: string[] = currentValue.value.slice();
const index: number = newValue.indexOf(value);
if (index !== -1) {
newValue.splice(index, 1);
} else {
newValue.push(value);
}
if (newValue.length === 0) {
const clickedElements: string[] = addDescendants(props.options, clickedElement);
const selectedElements: string[] = setElementValues(currentValue.value, clickedElements, value);
if (selectedElements.length === 0) {
emit("input", null);
} else {
emit("input", newValue);
emit("input", selectedElements);
}
} else {
emit("input", value);
emit("input", clickedElement);
}
}
// Handle click on select all checkbox to either select or unselect all values
function onSelectAll(selected: boolean): void {
emit("input", selected ? allValues.value : null);
}
// Returns the descendant values and the selected/parent value (regardless of unselected or selected)
function addDescendants(selectOptions: any[], selectedValue: string): string[] {
const descendants: any[] | null = findDescendants(selectOptions, selectedValue);
const allValues = flattenValues(descendants);
allValues.unshift(selectedValue);
return allValues;
}
function setElementValues(oldArray: string[], newArray: string[], value: string): string[] {
if (value) {
return Array.from(new Set([...oldArray, ...newArray]));
} else {
const newSet = new Set(newArray);
return oldArray.filter((item) => !newSet.has(item));
}
}
</script>

<template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ defineProps<{
</script>

<template>
<div>
<div v-for="option in options" :key="option.name" class="ui-drilldown">
<div class="ui-drilldown">
<div v-for="option in options" :key="option.name" class="descendant-lines">
<FormDrilldownOption
:current-value="currentValue"
:handle-click="handleClick"
Expand All @@ -22,3 +22,15 @@ defineProps<{
</div>
</div>
</template>

<style lang="scss" scoped>
@import "theme/blue.scss";
.ui-drilldown {
$ui-drilldown-border: 0.5px solid $gray-500;
/* selector: all except first nested drilldown */
& > * .descendant-lines {
border-left: $ui-drilldown-border;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,45 @@ onMounted(() => {
<template>
<div>
<b-button v-if="hasOptions" variant="link" class="btn p-0" @click="toggleChildren">
<i v-if="showChildren" class="fa fa-minus-square" />
<i v-else class="fa fa-plus-square" />
<i v-if="showChildren" class="fa fa-caret-down align-checkbox" />
<i v-else class="fa fa-caret-right align-checkbox" />
</b-button>
<span v-if="!hasOptions" class="align-indent"></span>
<component
:is="isComponent"
class="drilldown-option d-inline"
value="true"
:checked="isChecked"
@change="handleClick(option.value)">
@change="handleClick(option.value, $event)">
{{ option.name }}
</component>
<FormDrilldownList
v-if="hasOptions"
v-show="showChildren"
class="pl-5"
class="indent"
:current-value="currentValue"
:multiple="multiple"
:options="option.options"
:handle-click="handleClick" />
</div>
</template>

<style lang="scss" scoped>
@import "theme/blue.scss";
.ui-drilldown {
$ui-drilldown-padding: 1rem;
$ui-drilldown-border: 0.5px solid $gray-500;
.indent {
padding-left: calc($ui-drilldown-padding + $ui-drilldown-padding/2);
}
.align-indent {
display: inline-block;
width: $ui-drilldown-padding;
border-bottom: $ui-drilldown-border;
}
.align-checkbox {
width: $ui-drilldown-padding;
}
}
</style>
41 changes: 41 additions & 0 deletions client/src/components/Form/Elements/FormDrilldown/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,44 @@ export function getAllValues(headOptions: Array<Option>): string[] {
}
return values;
}

/**
* Returns all types of "decendants" (child, grandchild, and so forth) in nested array (or null).
* @param objects Array of Option objects with all keys intact
* @returns values: string[]
*/
export function findDescendants(objects: Array<Option>, search: string): any[] | null {
const stack: Array<Option> = [...objects];
while (stack.length > 0) {
const current = stack.pop();
if (current === undefined) {
return null;
} else {
if (current.value === search) {
return current.options;
}
if (current.options && Array.isArray(current.options)) {
stack.push(...current.options);
}
}
}

return null;
}

export function flattenValues(objects: any): string[] {
const newArray = [];
const stack = [...objects];

while (stack.length > 0) {
const current = stack.pop();
if (current.value) {
newArray.push(current.value);
}
if (current.options && Array.isArray(current.options)) {
stack.push(...current.options);
}
}

return newArray;
}
2 changes: 1 addition & 1 deletion client/src/style/scss/theme/blue.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ $gray-900: $text-color;
$gray-800: $text-muted;
$gray-700: $text-muted;
$gray-600: $text-muted;
$gray-500: $text-muted;
$gray-500: darken($brand-light, 30%);
$gray-400: $border-color;
$black: $brand-dark;

Expand Down
42 changes: 0 additions & 42 deletions client/src/style/scss/ui.scss
Original file line number Diff line number Diff line change
Expand Up @@ -254,48 +254,6 @@ $ui-margin-horizontal-large: $margin-v * 2;
}
}

.ui-options {
.ui-options-list {
@extend .ui-input;
height: 100% !important;
input[type="checkbox"],
input[type="radio"] {
display: none;
}
label {
margin: 0px;
cursor: pointer;
}
.ui-drilldown-button {
float: left;
cursor: pointer;
font-size: 1.2em;
margin-right: 5px;
margin-top: 3px;
}
.ui-drilldown-subgroup {
display: none;
margin-left: 25px;
}
input[type="checkbox"] + label:before {
@extend .far;
margin-right: 5px;
content: fa-content($fa-var-square);
}
input[type="checkbox"]:checked + label:before {
content: fa-content($fa-var-check-square);
}
input[type="radio"] + label:before {
@extend .far;
margin-right: 5px;
content: fa-content($fa-var-circle);
}
input[type="radio"]:checked + label:before {
content: fa-content($fa-var-check-circle);
}
}
}

.ui-select {
position: relative;
.icon-dropdown {
Expand Down
2 changes: 1 addition & 1 deletion client/src/utils/navigation/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -567,7 +567,7 @@ tool_form:
storage_options: '.tool-storage'
drilldown_select_all: 'div.ui-form-element[id="form-element-${parameter}"] div.select-all-checkbox'
drilldown_option: '.drilldown-option'
drilldown_expand: '.fa-plus-square'
drilldown_expand: '.fa-caret-down'

labels:
generate_tour: 'Generate Tour'
Expand Down

0 comments on commit 1d345d6

Please sign in to comment.