Loading client/src/components/History/CurrentHistory/HistoryNavigation.vue +1 −1 Original line number Diff line number Diff line Loading @@ -130,7 +130,7 @@ <SelectorModal id="selector-history-modal" :histories="histories" :current-history="history" :current-history-id="history.id" @selectHistory="$emit('setCurrentHistory', $event)" /> <CopyModal id="copy-history-modal" :history="history" /> Loading client/src/components/History/Modals/SelectorModal.test.js 0 → 100644 +65 −0 Original line number Diff line number Diff line import { mount } from "@vue/test-utils"; import flushPromises from "flush-promises"; import { getLocalVue } from "jest/helpers"; import SelectorModal from "./SelectorModal"; const localVue = getLocalVue(); const SELECTED_HISTORY_ID = "COOL_ID"; const getFakeHistorySummaries = (num, selectedIndex = 0) => { const result = Array.from({ length: num }, (_, index) => ({ id: `ID-${index}`, name: `History-${index}`, tags: [], update_time: new Date().toISOString(), })); result[selectedIndex].id = SELECTED_HISTORY_ID; return result; }; const PROPS_WITH_10_HISTORIES = { currentHistoryId: SELECTED_HISTORY_ID, histories: getFakeHistorySummaries(10), perPage: 3, static: true, // Force the modal visible for testing }; describe("History SelectorModal.vue", () => { let wrapper; async function mountWith(props) { wrapper = mount(SelectorModal, { propsData: props, localVue, }); await flushPromises(); } it("should highlight the currently selected history", async () => { await mountWith(PROPS_WITH_10_HISTORIES); const selectedRows = wrapper.findAll(".table-success"); expect(selectedRows.length).toBe(1); expect(selectedRows.at(0).attributes("data-pk")).toBe(SELECTED_HISTORY_ID); }); it("paginates the histories", async () => { await mountWith(PROPS_WITH_10_HISTORIES); const displayedRows = wrapper.findAll("tbody > tr").wrappers; expect(displayedRows.length).toBe(3); expect(wrapper.vm.histories.length).toBe(10); }); it("emits selectHistory with the correct history ID when a row is clicked", async () => { await mountWith(PROPS_WITH_10_HISTORIES); expect(wrapper.emitted()["selectHistory"]).toBeUndefined(); const targetHistoryId = "ID-2"; const targetRow = wrapper.find(`[data-pk="${targetHistoryId}"]`); await targetRow.trigger("click"); expect(wrapper.emitted()["selectHistory"]).toBeDefined(); expect(wrapper.emitted()["selectHistory"][0][0].id).toBe(targetHistoryId); }); }); client/src/components/History/Modals/SelectorModal.vue +25 −33 Original line number Diff line number Diff line <template> <b-modal ref="modal" v-bind="$attrs" :title="'Switch to History' | l" v-on="$listeners"> <b-form-group :description="'Filter histories' | l"> <b-input v-model="filter" :placeholder="'Search Filter' | l" /> <b-form-input v-model="filter" type="search" :placeholder="'Search Filter' | l" /> </b-form-group> <b-table ref="history-list" v-model="currentRows" striped hover sticky-header="50vh" primary-key="id" :fields="fields" :filter="filter" :items="histories" :items="formattedItems" :per-page="perPage" :current-page="currentPage" :selectable="true" select-mode="single" selected-variant="success" @row-selected="switchToHistory"> @row-selected="switchToHistory" @filtered="onFiltered"> <template v-slot:cell(tags)="row"> <stateless-tags :value="row.item.tags" :disabled="true" /> </template> Loading @@ -29,23 +28,28 @@ </b-table> <template v-slot:modal-footer> <b-pagination v-model="currentPage" :total-rows="filteredRowCount" :per-page="perPage"></b-pagination> <b-pagination v-model="currentPage" :total-rows="totalRows" :per-page="perPage" /> </template> </b-modal> </template> <script> import { BModal, BFormGroup, BFormInput, BTable, BPagination } from "bootstrap-vue"; import { StatelessTags } from "components/Tags"; import UtcDate from "components/UtcDate"; import { debounce } from "underscore"; export default { components: { StatelessTags, UtcDate, BModal, BFormGroup, BFormInput, BTable, BPagination, }, props: { currentHistory: { type: Object, required: true }, currentHistoryId: { type: String, required: true }, histories: { type: Array, default: () => [] }, perPage: { type: Number, required: false, default: 50 }, }, Loading @@ -53,30 +57,22 @@ export default { return { filter: null, currentPage: 1, currentRows: [], totalRows: 0, }; }, computed: { filteredRowCount() { return this.currentRows.length; }, selectedIndex() { return this.currentRows.findIndex((h) => h.id == this.currentHistory.id); formattedItems() { return this.histories.map((item) => { if (item.id == this.currentHistoryId) { item._rowVariant = "success"; } return item; }); }, }, watch: { currentRows() { this.selectCurrentRow(); }, filteredRowCount(newVal, oldVal) { if (newVal != oldVal) { this.currentPage = 1; } }, selectedIndex(idx, oldIdx) { if (idx != oldIdx) { this.debounceSelectCurrentRow(); } histories(newVal) { this.totalRows = newVal.length; }, }, created() { Loading @@ -85,7 +81,6 @@ export default { { key: "tags", sortable: true }, { key: "update_time", label: "Updated", sortable: true }, ]; this.debounceSelectCurrentRow = debounce(this.selectCurrentRow, 100); }, methods: { switchToHistory(selected) { Loading @@ -93,12 +88,9 @@ export default { this.$emit("selectHistory", selected[0]); } }, selectCurrentRow() { const idx = this.selectedIndex; const list = this.$refs["history-list"]; if (list && idx > -1) { list.selectRow(idx); } onFiltered(filteredItems) { this.totalRows = filteredItems.length; this.currentPage = 1; }, }, }; Loading Loading
client/src/components/History/CurrentHistory/HistoryNavigation.vue +1 −1 Original line number Diff line number Diff line Loading @@ -130,7 +130,7 @@ <SelectorModal id="selector-history-modal" :histories="histories" :current-history="history" :current-history-id="history.id" @selectHistory="$emit('setCurrentHistory', $event)" /> <CopyModal id="copy-history-modal" :history="history" /> Loading
client/src/components/History/Modals/SelectorModal.test.js 0 → 100644 +65 −0 Original line number Diff line number Diff line import { mount } from "@vue/test-utils"; import flushPromises from "flush-promises"; import { getLocalVue } from "jest/helpers"; import SelectorModal from "./SelectorModal"; const localVue = getLocalVue(); const SELECTED_HISTORY_ID = "COOL_ID"; const getFakeHistorySummaries = (num, selectedIndex = 0) => { const result = Array.from({ length: num }, (_, index) => ({ id: `ID-${index}`, name: `History-${index}`, tags: [], update_time: new Date().toISOString(), })); result[selectedIndex].id = SELECTED_HISTORY_ID; return result; }; const PROPS_WITH_10_HISTORIES = { currentHistoryId: SELECTED_HISTORY_ID, histories: getFakeHistorySummaries(10), perPage: 3, static: true, // Force the modal visible for testing }; describe("History SelectorModal.vue", () => { let wrapper; async function mountWith(props) { wrapper = mount(SelectorModal, { propsData: props, localVue, }); await flushPromises(); } it("should highlight the currently selected history", async () => { await mountWith(PROPS_WITH_10_HISTORIES); const selectedRows = wrapper.findAll(".table-success"); expect(selectedRows.length).toBe(1); expect(selectedRows.at(0).attributes("data-pk")).toBe(SELECTED_HISTORY_ID); }); it("paginates the histories", async () => { await mountWith(PROPS_WITH_10_HISTORIES); const displayedRows = wrapper.findAll("tbody > tr").wrappers; expect(displayedRows.length).toBe(3); expect(wrapper.vm.histories.length).toBe(10); }); it("emits selectHistory with the correct history ID when a row is clicked", async () => { await mountWith(PROPS_WITH_10_HISTORIES); expect(wrapper.emitted()["selectHistory"]).toBeUndefined(); const targetHistoryId = "ID-2"; const targetRow = wrapper.find(`[data-pk="${targetHistoryId}"]`); await targetRow.trigger("click"); expect(wrapper.emitted()["selectHistory"]).toBeDefined(); expect(wrapper.emitted()["selectHistory"][0][0].id).toBe(targetHistoryId); }); });
client/src/components/History/Modals/SelectorModal.vue +25 −33 Original line number Diff line number Diff line <template> <b-modal ref="modal" v-bind="$attrs" :title="'Switch to History' | l" v-on="$listeners"> <b-form-group :description="'Filter histories' | l"> <b-input v-model="filter" :placeholder="'Search Filter' | l" /> <b-form-input v-model="filter" type="search" :placeholder="'Search Filter' | l" /> </b-form-group> <b-table ref="history-list" v-model="currentRows" striped hover sticky-header="50vh" primary-key="id" :fields="fields" :filter="filter" :items="histories" :items="formattedItems" :per-page="perPage" :current-page="currentPage" :selectable="true" select-mode="single" selected-variant="success" @row-selected="switchToHistory"> @row-selected="switchToHistory" @filtered="onFiltered"> <template v-slot:cell(tags)="row"> <stateless-tags :value="row.item.tags" :disabled="true" /> </template> Loading @@ -29,23 +28,28 @@ </b-table> <template v-slot:modal-footer> <b-pagination v-model="currentPage" :total-rows="filteredRowCount" :per-page="perPage"></b-pagination> <b-pagination v-model="currentPage" :total-rows="totalRows" :per-page="perPage" /> </template> </b-modal> </template> <script> import { BModal, BFormGroup, BFormInput, BTable, BPagination } from "bootstrap-vue"; import { StatelessTags } from "components/Tags"; import UtcDate from "components/UtcDate"; import { debounce } from "underscore"; export default { components: { StatelessTags, UtcDate, BModal, BFormGroup, BFormInput, BTable, BPagination, }, props: { currentHistory: { type: Object, required: true }, currentHistoryId: { type: String, required: true }, histories: { type: Array, default: () => [] }, perPage: { type: Number, required: false, default: 50 }, }, Loading @@ -53,30 +57,22 @@ export default { return { filter: null, currentPage: 1, currentRows: [], totalRows: 0, }; }, computed: { filteredRowCount() { return this.currentRows.length; }, selectedIndex() { return this.currentRows.findIndex((h) => h.id == this.currentHistory.id); formattedItems() { return this.histories.map((item) => { if (item.id == this.currentHistoryId) { item._rowVariant = "success"; } return item; }); }, }, watch: { currentRows() { this.selectCurrentRow(); }, filteredRowCount(newVal, oldVal) { if (newVal != oldVal) { this.currentPage = 1; } }, selectedIndex(idx, oldIdx) { if (idx != oldIdx) { this.debounceSelectCurrentRow(); } histories(newVal) { this.totalRows = newVal.length; }, }, created() { Loading @@ -85,7 +81,6 @@ export default { { key: "tags", sortable: true }, { key: "update_time", label: "Updated", sortable: true }, ]; this.debounceSelectCurrentRow = debounce(this.selectCurrentRow, 100); }, methods: { switchToHistory(selected) { Loading @@ -93,12 +88,9 @@ export default { this.$emit("selectHistory", selected[0]); } }, selectCurrentRow() { const idx = this.selectedIndex; const list = this.$refs["history-list"]; if (list && idx > -1) { list.selectRow(idx); } onFiltered(filteredItems) { this.totalRows = filteredItems.length; this.currentPage = 1; }, }, }; Loading