Skip to content

Commit

Permalink
Merge pull request #3072 from NationalSecurityAgency/t#2218/collapse-…
Browse files Browse the repository at this point in the history
…groups

T#2218/collapse groups
  • Loading branch information
sudo-may authored Jan 10, 2025
2 parents be23d54 + 9fa6d4d commit f69adcd
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 20 deletions.
29 changes: 25 additions & 4 deletions dashboard/src/skills-display/components/progress/SkillProgress.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ limitations under the License.
<script setup>
import SkillProgressNameRow from '@/skills-display/components/progress/skill/SkillProgressNameRow.vue'
import { useRoute } from 'vue-router'
import { computed, ref } from 'vue'
import { computed, ref, watch, onMounted } from 'vue'
import { useSkillsDisplayInfo } from '@/skills-display/UseSkillsDisplayInfo.js'
import SkillsSummaryCards from '@/skills-display/components/progress/SkillsSummaryCards.vue'
import MarkdownText from '@/common-components/utilities/markdown/MarkdownText.vue'
Expand All @@ -29,6 +29,8 @@ import CatalogImportStatus from '@/skills-display/components/progress/CatalogImp
import PartialPointsAlert from '@/skills-display/components/skill/PartialPointsAlert.vue'
import SkillVideo from '@/skills-display/components/progress/SkillVideo.vue';
import dayjs from 'dayjs';
import {useStorage} from "@vueuse/core";
import {useSkillsAnnouncer} from "@/common-components/utilities/UseSkillsAnnouncer.js";
const props = defineProps({
skill: Object,
Expand Down Expand Up @@ -65,10 +67,16 @@ const props = defineProps({
type: Boolean,
default: false,
required: false
},
expandGroups: {
type: Boolean,
default: false,
required: false
}
})
const emit = defineEmits(['add-tag-filter', 'points-earned'])
const emit = defineEmits(['add-tag-filter', 'points-earned', 'reset-group-expansion'])
const route = useRoute()
const announcer = useSkillsAnnouncer()
const skillsDisplayInfo = useSkillsDisplayInfo()
const attributes = useSkillsDisplayAttributesState()
Expand Down Expand Up @@ -120,6 +128,18 @@ const pointsEarned = (pts) => {
}
const isSkillComplete = computed(() => props.skill && props.skill.meta && props.skill.meta.complete)
const storageKey = computed(() => props.skill.projectId + '-' + props.skill.skillId + '-expanded')
const expanded = useStorage(storageKey.value, true)
const toggleRow = () => {
expanded.value = !expanded.value;
announcer.polite(`Group ${props.skill.skill} has been ${expanded.value ? 'expanded' : 'collapsed'}`);
emit('reset-group-expansion')
}
watch(() => props.expandGroups, (newValue) => {
if(newValue !== null && props.skill.type === 'SkillsGroup') {
expanded.value = newValue
}
})
</script>
<template>
Expand All @@ -142,11 +162,12 @@ const isSkillComplete = computed(() => props.skill && props.skill.meta && props.
}}</strong> {{ attributes.projectDisplayName.toLowerCase() }}! Happy playing!!
</Message>
<skill-progress-name-row
:skill="skill"
:badge-is-locked="badgeIsLocked"
:to-route="toRoute"
:is-expanded="expanded"
@toggle-row="toggleRow"
:child-skill-highlight-string="childSkillHighlightString"
:type="type" />
<div class="mt-1">
Expand Down Expand Up @@ -226,7 +247,7 @@ const isSkillComplete = computed(() => props.skill && props.skill.meta && props.
</div>
</div>
<div v-if="skill.isSkillsGroupType && childSkillsInternal" class="ml-4 mt-3">
<div v-if="skill.isSkillsGroupType && childSkillsInternal && expanded" class="ml-4 mt-3">
<div v-for="(childSkill, index) in childSkillsInternal"
:key="`group-${skill.skillId}_skill-${childSkill.skillId}`"
:id="`skillRow-${childSkill.skillId}`"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ import { useSkillsDisplayAttributesState } from '@/skills-display/stores/UseSkil
import { useRoute } from 'vue-router'
import { useThemesHelper } from '@/components/header/UseThemesHelper.js'
// subject: {
// type: Object,
// required: true
// },
const props = defineProps({
showDescriptions: {
type: Boolean,
Expand Down Expand Up @@ -211,16 +207,28 @@ const skillsToShow = computed(() => {
})
resultSkills = filteredRes
}
// this.skillsInternal = resultSkills
return resultSkills
})
const showDescriptionsInternal = ref(false)
const isLastViewedScrollSupported = computed(() => {
return !parentFrame.parentFrame || parentFrame.isLastViewedScrollSupported
})
// this.lastViewedButtonDisabled = resultSkills.findIndex((i) => i.isLastViewed || (i.children && i.children.findIndex((c) => c.isLastViewed) >= 0)) < 0
const expandGroups = ref(null)
const hasGroups = computed(() => {
return !!skillsInternal.value.find(it => it.type === 'SkillsGroup')
})
const expandAllGroups = (() => {
expandGroups.value = true
})
const collapseAllGroups = (() => {
expandGroups.value = false
})
const resetGroupExpansion = (() => {
expandGroups.value = null
})
</script>
<template>
Expand Down Expand Up @@ -275,12 +283,18 @@ const isLastViewedScrollSupported = computed(() => {
<div class="" data-cy="skillDetailsToggle">
<div class="flex flex-row align-content-center">
<span class="text-muted pr-1 align-content-center">{{ attributes.skillDisplayName }} Details:</span>
<InputSwitch v-model="showDescriptionsInternal"
@change="onDetailsToggle"
:aria-label="`Show ${attributes.skillDisplayName} Details`"
data-cy="toggleSkillDetails" />
<div class="flex flex-row flex-wrap align-content-center">
<div class="flex flex-wrap mr-3 gap-2" v-if="!route.params.badgeId && hasGroups">
<SkillsButton label="Expand Groups" icon="fas fa-plus" size="small" data-cy="expandGroupsButton" @click="expandAllGroups"></SkillsButton>
<SkillsButton label="Collapse Groups" icon="fas fa-minus" size="small" data-cy="collapseGroupsButton" @click="collapseAllGroups"></SkillsButton>
</div>
<div class="flex">
<span class="text-muted pr-1 align-content-center">{{ attributes.skillDisplayName }} Details:</span>
<InputSwitch v-model="showDescriptionsInternal"
@change="onDetailsToggle"
:aria-label="`Show ${attributes.skillDisplayName} Details`"
data-cy="toggleSkillDetails" />
</div>
</div>
</div>
Expand Down Expand Up @@ -327,6 +341,8 @@ const isLastViewedScrollSupported = computed(() => {
:ref="`skillProgress${skill.skillId}`"
:skill="skill"
:type="type"
:expand-groups="expandGroups"
@reset-group-expansion="resetGroupExpansion"
:enable-drill-down="true"
:show-description="showDescriptionsInternal"
:data-cy="`skillProgress_index-${index}`"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
<script setup>
import { computed } from 'vue'
import { computed, ref } from 'vue'
import dayjs from 'dayjs'
import { useNumberFormat } from '@/common-components/filter/UseNumberFormat.js'
import { useTimeUtils } from '@/common-components/utilities/UseTimeUtils.js'
Expand All @@ -36,8 +36,13 @@ const props = defineProps({
childSkillHighlightString: {
type: String,
default: ''
},
isExpanded: {
type: Boolean,
default: true
}
})
const emit = defineEmits(['toggle-row']);
const numFormat = useNumberFormat()
const timeUtils = useTimeUtils()
const appConfig = useAppConfig()
Expand Down Expand Up @@ -129,11 +134,10 @@ const skillId = computed(() => {
<div class="sd-theme-primary-color font-medium flex">
<div class="mr-1">
<i v-if="skill.isSkillsGroupType" class="fas fa-layer-group"></i>
<i v-if="!skill.copiedFromProjectId && !skill.isSkillsGroupType"
class="fas fa-graduation-cap text-color-secondary"></i>
<i v-if="!skill.copiedFromProjectId && !skill.isSkillsGroupType" class="fas fa-graduation-cap text-color-secondary"></i>
<i v-if="skill.copiedFromProjectId" class="fas fa-book text-secondary"></i>
</div>
<div class="">
<div>
<div v-if="skillDisplayInfo.isGlobalBadgePage.value">
<span class="font-italic text-color-secondary">{{ attributes.projectDisplayName }}:</span> {{ skill.projectName }}
</div>
Expand All @@ -148,6 +152,15 @@ const skillId = computed(() => {
<div v-else class="inline-block" data-cy="skillProgressTitle">
<highlighted-value :value="skill.skill" :filter="childSkillHighlightString" />
</div>
<SkillsButton :icon="!isExpanded ? 'fas fa-plus' : 'fas fa-minus'"
v-if="skill.isSkillsGroupType"
outlined
:aria-label="!isExpanded ? 'Expand Group' : 'Collapse Group'"
style="padding: 0.3rem 0.3rem 0.3rem 0.1rem;"
class="ml-2"
:data-cy="`toggleGroup-${skillId}`"
@click="emit('toggle-row')">
</SkillsButton>
</div>
</div>
<div v-if="skill.copiedFromProjectId" class="ml-2"
Expand Down
111 changes: 111 additions & 0 deletions e2e-tests/cypress/e2e/client-display/client-display_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,117 @@ describe('Client Display Tests', () => {
});
});

it('ability to expand and collapse groups from subject page', () => {
for(let x = 1; x <= 2; x++) {
cy.createSkillsGroup(1, 2, x);
let startingSkill = 11 * x
for(let y = startingSkill; y < startingSkill + 3; y++) {
cy.addSkillToGroup(1, 2, x, y, {
pointIncrement: 50,
numPerformToCompletion: 2
});
}
}

cy.cdVisit('/', true);
cy.cdClickSubj(1, 'Subject 2', false);

checkGroupSkillExistence(true)

cy.get('[data-cy=collapseGroupsButton]').click()
checkGroupSkillExistence(false)

cy.get('[data-cy=expandGroupsButton]').click()
checkGroupSkillExistence(true)

cy.get('[data-cy="toggleGroup-group1Subj2"]').click()
cy.get('#skillProgressTitleLink-skill11Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill12Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill13Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill22Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill23Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill24Subj2').should('exist');

cy.get('[data-cy="toggleGroup-group2Subj2"]').click()
checkGroupSkillExistence(false)

cy.get('[data-cy="toggleGroup-group1Subj2"]').click()
cy.get('#skillProgressTitleLink-skill11Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill12Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill13Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill22Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill23Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill24Subj2').should('not.exist');
});

it('group expansion state persists', () => {
for(let x = 1; x <= 2; x++) {
cy.createSkillsGroup(1, 2, x);
let startingSkill = 11 * x
for(let y = startingSkill; y < startingSkill + 3; y++) {
cy.addSkillToGroup(1, 2, x, y, {
pointIncrement: 50,
numPerformToCompletion: 2
});
}
}

cy.cdVisit('/subjects/subj2');

checkGroupSkillExistence(true)

cy.get('[data-cy=collapseGroupsButton]').click()
checkGroupSkillExistence(false)

cy.cdVisit('/subjects/subj2');
checkGroupSkillExistence(false)

cy.get('[data-cy=expandGroupsButton]').click()

cy.cdVisit('/subjects/subj2');
checkGroupSkillExistence(true)

cy.get('[data-cy="toggleGroup-group1Subj2"]').click()
cy.get('#skillProgressTitleLink-skill11Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill12Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill13Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill22Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill23Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill24Subj2').should('exist');

cy.cdVisit('/subjects/subj2');
cy.get('#skillProgressTitleLink-skill11Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill12Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill13Subj2').should('not.exist');
cy.get('#skillProgressTitleLink-skill22Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill23Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill24Subj2').should('exist');

cy.get('[data-cy="toggleGroup-group1Subj2"]').click()
cy.get('#skillProgressTitleLink-skill11Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill12Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill13Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill22Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill23Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill24Subj2').should('exist');

cy.cdVisit('/subjects/subj2');
cy.get('#skillProgressTitleLink-skill11Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill12Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill13Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill22Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill23Subj2').should('exist');
cy.get('#skillProgressTitleLink-skill24Subj2').should('exist');
});

const checkGroupSkillExistence = (exists) => {
for(let group = 1; group <= 2; group++) {
let startingSkill = 11 * group
for(let y = startingSkill; y < startingSkill + 3; y++) {
cy.get(`#skillProgressTitleLink-skill${y}Subj2`).should(exists ? 'exist' : 'not.exist');
}
}
}
});


Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f69adcd

Please sign in to comment.