diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml index d1f89082..00fbb5ee 100644 --- a/.github/workflows/cd.yaml +++ b/.github/workflows/cd.yaml @@ -14,7 +14,7 @@ jobs: uses: actions/checkout@v4 - name: Set up node env - uses: actions/setup-node@v3.8.1 + uses: actions/setup-node@v3.8.2 with: node-version: 18 diff --git a/.github/workflows/test_e2e.yml b/.github/workflows/test_e2e.yml index c28dde04..dd77dc3a 100644 --- a/.github/workflows/test_e2e.yml +++ b/.github/workflows/test_e2e.yml @@ -10,7 +10,7 @@ jobs: uses: actions/checkout@v4 - name: Set up node env - uses: actions/setup-node@v3.8.1 + uses: actions/setup-node@v3.8.2 with: node-version: 16 diff --git a/components/annot-columns.vue b/components/annot-columns.vue index e69ca35c..3b064673 100644 --- a/components/annot-columns.vue +++ b/components/annot-columns.vue @@ -13,7 +13,7 @@ data-cy="mappedColumns" class="d-flex justify-content-between align-items-center" :key="columnName" - v-for="columnName of getMappedColumns(activeCategory)"> + v-for="columnName of getColumnsForCategory(activeCategory)"> {{ columnName }} {{ getColumnDescription(columnName) }} @@ -93,7 +93,7 @@ "getHarmonizedPreview", "getHeuristic", - "getMappedColumns", + "getColumnsForCategory", "getTransformOptions", "getUniqueValues" ]) diff --git a/components/annot-single-tool.vue b/components/annot-single-tool.vue new file mode 100644 index 00000000..ae4d3b23 --- /dev/null +++ b/components/annot-single-tool.vue @@ -0,0 +1,59 @@ + + + \ No newline at end of file diff --git a/components/annot-tool-groups.vue b/components/annot-tool-groups.vue new file mode 100644 index 00000000..483ea012 --- /dev/null +++ b/components/annot-tool-groups.vue @@ -0,0 +1,53 @@ + + + \ No newline at end of file diff --git a/components/category-toolgroup.vue b/components/category-toolgroup.vue new file mode 100644 index 00000000..3c2ceb14 --- /dev/null +++ b/components/category-toolgroup.vue @@ -0,0 +1,127 @@ + + + + diff --git a/cypress/component/annot-columns.cy.js b/cypress/component/annot-columns.cy.js index db62d369..7df78ab3 100644 --- a/cypress/component/annot-columns.cy.js +++ b/cypress/component/annot-columns.cy.js @@ -4,7 +4,7 @@ import annotColumns from "~/components/annot-columns.vue"; const store = { commit: () => {}, getters: { - getMappedColumns: () => (activeCategory) => { + getColumnsForCategory: () => (activeCategory) => { return [ "column1", "column2", diff --git a/cypress/component/annot-continuous-values.cy.js b/cypress/component/annot-continuous-values.cy.js index 4e4389f3..16889446 100644 --- a/cypress/component/annot-continuous-values.cy.js +++ b/cypress/component/annot-continuous-values.cy.js @@ -36,7 +36,7 @@ describe("Continuous values component", () => { return store.state.dataDictionary.annotated[p_column].transformationHeuristic; }, - getMappedColumns: () => (p_activeCategory) => { + getColumnsForCategory: () => (p_activeCategory) => { return ["column1"]; }, @@ -153,7 +153,7 @@ describe("Continuous values component", () => { // Setup store.state.dataDictionary.annotated["column2"] = { transformationHeuristic: "" }; - store.getters.getMappedColumns = () => (p_activeCategory) => { + store.getters.getColumnsForCategory = () => (p_activeCategory) => { return ["column1", "column2"]; }; @@ -196,7 +196,7 @@ describe("Continuous values component", () => { // Setup store.state.dataDictionary.annotated["column2"] = { transformationHeuristic: "" }; - store.getters.getMappedColumns = () => (p_activeCategory) => { + store.getters.getColumnsForCategory = () => (p_activeCategory) => { return ["column1", "column2"]; }; diff --git a/cypress/component/annot-tool-groups.cy.js b/cypress/component/annot-tool-groups.cy.js new file mode 100644 index 00000000..7e2dcf70 --- /dev/null +++ b/cypress/component/annot-tool-groups.cy.js @@ -0,0 +1,95 @@ +import annotToolGroups from "~/components/annot-tool-groups.vue"; +import annotSingleTool from "~/components/annot-single-tool.vue"; + +const getters = { + getSelectedTools: () => { + return [ + { + label: "MOCA", + identifier: "cogAtlas:MOCA", + selected: true + }, + { + label: "UPDRS", + identifier: "cogAtlas:UPDRS", + selected: true + } + ]; + }, + getColumnsForTool: () => (p_tool) => { + return ["column1", "column2"]; + }, + getUniqueColumnValues: () => (column) => { + return [1, 2, 3]; + } +}; + +const stubs = { + + "annot-single-tool": annotSingleTool +}; + + +const props = [ + { + column: "column1", + value: "val1" + }, + { + column: "column2", + value: "val1" + }, + { + column: "column2", + value: "val2" + } +]; + + +describe("Annotation tool component", () => { + + it("Takes a list of tools and makes a tab for each tool", () => { + cy.mount(annotToolGroups, { + computed: getters, + stubs: stubs, + props: props + }); + cy.contains('MOCA'); + cy.contains('UPDRS'); + }); + + it("mounts a subcomponent for each tool and provides the correct props to it", () => { + cy.mount(annotToolGroups, { + computed: getters, + stubs: stubs, + props: props + }); + cy.get('[data-cy="tool-annotation-for-cogAtlas:MOCA"]').contains('column1'); + }); + + it("clicking the missing value button fires correct mutation", () => { + const mockStore = { commit: () => {} }; + cy.spy(mockStore, "commit").as("commitSpy"); + + cy.mount(annotToolGroups, { + computed: getters, + stubs: stubs, + props: props, + mocks: { $store: mockStore } + }); + + cy.get('[data-cy="tool-annotation-for-cogAtlas:MOCA"]') + .get('table') + .find('tr') + .eq(1) + .then(row => { + cy.wrap(row).contains("Mark as missing").click(); + }); + + cy.get("@commitSpy").should("have.been.calledOnceWith", "changeMissingStatus", { + column: "column1", + value: 1, + markAsMissing: true + }); + }); +}); diff --git a/cypress/component/annot-tool-single.cy.js b/cypress/component/annot-tool-single.cy.js new file mode 100644 index 00000000..ad4c5082 --- /dev/null +++ b/cypress/component/annot-tool-single.cy.js @@ -0,0 +1,73 @@ +import annotSingleTool from "~/components/annot-single-tool.vue"; + +const props = { + name: "Hello", + uniqueColumnValues: [ + { + column: "column1", + value: "val1" + }, + { + column: "column2", + value: "val1" + }, + { + column: "column2", + value: "val2" + } + ] +}; + + +describe("Annotation tool component", () => { + + it("shows me a table of unique values when I provide the props", () => { + cy.mount(annotSingleTool, { + propsData: props + }); + cy.get("table").should("exist"); + cy.get("table").contains("column1"); + + }); + + it("each row has a button called 'Mark as missing'", () => { + cy.mount(annotSingleTool, { + propsData: props + }); + + cy.get('table') + .find('tr') + .each((row, index) => { + // skip the first (header) row + if (index !== 0) { + cy.wrap(row) + .contains("Mark as missing"); + } + }); + + }); + + it("clicking the missing value button emits a 'declareMissing' event", () => { + const spy = cy.spy().as("emitSpy"); + cy.mount(annotSingleTool, { + propsData: props, + listeners: { + declareMissing: spy + } + }); + + cy.get('table') + .find('tr') + .eq(1) // Select the second row (0 index), see https://docs.cypress.io/api/commands/eq + .then(row => { + cy.wrap(row).contains("Mark as missing").click(); + }); + cy.get("@emitSpy") + .should("have.been.calledWith", { + column: "column1", + value: "val1" + }); + + }); + +}); diff --git a/cypress/component/category-toolgroup.cy.js b/cypress/component/category-toolgroup.cy.js new file mode 100644 index 00000000..801d59a0 --- /dev/null +++ b/cypress/component/category-toolgroup.cy.js @@ -0,0 +1,234 @@ +import categoryToolGroup from "~/components/category-toolgroup.vue"; + +let store; +let state; +let getters; + +describe("Tool Group component", () => { + + beforeEach(() => { + state = { + + columnToToolMap: { + column1: 'cogatlas:MOCA', + column2: null, + column3: 'cogatlas:UPDRSIII' + }, + + toolTerms: [ + {label: 'MOCA', identifier: 'cogatlas:MOCA', selected: false}, + {label: 'UPDRSIII', identifier: 'cogatlas:UPDRSIII', selected: false}, + {label: 'SomeOtherThing', identifier: 'cogatlas:SomeOtherThing', selected: false}, + {label: 'AnotherThing', identifier: 'cogatlas:AnotherThing', selected: false} + ] + }; + getters = { + getColumnsForCategory: () => (p_category) => { + return ["column1", "column3"]; + }, + getSelectedTools: () => { + return [ + {label: 'MOCA', identifier: 'cogatlas:MOCA', selected: true}, + {label: 'UPDRSIII', identifier: 'cogatlas:UPDRSIII', selected: true} + ]; + } + }; + store = { + + commit: () => {}, + state: state, + getters: getters + }; + }); + + it("if nothing is selected or mapped, component is empty", () => { + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: { + getColumnsForCategory: () => (p_category) => { + return []; + }, + getSelectedTools: () => { + return []; + } + } + }); + + cy.get("[data-cy='toolgroup-select']").should('not.exist'); + cy.get("[data-cy='assessment-tool-table']").should('not.exist'); + cy.get("[data-cy='assessment-column-table']").should('not.exist'); + + }); + + it("gets columns about assessment tools from the store and shows them to me", () => { + + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: Object.assign(store.getters, {getSelectedTools: () => { + return []; + }}) + }); + + cy.get("[data-cy='assessment-column-table']").should("be.visible"); + cy.get("[data-cy='assessment-column-table']").contains("column1"); + cy.get("[data-cy='assessment-column-table']").contains("column3"); + }); + + it("before a tool is selected, all columns are unstyled", () => { + store.state.columnToToolMap = { + column1: null, + column2: null, + column3: null + }; + + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: Object.assign(store.getters, {getSelectedTools: () => { + return []; + }}) + }); + + cy.get("[data-cy='assessment-column-table']").find("tr:contains('column1')").should('not.have.class', 'selected-tool'); + cy.get("[data-cy='assessment-column-table']").find("tr:contains('column3')").should('not.have.class', 'selected-tool'); + + }); + + it("gets assessment tool names from the store and shows them in a dropdown", () => { + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: store.getters + }); + + cy.get("[data-cy='toolgroup-select']").should("be.visible"); + cy.get("[data-cy='toolgroup-select']").type("MOCA{enter}"); + cy.get("[data-cy='toolgroup-select']").should("contain", "MOCA"); + }); + + it("selecting a tool group fires a createAssessmentTool mutation", () => { + cy.spy(store, "commit").as("commitSpy"); + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: Object.assign(store.getters, {getSelectedTools: () => { + return []; + }}) + }); + + cy.get("[data-cy='toolgroup-select']").type("MOCA{enter}"); + cy.get("@commitSpy").should("have.been.calledWith", "createAssessmentTool", { identifier: 'cogatlas:MOCA', label: 'MOCA' }); + + }); + + it("clearing the dropdown selection does not crash the app", () => { + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: Object.assign(store.getters, {getSelectedTools: () => { + return []; + }}) + }); + + cy.get("[data-cy='toolgroup-select']").type("MOCA{enter}"); + cy.get("[data-cy='toolgroup-select']").get('button').click(); + + }); + + it("when a tool is selected in the store, it appears in the tool table", () => { + store.state.toolTerms[0]['selected'] = true; + + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: store.getters + }); + + cy.get("[data-cy='assessment-tool-table']").contains('MOCA'); + }); + + it("tools in the tool-table start unselected and become styled when clicked", () => { + store.state.toolTerms[0]['selected'] = true; + store.state.toolTerms[2]['selected'] = true; + + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: store.getters + }); + + cy.get("[data-cy='assessment-tool-table']").find("tr:contains('MOCA')") + .invoke("css", "background-color").then((InitialBackgroundColor) => { + cy.get("[data-cy='assessment-tool-table']") + .find("tr:contains('MOCA')").click(); + // assert that element has different color after + cy.get("[data-cy='assessment-tool-table']").find("tr:contains('MOCA')").should("not.have.css", "background-color", InitialBackgroundColor); + }); + }); + + it("if a tool is already created, trying to create it again has no effect", () => { + store.state.toolTerms[0]['selected'] = true; + + cy.spy(store, "commit").as("commitSpy"); + + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: store.getters + }); + cy.get("[data-cy='assessment-tool-table']").contains("MOCA").click(); + cy.get("@commitSpy").should("not.have.been.called"); + + }); + + it("when I click on a tool the tool gets highlighted", () => { + store.state.toolTerms[0]['selected'] = true; + + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: store.getters + }); + + cy.get("[data-cy='assessment-tool-table']").find("tr:contains('MOCA')") + .invoke("css", "background-color").then((InitialBackgroundColor) => { + cy.get("[data-cy='assessment-tool-table']") + .find("tr:contains('MOCA')").click(); + // assert that element has different color after + cy.get("[data-cy='assessment-tool-table']").find("tr:contains('MOCA')").should("not.have.css", "background-color", InitialBackgroundColor); + }); + }); + + it("clicking on column with tool fires mapping mutation every time", () => { + store.state.toolTerms[0]['selected'] = true; + + cy.spy(store, "commit").as("commitSpy"); + + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: store.getters + }); + + cy.get("[data-cy='assessment-tool-table']").contains('MOCA').click(); + cy.get("[data-cy='assessment-column-table']").contains("column1").click(); + cy.get("@commitSpy").should("have.been.calledWith", "alterColumnToToolMapping", {columnName:"column1", toolIdentifier: "cogatlas:MOCA"}); + cy.get("[data-cy='assessment-column-table']").contains("column1").click(); + cy.get("@commitSpy").should("have.been.calledWith", "alterColumnToToolMapping", {columnName:"column1", toolIdentifier: "cogatlas:MOCA"}); + cy.get("[data-cy='assessment-column-table']").contains("column3").click(); + cy.get("@commitSpy").should("have.been.calledWith", "alterColumnToToolMapping", {columnName: "column3", toolIdentifier: "cogatlas:MOCA"}); + }); + + it("when a column is mapped to a tool and the tool gets selected, the column gets highlighted", () => { + // MOCA + store.state.toolTerms[0]['selected'] = true; + // UPDRS + store.state.toolTerms[1]['selected'] = true; + + cy.mount(categoryToolGroup, { + mocks: { $store: store }, + computed: store.getters + }); + // Starting out with a different tool selected + cy.get("[data-cy='assessment-tool-table']").find("tr:contains('MOCA')").click(); + cy.get("[data-cy='assessment-column-table']").find("tr:contains('column3')") + .invoke("css", "background-color").then((InitialBackgroundColor) => { + cy.get("[data-cy='assessment-tool-table']") + // Selecting the tool my column is mapped to should change my columns styling + .find("tr:contains('UPDRSIII')").click(); + // assert that element has different color after + cy.get("[data-cy='assessment-column-table']").find("tr:contains('column3')").should("not.have.css", "background-color", InitialBackgroundColor); + }); + }); +}); diff --git a/cypress/e2e/page/annotation-pagetests.cy.js b/cypress/e2e/page/annotation-pagetests.cy.js index bf53b82d..75e0199b 100644 --- a/cypress/e2e/page/annotation-pagetests.cy.js +++ b/cypress/e2e/page/annotation-pagetests.cy.js @@ -49,7 +49,6 @@ describe("tests on annotation page ui with programmatic state loading and store it("Annotate age column; default age format transformations", () => { cy.window().its("$nuxt.$store").then(p_store => { - console.dir(p_store); }); // 0. Categories required for this test and the number of required columns for each category diff --git a/cypress/e2e/page/my_happy_annotation-page_tests.cy.js b/cypress/e2e/page/my_happy_annotation-page_tests.cy.js new file mode 100644 index 00000000..6eed8fe4 --- /dev/null +++ b/cypress/e2e/page/my_happy_annotation-page_tests.cy.js @@ -0,0 +1,63 @@ +describe("to annotate an assessment ", () => { + + + it("sets up some stuff", () => { + // Load some data + cy.visit('/'); + cy.get('[data-cy="data-table-selector"]').get('input').selectFile('cypress/fixtures/examples/good/example.tsv', { force: true }); + cy.get("[data-cy='button-nextpage']").click(); + + // Categorize some columns + const desiredColumnMappings = [ + { + "column": "participant_id", + "category": "Subject ID" + }, + { + "column": "sex", + "category": "Sex" + }, + { + "column": "group", + "category": "Diagnosis" + }, + { + "column": "stroop", + "category": "Assessment Tool" + }, + { + "column": "iq", + "category": "Assessment Tool" + } + ]; + desiredColumnMappings.forEach(desiredColumnMapping => { + cy.get("[data-cy='categorization-table']").contains(desiredColumnMapping.category).click(); + cy.get("[data-cy='column-linking-table']").contains(desiredColumnMapping.column).click(); + }); + // Create two tools + cy.get("[data-cy='toolgroup-select']").type("MOCA{enter}"); + cy.get("[data-cy='toolgroup-select']").type("UPDRS{enter}"); + // Map columns to tools + const desiredColumnToolMappings = [ + { + "column": "iq", + "tool": "MOCA" + }, + { + "column": "stroop", + "tool": "UPDRS" + } + ]; + desiredColumnToolMappings.forEach(desiredColumnToolMapping => { + cy.get("[data-cy='assessment-tool-table']").contains(desiredColumnToolMapping.tool).click(); + cy.get("[data-cy='assessment-column-table']").contains(desiredColumnToolMapping.column).click(); + }); + + // We apparently are unable to use the normal "next page" button here + // for some reason I don't yet understand. So we can force-route ourselves + // to the next page here despite the button erroneously not being enabled. + cy.window().its("$nuxt.$router").then(router => { + router.push({ path: "/annotation" }); + }); + }); +}); \ No newline at end of file diff --git a/cypress/unit/store-getter-getMappedColumns.cy.js b/cypress/unit/store-getter-getColumnsForCategory.cy.js similarity index 63% rename from cypress/unit/store-getter-getMappedColumns.cy.js rename to cypress/unit/store-getter-getColumnsForCategory.cy.js index bd8ccdf7..7cce2136 100644 --- a/cypress/unit/store-getter-getMappedColumns.cy.js +++ b/cypress/unit/store-getter-getColumnsForCategory.cy.js @@ -13,17 +13,17 @@ const store = { } }; -describe("getMappedColumns", () => { +describe("getColumnsForCategory", () => { it("Gets list of columns of a given category", () => { // Assert - expect(getters.getMappedColumns(store.state)("category1")).to.deep.equal(["column1", "column3"]); + expect(getters.getColumnsForCategory(store.state)("category1")).to.deep.equal(["column1", "column3"]); }); it("Gets empty list if a given category is not assigned to any columns", () => { // Assert - expect(getters.getMappedColumns(store.state)("category4")).to.deep.equal([]); + expect(getters.getColumnsForCategory(store.state)("category4")).to.deep.equal([]); }); -}); \ No newline at end of file +}); diff --git a/cypress/unit/store-getter-getColumnsForTool.cy.js b/cypress/unit/store-getter-getColumnsForTool.cy.js new file mode 100644 index 00000000..6a88c50d --- /dev/null +++ b/cypress/unit/store-getter-getColumnsForTool.cy.js @@ -0,0 +1,29 @@ +import { getters } from "~/store"; + +const store = { + + state: { + + columnToToolMap: { + "column1": "cogatlas:MOCA", + "column2": null, + "column3": "cogatlas:MOCA", + "column4": "cogatlas:UPDRS" + } + } +}; + +describe("getColumnsForTool", () => { + + it("Gets list of columns mapped to a given tool", () => { + + // Assert + expect(getters.getColumnsForTool(store.state)("cogatlas:MOCA")).to.deep.equal(["column1", "column3"]); + }); + + it("Gets empty list if no column was assigned to this tool", () => { + + // Assert + expect(getters.getColumnsForTool(store.state)("cogatlas:SomethingElse")).to.deep.equal([]); + }); +}); diff --git a/cypress/unit/store-getter-getUniqueValues.cy.js b/cypress/unit/store-getter-getUniqueValues.cy.js index 6220a508..e1f08f3d 100644 --- a/cypress/unit/store-getter-getUniqueValues.cy.js +++ b/cypress/unit/store-getter-getUniqueValues.cy.js @@ -35,11 +35,7 @@ describe("getUniqueValues getter", () => { store = { getters: { - // getColumnsForCategory: () => (p_category) => { - // return ["column1", "column2", "column3"]; - // }, getColumnsForCategory: getters.getColumnsForCategory(state), - getUniqueColumnValues: getters.getUniqueColumnValues(state) }, diff --git a/cypress/unit/store-getter-isPageAccessible.cy.js b/cypress/unit/store-getter-isPageAccessible.cy.js index 6c9519d4..f207710b 100644 --- a/cypress/unit/store-getter-isPageAccessible.cy.js +++ b/cypress/unit/store-getter-isPageAccessible.cy.js @@ -1,6 +1,7 @@ import { getters } from "~/store"; let state = {}; +getters.getColumnsForCategory = getters.getColumnsForCategory(state); describe("isPageAccessible", () => { @@ -15,6 +16,10 @@ describe("isPageAccessible", () => { "column1Name": "Subject ID" }, + columnToToolMap: { + + "column1Name": null + }, dataTable: [ @@ -34,13 +39,13 @@ describe("isPageAccessible", () => { let nextPage = "categorization"; // Assert - expect(getters.isPageAccessible(state)(nextPage)).to.be.true; + expect(getters.isPageAccessible(state, getters)(nextPage)).to.be.true; // Setup state.dataTable = []; // Assert - expect(getters.isPageAccessible(state)(nextPage)).to.be.false; + expect(getters.isPageAccessible(state, getters)(nextPage)).to.be.false; }); it("Test page accessibility via the categorization page", () => { @@ -50,13 +55,13 @@ describe("isPageAccessible", () => { state.columnToCategoryMap["column2Name"] = "Sex"; // Assert - expect(getters.isPageAccessible(state)(nextPage)).to.be.true; + expect(getters.isPageAccessible(state, getters)(nextPage)).to.be.true; // Setup state.columnToCategoryMap = {}; // Assert - expect(getters.isPageAccessible(state)(nextPage)).to.be.false; + expect(getters.isPageAccessible(state, getters)(nextPage)).to.be.false; }); it("Test page accessibility via the annotation page", () => { @@ -65,12 +70,12 @@ describe("isPageAccessible", () => { let nextPage = "download"; // Assert - expect(getters.isPageAccessible(state)(nextPage)).to.be.true; + expect(getters.isPageAccessible(state, getters)(nextPage)).to.be.true; // Setup state.annotationCount = 0; // Assert - expect(getters.isPageAccessible(state)(nextPage)).to.be.false; + expect(getters.isPageAccessible(state, getters)(nextPage)).to.be.false; }); -}); \ No newline at end of file +}); diff --git a/cypress/unit/store-mutation-alterColumnToToolMap.cy.js b/cypress/unit/store-mutation-alterColumnToToolMap.cy.js new file mode 100644 index 00000000..2a9f98e4 --- /dev/null +++ b/cypress/unit/store-mutation-alterColumnToToolMap.cy.js @@ -0,0 +1,40 @@ +import { mutations } from "~/store"; + +let store; + +describe("alterColumnToToolMapping", () => { + + beforeEach(() => { + + store = { + + state: { + + columnToToolMap : { + + "column1": "cogatlas:MOCA", + "column2": null, + "column3": "cogatlas:UPDRSIII" + } + } + }; + }); + + it("Maps column to tool if it's not already mapped", () => { + + mutations.alterColumnToToolMapping(store.state, {columnName: "column2", toolIdentifier: "cogatlas:MOCA"}); + expect(store.state.columnToToolMap.column2).to.equal("cogatlas:MOCA"); + }); + + it("Maps column to new tool overwriting previous mapping", () => { + + mutations.alterColumnToToolMapping(store.state, {columnName: "column3", toolIdentifier: "cogatlas:MOCA"}); + expect(store.state.columnToToolMap.column3).to.equal("cogatlas:MOCA"); + }); + + it("Sets mapping to null if it's already mapped", () => { + + mutations.alterColumnToToolMapping(store.state, {columnName: "column1", toolIdentifier: "cogatlas:MOCA"}); + expect(store.state.columnToToolMap.column1).to.equal(null); + }); +}); diff --git a/cypress/unit/store-mutation-createToolGroup.cy.js b/cypress/unit/store-mutation-createToolGroup.cy.js new file mode 100644 index 00000000..2f670210 --- /dev/null +++ b/cypress/unit/store-mutation-createToolGroup.cy.js @@ -0,0 +1,37 @@ +import { mutations } from "~/store"; + +let store; + +describe("createToolGroup mutation", () => { + + beforeEach(() => { + + store = { + + state: { + + toolTerms: [ + { + label: "MOCA", + identifier: "cogAtlas:MOCA", + selected: false + }, + { + label: "UPDRS", + identifier: "cogAtlas:UPDRS", + selected: false + } + ] + } + }; + }); + + it("Makes sure mutation sets a value in the toolTerms state object", () => { + + // Act + mutations.createAssessmentTool(store.state, { identifier: 'cogAtlas:MOCA', label: 'MOCA' }); + // Assert + expect(store.state.toolTerms.filter(tool => tool.identifier === 'cogAtlas:MOCA')[0]['selected']).to.be.true; + }); + +}); diff --git a/package-lock.json b/package-lock.json index 31018355..ccbb43dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,17 +23,17 @@ "webpack": "^4.47.0" }, "devDependencies": { - "cy-verify-downloads": "^0.2.1", + "cy-verify-downloads": "^0.2.2", "cypress": "^13.3.1", "editorconfig": "^2.0.0", - "eslint": "^8.51.0", + "eslint": "^8.52.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^9.0.0", "eslint-plugin-cypress": "^2.15.1", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-vue": "^9.17.0", "husky": "^8.0.3", - "lint-staged": "^14.0.1", + "lint-staged": "^15.0.2", "push-dir": "^0.4.1" } }, @@ -59,16 +59,73 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { "version": "7.22.9", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", @@ -107,11 +164,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", - "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.22.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -214,20 +271,20 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -377,9 +434,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -419,12 +476,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -488,9 +545,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1777,31 +1834,31 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", - "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1810,12 +1867,12 @@ } }, "node_modules/@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2748,9 +2805,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2762,12 +2819,12 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -2789,9 +2846,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@jridgewell/gen-mapping": { @@ -4080,6 +4137,12 @@ "@types/node": "*" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@vue/babel-helper-vue-jsx-merge-props": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", @@ -6646,9 +6709,9 @@ "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==" }, "node_modules/cy-verify-downloads": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cy-verify-downloads/-/cy-verify-downloads-0.2.1.tgz", - "integrity": "sha512-RXqLeLztnPZuGkXq8lnkVcxJYSUz2evUbhNKIfsYQ/I2tMCif9x8TQBC/jskmw+qibCclJ8CfG//bYeZP9bUhA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cy-verify-downloads/-/cy-verify-downloads-0.2.2.tgz", + "integrity": "sha512-Cr4U38xg5z8AK8XiYuEcbAy1rfgtkZTdUFTWkG5NM+BxKSjRlpGt6LpylLpHp9B6ikKCBPotpeewW7fOuBFKlA==", "dev": true }, "node_modules/cyclist": { @@ -7482,18 +7545,19 @@ } }, "node_modules/eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -10735,27 +10799,27 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/lint-staged": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.1.tgz", - "integrity": "sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==", + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.0.2.tgz", + "integrity": "sha512-vnEy7pFTHyVuDmCAIFKR5QDO8XLVlPFQQyujQ/STOxe40ICWqJ6knS2wSJ/ffX/Lw0rz83luRDh+ET7toN+rOw==", "dev": true, "dependencies": { "chalk": "5.3.0", - "commander": "11.0.0", + "commander": "11.1.0", "debug": "4.3.4", - "execa": "7.2.0", + "execa": "8.0.1", "lilconfig": "2.1.0", - "listr2": "6.6.1", + "listr2": "7.0.2", "micromatch": "4.0.5", "pidtree": "0.6.0", "string-argv": "0.3.2", - "yaml": "2.3.1" + "yaml": "2.3.3" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=18.12.0" }, "funding": { "url": "https://opencollective.com/lint-staged" @@ -10844,9 +10908,9 @@ } }, "node_modules/lint-staged/node_modules/commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, "engines": { "node": ">=16" @@ -10865,35 +10929,47 @@ "dev": true }, "node_modules/lint-staged/node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^3.0.7", + "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" }, "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" + "node": ">=16.17" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lint-staged/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, "engines": { - "node": ">=14.18.0" + "node": ">=16.17.0" } }, "node_modules/lint-staged/node_modules/is-fullwidth-code-point": { @@ -10921,9 +10997,9 @@ } }, "node_modules/lint-staged/node_modules/listr2": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", - "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", + "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", "dev": true, "dependencies": { "cli-truncate": "^3.1.0", @@ -10935,14 +11011,6 @@ }, "engines": { "node": ">=16.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } } }, "node_modules/lint-staged/node_modules/log-update": { @@ -11058,6 +11126,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lint-staged/node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/lint-staged/node_modules/slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -18572,9 +18658,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", + "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", "dev": true, "engines": { "node": ">= 14" @@ -18619,11 +18705,58 @@ } }, "@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "requires": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/compat-data": { @@ -18654,11 +18787,11 @@ } }, "@babel/generator": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz", - "integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "requires": { - "@babel/types": "^7.22.5", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -18731,17 +18864,17 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, "@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { @@ -18843,9 +18976,9 @@ "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==" }, "@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.22.5", @@ -18873,12 +19006,12 @@ } }, "@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -18929,9 +19062,9 @@ } }, "@babel/parser": { - "version": "7.22.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", - "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==" + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.22.5", @@ -19762,39 +19895,39 @@ } }, "@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.22.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz", - "integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==", - "requires": { - "@babel/code-frame": "^7.22.5", - "@babel/generator": "^7.22.7", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.7", - "@babel/types": "^7.22.5", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", - "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "requires": { "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -20188,9 +20321,9 @@ } }, "@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "dev": true }, "@gar/promisify": { @@ -20199,12 +20332,12 @@ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, "@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" } @@ -20216,9 +20349,9 @@ "dev": true }, "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "@jridgewell/gen-mapping": { @@ -21270,6 +21403,12 @@ "@types/node": "*" } }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "@vue/babel-helper-vue-jsx-merge-props": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz", @@ -23182,9 +23321,9 @@ "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==" }, "cy-verify-downloads": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/cy-verify-downloads/-/cy-verify-downloads-0.2.1.tgz", - "integrity": "sha512-RXqLeLztnPZuGkXq8lnkVcxJYSUz2evUbhNKIfsYQ/I2tMCif9x8TQBC/jskmw+qibCclJ8CfG//bYeZP9bUhA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cy-verify-downloads/-/cy-verify-downloads-0.2.2.tgz", + "integrity": "sha512-Cr4U38xg5z8AK8XiYuEcbAy1rfgtkZTdUFTWkG5NM+BxKSjRlpGt6LpylLpHp9B6ikKCBPotpeewW7fOuBFKlA==", "dev": true }, "cyclist": { @@ -23843,18 +23982,19 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -26253,21 +26393,21 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "lint-staged": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-14.0.1.tgz", - "integrity": "sha512-Mw0cL6HXnHN1ag0mN/Dg4g6sr8uf8sn98w2Oc1ECtFto9tvRF7nkXGJRbx8gPlHyoR0pLyBr2lQHbWwmUHe1Sw==", + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.0.2.tgz", + "integrity": "sha512-vnEy7pFTHyVuDmCAIFKR5QDO8XLVlPFQQyujQ/STOxe40ICWqJ6knS2wSJ/ffX/Lw0rz83luRDh+ET7toN+rOw==", "dev": true, "requires": { "chalk": "5.3.0", - "commander": "11.0.0", + "commander": "11.1.0", "debug": "4.3.4", - "execa": "7.2.0", + "execa": "8.0.1", "lilconfig": "2.1.0", - "listr2": "6.6.1", + "listr2": "7.0.2", "micromatch": "4.0.5", "pidtree": "0.6.0", "string-argv": "0.3.2", - "yaml": "2.3.1" + "yaml": "2.3.3" }, "dependencies": { "ansi-escapes": { @@ -26317,9 +26457,9 @@ } }, "commander": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", - "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true }, "emoji-regex": { @@ -26335,26 +26475,32 @@ "dev": true }, "execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", - "signal-exit": "^3.0.7", + "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, + "get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true + }, "human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true }, "is-fullwidth-code-point": { @@ -26370,9 +26516,9 @@ "dev": true }, "listr2": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-6.6.1.tgz", - "integrity": "sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", + "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", "dev": true, "requires": { "cli-truncate": "^3.1.0", @@ -26450,9 +26596,21 @@ "requires": { "mimic-fn": "^2.1.0" } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true } } }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, "slice-ansi": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", @@ -31866,9 +32024,9 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.3.tgz", + "integrity": "sha512-zw0VAJxgeZ6+++/su5AFoqBbZbrEakwu+X0M5HmcwUiBL7AzcuPKjj5we4xfQLp78LkEMpD0cOnUhmgOVy3KdQ==", "dev": true }, "yauzl": { diff --git a/package.json b/package.json index 2d8e112a..474e32e0 100644 --- a/package.json +++ b/package.json @@ -30,17 +30,17 @@ "webpack": "^4.47.0" }, "devDependencies": { - "cy-verify-downloads": "^0.2.1", + "cy-verify-downloads": "^0.2.2", "cypress": "^13.3.1", "editorconfig": "^2.0.0", - "eslint": "^8.51.0", + "eslint": "^8.52.0", "eslint-config-airbnb": "^19.0.4", "eslint-config-prettier": "^9.0.0", "eslint-plugin-cypress": "^2.15.1", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-vue": "^9.17.0", "husky": "^8.0.3", - "lint-staged": "^14.0.1", + "lint-staged": "^15.0.2", "push-dir": "^0.4.1" } } diff --git a/pages/categorization.vue b/pages/categorization.vue index fd5930e2..9f41ca6d 100644 --- a/pages/categorization.vue +++ b/pages/categorization.vue @@ -34,6 +34,11 @@ + + + + + @@ -45,43 +50,29 @@ import { mapGetters } from "vuex"; export default { - name: "CategorizationPage", - data() { - return { - // Category selection (default is index 0, no selection is -1) selectedCategory: "", - // Text for UI elements uiText: { - categorySelectInstructions: "Click category and then corresponding column from tsv file", categorySelectTitle: "Recommended Categories" } }; }, - computed: { - ...mapGetters([ - "getCategoryNames" ]) }, - mounted() { - // Set selected category to the first category by default this.setSelectedCategory(this.getCategoryNames[0]); }, - methods: { - setSelectedCategory(p_category) { - // Save the name of the selected category this.selectedCategory = p_category; } diff --git a/store/index.js b/store/index.js index 2c254499..f9e63746 100644 --- a/store/index.js +++ b/store/index.js @@ -69,9 +69,9 @@ export const state = () => ({ }, "Assessment Tool": { - componentName: "annot-categorical", - explanation: "This is an explanation for how to annotate diagnosis.", - identifier: "nb:Diagnosis" + componentName: "annot-tool-groups", + explanation: "This is an explanation for how to annotate a tool.", + identifier: "nb:AssessmentTool" } }, @@ -187,7 +187,22 @@ export const state = () => ({ Label: "period of time defined according to the ISO8601 standard", TermURL: "nb:FromISO8601" } - } + }, + + toolTerms: [ + { + label: "MOCA", + identifier: "cogAtlas:MOCA", + selected: false + }, + { + label: "UPDRS", + identifier: "cogAtlas:UPDRS", + selected: false + } + ], + + columnToToolMap: {} }); export const getters = { @@ -453,20 +468,6 @@ export const getters = { return [...categorySet]; }, - getMappedColumns: (p_state) => (p_category) => { - - const mappedColumns = []; - for ( const column in p_state.columnToCategoryMap ) { - - if ( p_category === p_state.columnToCategoryMap[column] ) { - - mappedColumns.push(column); - } - } - - return mappedColumns; - }, - getMissingValues: (p_state) => (p_category) => { // 1. Retrieve all columns linked with the given category @@ -542,6 +543,10 @@ export const getters = { return selectedCategoricalOption; }, + getSelectedTools: (p_state) => { + return p_state.toolTerms.filter(term => term.selected); + }, + getTransformOptions: (p_state) => (p_category) => { return Object.keys(p_state.transformationHeuristics); @@ -560,6 +565,12 @@ export const getters = { return columns; }, + getColumnsForTool: (p_state) => (p_tool) => { + + return Object.keys(p_state.columnToToolMap) + .filter(key => p_state.columnToToolMap[key] === p_tool); + }, + getUniqueColumnValues: (p_state) => (columnName, p_maxValues="None") => { let uniqueColumnValues = new Set(); for ( let index = 0; index < p_state.dataTable.length; index++ ) { @@ -606,7 +617,7 @@ export const getters = { return description; }, - isPageAccessible: (p_state) => (p_pageName) => { + isPageAccessible: (p_state, p_getters) => (p_pageName) => { let pageAccessible = false; @@ -638,10 +649,13 @@ export const getters = { null !== category) .length >= 1 ); +// 3. Make sure all columns about assessment tools are mapped to something + const allAssessmentColumnsAreMapped = p_getters.getColumnsForCategory("Assessment Tool") + .every(column => p_state.columnToToolMap[column] !== null); // Annotation page is only accessible if one (and only one) // column has been categorized as 'Subject ID' and if at least // one category other than Subject ID has been categorized - pageAccessible = singleSubjectIDColumn && notOnlySubjectIDCategorized; + pageAccessible = singleSubjectIDColumn && notOnlySubjectIDCategorized && allAssessmentColumnsAreMapped; break; } @@ -719,6 +733,7 @@ export const mutations = { break; case "Diagnosis": + case "Assessment Tool": case "Sex": p_state.dataDictionary.annotated[columnName] = Object.assign( @@ -747,11 +762,28 @@ export const mutations = { } }, + alterColumnToToolMapping(p_state, {columnName, toolIdentifier}) { + if ( p_state.columnToToolMap[columnName] === toolIdentifier ) { + p_state.columnToToolMap[columnName] = null; + } else { + p_state.columnToToolMap[columnName] = toolIdentifier; + } + }, + + createAssessmentTool(p_state, newTool) { + const toolIndex = p_state.toolTerms.findIndex(tool => tool.identifier === newTool.identifier); + p_state.toolTerms.splice(toolIndex, 1, Object.assign(p_state.toolTerms[toolIndex], { selected: true })); + }, + initializeColumnToCategoryMap(p_state, p_columns) { // Column to category map lists all columns as keys with default value of null p_state.columnToCategoryMap = Object.fromEntries(p_columns.map((column) => [column, null])); + // TODO: consider refactoring this so we don't initialize all columns + // but only the ones that are assigned to assessment tool + p_state.columnToToolMap = + Object.fromEntries(p_columns.map((column) => [column, null])); }, initializeDataDictionary(p_state) {