From a79f56ea6042821d513efd0b3ceb00e99f09436a Mon Sep 17 00:00:00 2001 From: Lucas Song Date: Thu, 22 Feb 2024 11:41:43 -0800 Subject: [PATCH 1/9] add filter by grade and filter by school --- src/components/RoarDataTable.vue | 12 +- src/pages/ProgressReport.vue | 356 +++++++++++++++++++++++++++---- 2 files changed, 321 insertions(+), 47 deletions(-) diff --git a/src/components/RoarDataTable.vue b/src/components/RoarDataTable.vue index 3af210212..fade36450 100644 --- a/src/components/RoarDataTable.vue +++ b/src/components/RoarDataTable.vue @@ -232,6 +232,13 @@ style="margin-bottom: 0.5rem" /> +
+ +
@@ -372,7 +379,7 @@ function increasePadding() { } // Generate filters and options objects -const valid_dataTypes = ['NUMERIC', 'NUMBER', 'TEXT', 'STRING', 'DATE', 'BOOLEAN', 'SCORE']; +const valid_dataTypes = ['NUMERIC', 'NUMBER', 'TEXT', 'STRING', 'DATE', 'BOOLEAN', 'SCORE', 'PROGRESS']; let filters = {}; let options = {}; _forEach(computedColumns.value, (column) => { @@ -395,6 +402,9 @@ _forEach(computedColumns.value, (column) => { if (scoredTasks.includes(column.field.split('.')[1])) { returnMatchMode = { value: null, matchMode: FilterMatchMode.STARTS_WITH }; } + } else if (dataType === 'PROGRESS') { + returnMatchMode = { value: null, matchMode: FilterMatchMode.IN }; + options[column.field] = ['Completed', 'Assigned', 'Started']; } if (_get(column, 'useMultiSelect')) { diff --git a/src/pages/ProgressReport.vue b/src/pages/ProgressReport.vue index 42520d7b0..613cce371 100644 --- a/src/pages/ProgressReport.vue +++ b/src/pages/ProgressReport.vue @@ -7,7 +7,7 @@
{{ props.orgType }} Progress Report
- {{ orgInfo.name }} + {{ orgInfo?.name }}
@@ -21,55 +21,80 @@
VIEW
+v-model="reportView" :options="reportViews" option-disabled="constant" :allow-empty="false" + option-label="name" class="flex my-2 select-button" @change="handleViewChange">
- -
+ +
+

No scores found.

+ The filters applied have no matching scores. + Reset filters +
+
+ + + + + + + +
+ @@ -383,6 +632,21 @@ onMounted(async () => { margin-top: 0; } +.no-scores-container { + display: flex; + flex-direction: column; + padding: 2rem; + + h3 { + font-weight: bold; + } + + span { + display: flex; + align-items: center; + } +} + .administration-name { font-size: 1.8rem; font-weight: light; From fbaf949c1f6b9eccc63b1a2ee06f6e539157ab89 Mon Sep 17 00:00:00 2001 From: Lucas Song Date: Fri, 23 Feb 2024 06:00:23 -0800 Subject: [PATCH 2/9] add filter by grade and school --- src/components/RoarDataTable.vue | 4 ++-- src/pages/ProgressReport.vue | 6 +++--- src/pages/ScoreReport.vue | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/RoarDataTable.vue b/src/components/RoarDataTable.vue index fade36450..b4dcd6657 100644 --- a/src/components/RoarDataTable.vue +++ b/src/components/RoarDataTable.vue @@ -403,8 +403,8 @@ _forEach(computedColumns.value, (column) => { returnMatchMode = { value: null, matchMode: FilterMatchMode.STARTS_WITH }; } } else if (dataType === 'PROGRESS') { - returnMatchMode = { value: null, matchMode: FilterMatchMode.IN }; - options[column.field] = ['Completed', 'Assigned', 'Started']; + console.log('progress', column) + returnMatchMode = { value: null, matchMode: FilterMatchMode.EQUALS }; } if (_get(column, 'useMultiSelect')) { diff --git a/src/pages/ProgressReport.vue b/src/pages/ProgressReport.vue index 613cce371..5cf1c044b 100644 --- a/src/pages/ProgressReport.vue +++ b/src/pages/ProgressReport.vue @@ -374,7 +374,7 @@ const onFilter = (event) => { const filters = []; for (const filterKey in _get(event, 'filters')) { const filter = _get(event, 'filters')[filterKey]; - console.log("filter", filter) + console.log("filter", filter, _head(filterKey.split('.'))) const constraint = _head(_get(filter, 'constraints')); if (_get(constraint, 'value')) { const path = filterKey.split('.'); @@ -396,7 +396,7 @@ const onFilter = (event) => { filters.push({ ...constraint, collection: 'users', field: _tail(path).join('.') }); } } - if (_head(path) === 'progress') { + if (_head(path) === 'status') { console.log("progress filter") // const taskId = path[1]; // const cutoffs = getRawScoreThreshold(taskId); @@ -530,7 +530,7 @@ const columns = computed(() => { tableColumns.push({ field: `status.${taskId}.value`, header: taskDisplayNames[taskId]?.name ?? taskId, - dataType: 'progress', + dataType: 'text', tag: true, severityField: `status.${taskId}.severity`, iconField: `status.${taskId}.icon`, diff --git a/src/pages/ScoreReport.vue b/src/pages/ScoreReport.vue index c1e2719dc..2cc4b3e0c 100644 --- a/src/pages/ScoreReport.vue +++ b/src/pages/ScoreReport.vue @@ -696,7 +696,9 @@ const onFilter = (event) => { const filters = []; for (const filterKey in _get(event, 'filters')) { const filter = _get(event, 'filters')[filterKey]; + console.log("filter", filter, _head(filterKey.split('.'))) const constraint = _head(_get(filter, 'constraints')); + console.log("constraint", constraint) if (_get(constraint, 'value')) { const path = filterKey.split('.'); if (_head(path) === 'user') { From 9ebb32a791cde8b9074ff49350758a6aafaf691f Mon Sep 17 00:00:00 2001 From: Lucas Song Date: Mon, 26 Feb 2024 19:21:23 -0800 Subject: [PATCH 3/9] add sort for progress status --- src/components/RoarDataTable.vue | 214 ++++++++++--------------------- src/helpers/query/assignments.js | 159 +++++++++++++---------- src/pages/ProgressReport.vue | 23 ++-- 3 files changed, 171 insertions(+), 225 deletions(-) diff --git a/src/components/RoarDataTable.vue b/src/components/RoarDataTable.vue index b4dcd6657..91f669d00 100644 --- a/src/components/RoarDataTable.vue +++ b/src/components/RoarDataTable.vue @@ -7,46 +7,27 @@ +id="ms-columns" v-tooltip.top="'Show and hide columns'" :model-value="selectedColumns" + :options="inputColumns" option-label="header" :max-selected-labels="3" class="w-2 md:w-20rem" + selected-items-label="{0} columns selected" @update:model-value="onColumnToggle" /> +id="ms-freeze" :model-value="frozenColumns" :options="inputColumns" option-label="header" + :max-selected-labels="3" class="w-2 md:w-20rem" selected-items-label="{0} columns frozen" + :show-toggle-all="false" @update:model-value="onFreezeToggle" /> + label="Export Selected" :disabled="selectedRows.length === 0" @click="exportCSV(true, $event)" /> + label="Export Whole Table" @click="exportCSV(false, $event)" />
@@ -58,126 +39,70 @@ +ref="dataTable" v-model:filters="refFilters" v-model:selection="selectedRows" + class="scrollable-container" :class="{ compressed: compressedRows }" :value="computedData" :row-hover="true" + :reorderable-columns="true" :resizable-columns="true" :export-filename="exportFilename" removable-sort + sort-mode="multiple" show-gridlines filter-display="menu" paginator :rows="props.pageLimit" + :always-show-paginator="true" paginator-position="both" :rows-per-page-options="[10, 25, 50, 100]" + :total-records="props.totalRecords" :lazy="props.lazy" :loading="props.loading" scrollable + :select-all="selectAll" :multi-sort-meta="lazyPreSorting" @page="onPage($event)" @sort="onSort($event)" + @filter="onFilter($event)" @select-all-change="onSelectAll" @row-select="onSelectionChange" + @row-unselect="onSelectionChange"> + header-style="background:var(--primary-color); color:white; padding-top:0; margin-top:0; padding-bottom:0; margin-bottom:0; border:0; margin-left:0"> @@ -404,7 +313,7 @@ _forEach(computedColumns.value, (column) => { } } else if (dataType === 'PROGRESS') { console.log('progress', column) - returnMatchMode = { value: null, matchMode: FilterMatchMode.EQUALS }; + returnMatchMode = { value: null, matchMode: FilterMatchMode.STARTS_WITH }; } if (_get(column, 'useMultiSelect')) { @@ -605,17 +514,19 @@ const onFilter = (event) => { margin-top: 5px; margin-bottom: 5px; } + button.p-button.p-component.softer { background: #f3adad; color: black; } + button.p-column-filter-menu-button.p-link, g { color: white; margin-left: 10px; } -.p-datatable .p-datatable-tbody > tr > td { +.p-datatable .p-datatable-tbody>tr>td { text-align: left; border: 1px solid var(--surface-c); border-width: 0 0 1px 0; @@ -629,6 +540,7 @@ g { font-size: smaller; color: var(--surface-500); } + .view-label2 { position: absolute; top: -15px; @@ -644,24 +556,28 @@ button.p-column-filter-menu-button.p-link:hover { background: var(--surface-500); } -.compressed .p-datatable .p-datatable-tbody > tr > td { +.compressed .p-datatable .p-datatable-tbody>tr>td { text-align: left; border: 1px solid var(--surface-c); border-width: 0 0 3px 0; padding: 1px 1.5rem 2px 1.5rem; } + .filter-content { width: 12rem; } + .filter-button-override .p-column-filter-menu-button:not(.p-column-filter-menu-button-active) { display: none; } + .p-column-filter-matchmode-dropdown { /* Our current filtering queries do not support options other than equals for strings. To reduce confusion for end users, remove the dropdown offering different matchmodes */ display: none; } + .scrollable-container::-webkit-scrollbar { width: 10px; } diff --git a/src/helpers/query/assignments.js b/src/helpers/query/assignments.js index ab60d525b..b93a45a75 100644 --- a/src/helpers/query/assignments.js +++ b/src/helpers/query/assignments.js @@ -334,80 +334,82 @@ export const getFilteredScoresRequestBody = ({ }); } if (filter) { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - compositeFilter: { - op: 'OR', - filters: [ - { - compositeFilter: { - op: 'AND', - filters: [ - { - compositeFilter: { - op: 'OR', - filters: [ - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'EQUAL', - value: { stringValue: 'elementary' }, + if (filter.value === 'Green' || filter.value === 'Yellow' || filter.value === 'Red') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + compositeFilter: { + op: 'OR', + filters: [ + { + compositeFilter: { + op: 'AND', + filters: [ + { + compositeFilter: { + op: 'OR', + filters: [ + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'EQUAL', + value: { stringValue: 'elementary' }, + }, }, - }, - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'EQUAL', - value: { stringValue: 'early-childhood' }, + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'EQUAL', + value: { stringValue: 'early-childhood' }, + }, }, - }, - ], + ], + }, }, - }, - // Add filter inequalities here - // Inequalities that match elementary school students - ], + // Add filter inequalities here + // Inequalities that match elementary school students + ], + }, }, - }, - { - compositeFilter: { - op: 'AND', - filters: [ - { - compositeFilter: { - op: 'OR', - filters: [ - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'EQUAL', - value: { stringValue: 'middle' }, + { + compositeFilter: { + op: 'AND', + filters: [ + { + compositeFilter: { + op: 'OR', + filters: [ + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'EQUAL', + value: { stringValue: 'middle' }, + }, }, - }, - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'EQUAL', - value: { stringValue: 'high' }, + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'EQUAL', + value: { stringValue: 'high' }, + }, }, - }, - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'Equal', - value: { stringValue: 'postsecondary' }, + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'Equal', + value: { stringValue: 'postsecondary' }, + }, }, - }, - ], + ], + }, }, - }, - // Add filter inequalities here - // Inequalities that match middle and high school students - ], + // Add filter inequalities here + // Inequalities that match middle and high school students + ], + }, }, - }, - ], - }, - }); + ], + }, + }); + } if (filter.value === 'Green') { // If the filter requests average students, define filters in which // elementary school students have the inequality percentileScore >= 50 @@ -489,6 +491,33 @@ export const getFilteredScoresRequestBody = ({ }, ); } + if (filter.value === 'Completed') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: 'completed' }, + op: 'EQUAL', + value: { booleanValue: true }, + }, + }); + } + else if (filter.value === 'Started') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: 'completed' }, + op: 'EQUAL', + value: { booleanValue: false }, + }, + }); + } + else if (filter.value === 'Assigned') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: 'timeStarted' }, + op: 'EQUAL', + value: { doubleValue: 0}, + }, + }); + } if (!_isEmpty(grades)) { requestBody.structuredQuery.where.compositeFilter.filters.push({ fieldFilter: { diff --git a/src/pages/ProgressReport.vue b/src/pages/ProgressReport.vue index 5cf1c044b..7753d8fb3 100644 --- a/src/pages/ProgressReport.vue +++ b/src/pages/ProgressReport.vue @@ -263,8 +263,8 @@ const { // Scores count query const { data: assignmentCount } = useQuery({ - queryKey: ['assignments', props.administrationId, props.orgId], - queryFn: () => assignmentCounter(props.administrationId, props.orgType, props.orgId), + queryKey: ['assignments', props.administrationId, props.orgId, filterBy], + queryFn: () => assignmentCounter(props.administrationId, props.orgType, props.orgId, filterBy.value), keepPreviousData: true, enabled: scoreQueryEnabled, staleTime: 5 * 60 * 1000, @@ -398,15 +398,16 @@ const onFilter = (event) => { } if (_head(path) === 'status') { console.log("progress filter") - // const taskId = path[1]; + const taskId = path[1]; // const cutoffs = getRawScoreThreshold(taskId); - // filters.push({ - // ...constraint, - // collection: 'scores', - // taskId: taskId, - // cutoffs, - // field: 'scores.computed.composite.categoryScore', - // }); + filters.push({ + ...constraint, + collection: 'scores', + taskId: taskId, + // cutoffs, + field: 'scores.computed.composite.categoryScore', + }); + console.log("progress", filters) } } } @@ -530,7 +531,7 @@ const columns = computed(() => { tableColumns.push({ field: `status.${taskId}.value`, header: taskDisplayNames[taskId]?.name ?? taskId, - dataType: 'text', + dataType: 'progress', tag: true, severityField: `status.${taskId}.severity`, iconField: `status.${taskId}.icon`, From fed6654e1bacee5e7fa126f59071d1a1cfb6c757 Mon Sep 17 00:00:00 2001 From: Lucas Song Date: Tue, 27 Feb 2024 16:44:50 -0800 Subject: [PATCH 4/9] Fix undefined map bug --- src/components/RoarDataTable.vue | 208 ++++++++++++++++++++++--------- src/helpers/query/assignments.js | 62 ++++++--- src/pages/ProgressReport.vue | 97 +++++++++----- src/pages/ScoreReport.vue | 4 +- 4 files changed, 262 insertions(+), 109 deletions(-) diff --git a/src/components/RoarDataTable.vue b/src/components/RoarDataTable.vue index 91f669d00..81abf8bf0 100644 --- a/src/components/RoarDataTable.vue +++ b/src/components/RoarDataTable.vue @@ -7,27 +7,46 @@ + id="ms-columns" + v-tooltip.top="'Show and hide columns'" + :model-value="selectedColumns" + :options="inputColumns" + option-label="header" + :max-selected-labels="3" + class="w-2 md:w-20rem" + selected-items-label="{0} columns selected" + @update:model-value="onColumnToggle" + /> + id="ms-freeze" + :model-value="frozenColumns" + :options="inputColumns" + option-label="header" + :max-selected-labels="3" + class="w-2 md:w-20rem" + selected-items-label="{0} columns frozen" + :show-toggle-all="false" + @update:model-value="onFreezeToggle" + /> + label="Export Selected" + :disabled="selectedRows.length === 0" + @click="exportCSV(true, $event)" + /> + label="Export Whole Table" + @click="exportCSV(false, $event)" + /> @@ -39,70 +58,126 @@ v-if="allowExport" + ref="dataTable" + v-model:filters="refFilters" + v-model:selection="selectedRows" + class="scrollable-container" + :class="{ compressed: compressedRows }" + :value="computedData" + :row-hover="true" + :reorderable-columns="true" + :resizable-columns="true" + :export-filename="exportFilename" + removable-sort + sort-mode="multiple" + show-gridlines + filter-display="menu" + paginator + :rows="props.pageLimit" + :always-show-paginator="true" + paginator-position="both" + :rows-per-page-options="[10, 25, 50, 100]" + :total-records="props.totalRecords" + :lazy="props.lazy" + :loading="props.loading" + scrollable + :select-all="selectAll" + :multi-sort-meta="lazyPreSorting" + @page="onPage($event)" + @sort="onSort($event)" + @filter="onFilter($event)" + @select-all-change="onSelectAll" + @row-select="onSelectionChange" + @row-unselect="onSelectionChange" + > + header-style="background:var(--primary-color); color:white; padding-top:0; margin-top:0; padding-bottom:0; margin-bottom:0; border:0; margin-left:0" + > @@ -312,7 +403,6 @@ _forEach(computedColumns.value, (column) => { returnMatchMode = { value: null, matchMode: FilterMatchMode.STARTS_WITH }; } } else if (dataType === 'PROGRESS') { - console.log('progress', column) returnMatchMode = { value: null, matchMode: FilterMatchMode.STARTS_WITH }; } @@ -526,7 +616,7 @@ g { margin-left: 10px; } -.p-datatable .p-datatable-tbody>tr>td { +.p-datatable .p-datatable-tbody > tr > td { text-align: left; border: 1px solid var(--surface-c); border-width: 0 0 1px 0; @@ -556,7 +646,7 @@ button.p-column-filter-menu-button.p-link:hover { background: var(--surface-500); } -.compressed .p-datatable .p-datatable-tbody>tr>td { +.compressed .p-datatable .p-datatable-tbody > tr > td { text-align: left; border: 1px solid var(--surface-c); border-width: 0 0 3px 0; diff --git a/src/helpers/query/assignments.js b/src/helpers/query/assignments.js index b93a45a75..15ac69000 100644 --- a/src/helpers/query/assignments.js +++ b/src/helpers/query/assignments.js @@ -129,13 +129,47 @@ export const getAssignmentsRequestBody = ({ } if (!_isEmpty(filter)) { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - fieldFilter: { - field: { fieldPath: `userData.${filter.field}` }, - op: 'EQUAL', - value: { stringValue: filter.value }, - }, - }); + if (filter.value === 'Completed' || filter.value === 'Assigned' || filter.value === 'Started') { + console.log('completed called'); + if (filter.value === 'Completed') { + // console.log('completed called'); + // requestBody.structuredQuery.where.compositeFilter.filters.push({ + // unaryFilter: { + // op: 'IS_NOT_NULL', + // field: { fieldPath: `completed` }, + // }, + // }); + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: `assessments` }, + op: 'EQUAL', + value: { stringValue: '2' }, + }, + }); + } else if (filter.value === 'Assigned') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + unaryFilter: { + op: 'IS_NULL', + field: { fieldPath: `startedOn` }, + }, + }); + } else if (filter.value === 'Started') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + unaryFilter: { + op: 'IS_NOT_NULL', + field: { fieldPath: `startedOn` }, + }, + }); + } + } else { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: `userData.${filter.field}` }, + op: 'EQUAL', + value: { stringValue: filter.value }, + }, + }); + } } } else { const currentDate = new Date().toISOString(); @@ -499,8 +533,7 @@ export const getFilteredScoresRequestBody = ({ value: { booleanValue: true }, }, }); - } - else if (filter.value === 'Started') { + } else if (filter.value === 'Started') { requestBody.structuredQuery.where.compositeFilter.filters.push({ fieldFilter: { field: { fieldPath: 'completed' }, @@ -508,13 +541,12 @@ export const getFilteredScoresRequestBody = ({ value: { booleanValue: false }, }, }); - } - else if (filter.value === 'Assigned') { + } else if (filter.value === 'Assigned') { requestBody.structuredQuery.where.compositeFilter.filters.push({ fieldFilter: { - field: { fieldPath: 'timeStarted' }, + field: { fieldPath: 'completed' }, op: 'EQUAL', - value: { doubleValue: 0}, + value: { nullValue: null }, }, }); } @@ -653,7 +685,7 @@ export const assignmentCounter = (adminId, orgType, orgId, filters = []) => { } }); let requestBody; - if (nonOrgFilter && nonOrgFilter.collection === 'scores') { + if (nonOrgFilter && nonOrgFilter.collection === 'scores' && nonOrgFilter.constraint.value !== 'Assigned') { let orgFilter = null; let gradeFilter = null; if (orgFilters && orgFilters.collection === 'schools' && !_isEmpty(orgFilters.value)) { @@ -950,7 +982,7 @@ export const assignmentPageFetcher = async ( page: page.value, paginate: paginate, select: select, - filter: userFilter, + filter: userFilter || nonOrgFilter, grades: gradeFilter, orderBy: toRaw(orderBy), }); diff --git a/src/pages/ProgressReport.vue b/src/pages/ProgressReport.vue index 7753d8fb3..2b5cae7a1 100644 --- a/src/pages/ProgressReport.vue +++ b/src/pages/ProgressReport.vue @@ -21,8 +21,14 @@
VIEW
+ v-model="reportView" + :options="reportViews" + option-disabled="constant" + :allow-empty="false" + option-label="name" + class="flex my-2 select-button" + @change="handleViewChange" + >
@@ -33,45 +39,65 @@ v-model="reportView" :options="reportViews" option-disabled="constant" :allow-em -->

No scores found.

- The filters applied have no matching scores. + The filters applied have no matching scores. Reset filters
+ v-if="columns?.length ?? 0 > 0" + :data="tableData" + :columns="columns" + :total-records="assignmentCount" + :loading="isLoadingScores || isFetchingScores" + :page-limit="pageLimit" + lazy + :lazy-pre-sorting="sortDisplay" + data-cy="roar-data-table" + :allow-filtering="true" + @page="onPage($event)" + @sort="onSort($event)" + @filter="onFilter($event)" + @export-selected="exportSelected" + @export-all="exportAll" + > - - - -
- @@ -176,7 +202,7 @@ const { data: administrationInfo } = useQuery({ staleTime: 5 * 60 * 1000, // 5 minutes }); -const { data: orgInfo } = useQuery({ +const { dta: orgInfo } = useQuery({ queryKey: ['orgInfo', props.orgId], queryFn: () => fetchDocById(pluralizeFirestoreCollection(props.orgType), props.orgId, ['name']), keepPreviousData: true, @@ -231,7 +257,7 @@ const gradeOptions = ref([ label: '11th Grade', }, { - value: '12th', + value: '12', label: '12th Grade', }, ]); @@ -255,7 +281,19 @@ const { data: assignmentData, } = useQuery({ queryKey: ['assignments', props.administrationId, props.orgId, pageLimit, page, filterBy, orderBy], - queryFn: () => assignmentPageFetcher(props.administrationId, props.orgType, props.orgId, pageLimit, page, false, undefined, true, filterBy.value, orderBy.value), + queryFn: () => + assignmentPageFetcher( + props.administrationId, + props.orgType, + props.orgId, + pageLimit, + page, + false, + undefined, + true, + filterBy.value, + orderBy.value, + ), keepPreviousData: true, enabled: scoreQueryEnabled, staleTime: 5 * 60 * 1000, // 5 mins @@ -307,7 +345,6 @@ const confirm = useConfirm(); const onSort = (event) => { const _orderBy = (event.multiSortMeta ?? []).map((item) => { let field = item.field.replace('user', 'userData'); - console.log("onsort called", field) // Due to differences in the document schemas, // fields found in studentData in the user document are in the // top level of the assignments.userData object. @@ -374,7 +411,6 @@ const onFilter = (event) => { const filters = []; for (const filterKey in _get(event, 'filters')) { const filter = _get(event, 'filters')[filterKey]; - console.log("filter", filter, _head(filterKey.split('.'))) const constraint = _head(_get(filter, 'constraints')); if (_get(constraint, 'value')) { const path = filterKey.split('.'); @@ -397,17 +433,13 @@ const onFilter = (event) => { } } if (_head(path) === 'status') { - console.log("progress filter") const taskId = path[1]; - // const cutoffs = getRawScoreThreshold(taskId); filters.push({ ...constraint, collection: 'scores', taskId: taskId, - // cutoffs, - field: 'scores.computed.composite.categoryScore', + field: 'completed', }); - console.log("progress", filters) } } } @@ -539,7 +571,6 @@ const columns = computed(() => { }); } } - console.log(tableColumns) return tableColumns; }); @@ -600,7 +631,7 @@ const tableData = computed(() => { let unsubscribe; const refreshing = ref(false); const refresh = () => { - console.log("refreshing called") + console.log('refreshing called'); refreshing.value = true; if (unsubscribe) unsubscribe(); @@ -613,7 +644,7 @@ unsubscribe = authStore.$subscribe(async (mutation, state) => { }); const { roarfirekit } = storeToRefs(authStore); onMounted(async () => { - console.log("onmounted called") + console.log('onmounted called'); if (roarfirekit.value.restConfig) refresh(); }); diff --git a/src/pages/ScoreReport.vue b/src/pages/ScoreReport.vue index 2cc4b3e0c..e74380f15 100644 --- a/src/pages/ScoreReport.vue +++ b/src/pages/ScoreReport.vue @@ -696,9 +696,9 @@ const onFilter = (event) => { const filters = []; for (const filterKey in _get(event, 'filters')) { const filter = _get(event, 'filters')[filterKey]; - console.log("filter", filter, _head(filterKey.split('.'))) + console.log('filter', filter, _head(filterKey.split('.'))); const constraint = _head(_get(filter, 'constraints')); - console.log("constraint", constraint) + console.log('constraint', constraint); if (_get(constraint, 'value')) { const path = filterKey.split('.'); if (_head(path) === 'user') { From 2b7e5a448baa28a4d8836bb04cd5def89d3b0570 Mon Sep 17 00:00:00 2001 From: Lucas Song Date: Tue, 27 Feb 2024 16:49:02 -0800 Subject: [PATCH 5/9] remove prototype filtering code from assessments --- src/helpers/query/assignments.js | 52 ++++++-------------------------- 1 file changed, 9 insertions(+), 43 deletions(-) diff --git a/src/helpers/query/assignments.js b/src/helpers/query/assignments.js index 15ac69000..06892e8be 100644 --- a/src/helpers/query/assignments.js +++ b/src/helpers/query/assignments.js @@ -129,47 +129,13 @@ export const getAssignmentsRequestBody = ({ } if (!_isEmpty(filter)) { - if (filter.value === 'Completed' || filter.value === 'Assigned' || filter.value === 'Started') { - console.log('completed called'); - if (filter.value === 'Completed') { - // console.log('completed called'); - // requestBody.structuredQuery.where.compositeFilter.filters.push({ - // unaryFilter: { - // op: 'IS_NOT_NULL', - // field: { fieldPath: `completed` }, - // }, - // }); - requestBody.structuredQuery.where.compositeFilter.filters.push({ - fieldFilter: { - field: { fieldPath: `assessments` }, - op: 'EQUAL', - value: { stringValue: '2' }, - }, - }); - } else if (filter.value === 'Assigned') { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - unaryFilter: { - op: 'IS_NULL', - field: { fieldPath: `startedOn` }, - }, - }); - } else if (filter.value === 'Started') { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - unaryFilter: { - op: 'IS_NOT_NULL', - field: { fieldPath: `startedOn` }, - }, - }); - } - } else { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - fieldFilter: { - field: { fieldPath: `userData.${filter.field}` }, - op: 'EQUAL', - value: { stringValue: filter.value }, - }, - }); - } + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: `userData.${filter.field}` }, + op: 'EQUAL', + value: { stringValue: filter.value }, + }, + }); } } else { const currentDate = new Date().toISOString(); @@ -685,7 +651,7 @@ export const assignmentCounter = (adminId, orgType, orgId, filters = []) => { } }); let requestBody; - if (nonOrgFilter && nonOrgFilter.collection === 'scores' && nonOrgFilter.constraint.value !== 'Assigned') { + if (nonOrgFilter && nonOrgFilter.collection === 'scores') { let orgFilter = null; let gradeFilter = null; if (orgFilters && orgFilters.collection === 'schools' && !_isEmpty(orgFilters.value)) { @@ -982,7 +948,7 @@ export const assignmentPageFetcher = async ( page: page.value, paginate: paginate, select: select, - filter: userFilter || nonOrgFilter, + filter: userFilter, grades: gradeFilter, orderBy: toRaw(orderBy), }); From 569e26bd0e33324582a49bf8b8b46b56c8311395 Mon Sep 17 00:00:00 2001 From: Lucas Song Date: Tue, 27 Feb 2024 17:09:52 -0800 Subject: [PATCH 6/9] fix orgInfo bug --- src/pages/ProgressReport.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ProgressReport.vue b/src/pages/ProgressReport.vue index 2b5cae7a1..4eb832b7c 100644 --- a/src/pages/ProgressReport.vue +++ b/src/pages/ProgressReport.vue @@ -202,7 +202,7 @@ const { data: administrationInfo } = useQuery({ staleTime: 5 * 60 * 1000, // 5 minutes }); -const { dta: orgInfo } = useQuery({ +const { data: orgInfo } = useQuery({ queryKey: ['orgInfo', props.orgId], queryFn: () => fetchDocById(pluralizeFirestoreCollection(props.orgType), props.orgId, ['name']), keepPreviousData: true, From c4294a1ee5ecba58e074d62f956c3c4bbd4d7c62 Mon Sep 17 00:00:00 2001 From: Lucas Song Date: Tue, 5 Mar 2024 11:38:39 -0800 Subject: [PATCH 7/9] Add filtering by progress category --- src/components/RoarDataTable.vue | 2 +- src/helpers/query/assignments.js | 197 +++++++++++++++---------------- src/pages/ProgressReport.vue | 4 +- 3 files changed, 100 insertions(+), 103 deletions(-) diff --git a/src/components/RoarDataTable.vue b/src/components/RoarDataTable.vue index 81abf8bf0..92f62b2fe 100644 --- a/src/components/RoarDataTable.vue +++ b/src/components/RoarDataTable.vue @@ -235,7 +235,7 @@
diff --git a/src/helpers/query/assignments.js b/src/helpers/query/assignments.js index 06892e8be..ba9d59d3a 100644 --- a/src/helpers/query/assignments.js +++ b/src/helpers/query/assignments.js @@ -124,11 +124,31 @@ export const getAssignmentsRequestBody = ({ }); } - if (!_isEmpty(orderBy)) { - requestBody.structuredQuery.orderBy = orderBy; - } - - if (!_isEmpty(filter)) { + if (filter?.value === 'Completed') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: `progress.${filter.taskId}` }, + op: 'EQUAL', + value: { stringValue: 'completed' }, + }, + }); + } else if (filter?.value === 'Started') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: `progress.${filter.taskId}` }, + op: 'EQUAL', + value: { stringValue: 'started' }, + }, + }); + } else if (filter?.value === 'Assigned') { + requestBody.structuredQuery.where.compositeFilter.filters.push({ + fieldFilter: { + field: { fieldPath: `progress.${filter.taskId}` }, + op: 'EQUAL', + value: { stringValue: 'assigned' }, + }, + }); + } else if (!_isEmpty(filter)) { requestBody.structuredQuery.where.compositeFilter.filters.push({ fieldFilter: { field: { fieldPath: `userData.${filter.field}` }, @@ -148,6 +168,10 @@ export const getAssignmentsRequestBody = ({ }; } + if (!_isEmpty(orderBy)) { + requestBody.structuredQuery.orderBy = orderBy; + } + if (aggregationQuery) { return { structuredAggregationQuery: { @@ -334,82 +358,80 @@ export const getFilteredScoresRequestBody = ({ }); } if (filter) { - if (filter.value === 'Green' || filter.value === 'Yellow' || filter.value === 'Red') { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - compositeFilter: { - op: 'OR', - filters: [ - { - compositeFilter: { - op: 'AND', - filters: [ - { - compositeFilter: { - op: 'OR', - filters: [ - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'EQUAL', - value: { stringValue: 'elementary' }, - }, + requestBody.structuredQuery.where.compositeFilter.filters.push({ + compositeFilter: { + op: 'OR', + filters: [ + { + compositeFilter: { + op: 'AND', + filters: [ + { + compositeFilter: { + op: 'OR', + filters: [ + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'EQUAL', + value: { stringValue: 'elementary' }, }, - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'EQUAL', - value: { stringValue: 'early-childhood' }, - }, + }, + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'EQUAL', + value: { stringValue: 'early-childhood' }, }, - ], - }, + }, + ], }, - // Add filter inequalities here - // Inequalities that match elementary school students - ], - }, + }, + // Add filter inequalities here + // Inequalities that match elementary school students + ], }, - { - compositeFilter: { - op: 'AND', - filters: [ - { - compositeFilter: { - op: 'OR', - filters: [ - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'EQUAL', - value: { stringValue: 'middle' }, - }, + }, + { + compositeFilter: { + op: 'AND', + filters: [ + { + compositeFilter: { + op: 'OR', + filters: [ + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'EQUAL', + value: { stringValue: 'middle' }, }, - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'EQUAL', - value: { stringValue: 'high' }, - }, + }, + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'EQUAL', + value: { stringValue: 'high' }, }, - { - fieldFilter: { - field: { fieldPath: 'userData.schoolLevel' }, - op: 'Equal', - value: { stringValue: 'postsecondary' }, - }, + }, + { + fieldFilter: { + field: { fieldPath: 'userData.schoolLevel' }, + op: 'Equal', + value: { stringValue: 'postsecondary' }, }, - ], - }, + }, + ], }, - // Add filter inequalities here - // Inequalities that match middle and high school students - ], - }, + }, + // Add filter inequalities here + // Inequalities that match middle and high school students + ], }, - ], - }, - }); - } + }, + ], + }, + }); if (filter.value === 'Green') { // If the filter requests average students, define filters in which // elementary school students have the inequality percentileScore >= 50 @@ -491,31 +513,6 @@ export const getFilteredScoresRequestBody = ({ }, ); } - if (filter.value === 'Completed') { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - fieldFilter: { - field: { fieldPath: 'completed' }, - op: 'EQUAL', - value: { booleanValue: true }, - }, - }); - } else if (filter.value === 'Started') { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - fieldFilter: { - field: { fieldPath: 'completed' }, - op: 'EQUAL', - value: { booleanValue: false }, - }, - }); - } else if (filter.value === 'Assigned') { - requestBody.structuredQuery.where.compositeFilter.filters.push({ - fieldFilter: { - field: { fieldPath: 'completed' }, - op: 'EQUAL', - value: { nullValue: null }, - }, - }); - } if (!_isEmpty(grades)) { requestBody.structuredQuery.where.compositeFilter.filters.push({ fieldFilter: { @@ -676,7 +673,7 @@ export const assignmentCounter = (adminId, orgType, orgId, filters = []) => { let userFilter = null; let orgFilter = null; let gradeFilter = null; - if (nonOrgFilter && nonOrgFilter.collection === 'users') { + if (nonOrgFilter && nonOrgFilter.collection === 'users' && nonOrgFilter.collection === 'assignments') { userFilter = nonOrgFilter; } if (orgFilters && orgFilters.collection === 'schools' && !_isEmpty(orgFilters.value)) { @@ -691,7 +688,7 @@ export const assignmentCounter = (adminId, orgType, orgId, filters = []) => { orgId: orgFilter ? null : orgId, orgArray: orgFilter, aggregationQuery: true, - filter: userFilter, + filter: userFilter || nonOrgFilter, grades: gradeFilter, }); return adminAxiosInstance.post(':runAggregationQuery', requestBody).then(({ data }) => { @@ -948,7 +945,7 @@ export const assignmentPageFetcher = async ( page: page.value, paginate: paginate, select: select, - filter: userFilter, + filter: userFilter || nonOrgFilter, grades: gradeFilter, orderBy: toRaw(orderBy), }); diff --git a/src/pages/ProgressReport.vue b/src/pages/ProgressReport.vue index 4eb832b7c..1795ba447 100644 --- a/src/pages/ProgressReport.vue +++ b/src/pages/ProgressReport.vue @@ -436,9 +436,9 @@ const onFilter = (event) => { const taskId = path[1]; filters.push({ ...constraint, - collection: 'scores', + collection: 'assignments', taskId: taskId, - field: 'completed', + field: 'progress', }); } } From e668c6c17e3f9e2637d4de85b62e2d070c014419 Mon Sep 17 00:00:00 2001 From: Lucas Song Date: Tue, 5 Mar 2024 14:06:45 -0800 Subject: [PATCH 8/9] clean up console.logs --- src/pages/ProgressReport.vue | 6 ------ src/pages/ScoreReport.vue | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/pages/ProgressReport.vue b/src/pages/ProgressReport.vue index 1795ba447..13762ec56 100644 --- a/src/pages/ProgressReport.vue +++ b/src/pages/ProgressReport.vue @@ -33,10 +33,6 @@ -

No scores found.

{ let unsubscribe; const refreshing = ref(false); const refresh = () => { - console.log('refreshing called'); refreshing.value = true; if (unsubscribe) unsubscribe(); @@ -644,7 +639,6 @@ unsubscribe = authStore.$subscribe(async (mutation, state) => { }); const { roarfirekit } = storeToRefs(authStore); onMounted(async () => { - console.log('onmounted called'); if (roarfirekit.value.restConfig) refresh(); }); diff --git a/src/pages/ScoreReport.vue b/src/pages/ScoreReport.vue index e74380f15..c1e2719dc 100644 --- a/src/pages/ScoreReport.vue +++ b/src/pages/ScoreReport.vue @@ -696,9 +696,7 @@ const onFilter = (event) => { const filters = []; for (const filterKey in _get(event, 'filters')) { const filter = _get(event, 'filters')[filterKey]; - console.log('filter', filter, _head(filterKey.split('.'))); const constraint = _head(_get(filter, 'constraints')); - console.log('constraint', constraint); if (_get(constraint, 'value')) { const path = filterKey.split('.'); if (_head(path) === 'user') { From 47af6f5c0b4107cf5bb63134db6f4ad49e5f551f Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 5 Mar 2024 15:28:23 -0800 Subject: [PATCH 9/9] format --- .../network-tests/roar-swr/playSWR-2G.cy.js | 10 ++-------- .../network-tests/roar-swr/playSWR-3G.cy.js | 10 ++-------- .../network-tests/roar-swr/playSWR-HighLatency.cy.js | 8 +------- 3 files changed, 5 insertions(+), 23 deletions(-) diff --git a/cypress/e2e/participant/network-tests/roar-swr/playSWR-2G.cy.js b/cypress/e2e/participant/network-tests/roar-swr/playSWR-2G.cy.js index c4f6ee4a1..e1e94a899 100644 --- a/cypress/e2e/participant/network-tests/roar-swr/playSWR-2G.cy.js +++ b/cypress/e2e/participant/network-tests/roar-swr/playSWR-2G.cy.js @@ -10,15 +10,9 @@ describe('Testing playthrough of SWR as a participant under a 2G Mobile connecti cy.wait(0.5 * timeout); cy.visit('/'); - cy.get('.p-dropdown-trigger', { timeout: 3 * timeout }) - .should('be.visible') - .click(); - cy.get('.p-dropdown-item', { timeout: 3 * timeout }) - .contains(Cypress.env('testRoarAppsAdministration')) - .should('be.visible') - .click(); + cy.selectAdministration(Cypress.env('testRoarAppsAdministration')); - cy.get('.p-tabview').contains('ROAR - Word'); + cy.get('.p-tabview', { timeout: 3 * timeout }).contains('ROAR - Word'); cy.visit(`/game/swr`); cy.get('.jspsych-btn', { timeout: 3 * timeout }) diff --git a/cypress/e2e/participant/network-tests/roar-swr/playSWR-3G.cy.js b/cypress/e2e/participant/network-tests/roar-swr/playSWR-3G.cy.js index 8cca35d50..f9c2c5ce2 100644 --- a/cypress/e2e/participant/network-tests/roar-swr/playSWR-3G.cy.js +++ b/cypress/e2e/participant/network-tests/roar-swr/playSWR-3G.cy.js @@ -10,15 +10,9 @@ describe('Testing playthrough of SWR as a participant under a 3G Mobile connecti cy.wait(0.3 * timeout); cy.visit('/'); - cy.get('.p-dropdown-trigger', { timeout: 2 * timeout }) - .should('be.visible') - .click(); - cy.get('.p-dropdown-item', { timeout: 2 * timeout }) - .contains(Cypress.env('testRoarAppsAdministration')) - .should('be.visible') - .click(); + cy.selectAdministration(Cypress.env('testRoarAppsAdministration')); - cy.get('.p-tabview').contains('ROAR - Word'); + cy.get('.p-tabview', { timeout: 2 * timeout }).contains('ROAR - Word'); cy.visit(`/game/swr`); cy.get('.jspsych-btn', { timeout: 2 * timeout }) diff --git a/cypress/e2e/participant/network-tests/roar-swr/playSWR-HighLatency.cy.js b/cypress/e2e/participant/network-tests/roar-swr/playSWR-HighLatency.cy.js index 094ad0a5f..e5abdfe55 100644 --- a/cypress/e2e/participant/network-tests/roar-swr/playSWR-HighLatency.cy.js +++ b/cypress/e2e/participant/network-tests/roar-swr/playSWR-HighLatency.cy.js @@ -10,13 +10,7 @@ describe('Testing playthrough of SWR as a participant under a 2G Mobile connecti cy.wait(0.5 * timeout); cy.visit('/'); - cy.get('.p-dropdown-trigger', { timeout: 6 * timeout }) - .should('be.visible') - .click(); - cy.get('.p-dropdown-item', { timeout: 6 * timeout }) - .contains(Cypress.env('testRoarAppsAdministration')) - .should('be.visible') - .click(); + cy.selectAdministration(Cypress.env('testRoarAppsAdministration')); cy.get('.p-tabview', { timeout: 6 * timeout }).contains('ROAR - Word'); cy.visit(`/game/swr`);