diff --git a/proxy-ui-app/src/App.vue b/proxy-ui-app/src/App.vue index c90e1a8..a9e4cb2 100644 --- a/proxy-ui-app/src/App.vue +++ b/proxy-ui-app/src/App.vue @@ -35,6 +35,18 @@ export default { v-for="route in routes" :id="route.id" :key="`key-${route.id}`" + :isCbOn="route.is_cb_on" + :isOnline="route.is_online" + :path="route.path" + :role="route.role" + :description="route.description" + :errorPercent="route.cb_error_threshold_percentage" + :intervalDuration="route.cb_interval_duration" + :minRequests="route.cb_min_requests" + :openStateTimeout="route.cb_open_state_timeout" + :requestLimit="route.cb_request_limit" + :deepness="route.deepness" + :order="route.order" /> diff --git a/proxy-ui-app/src/components/3_organisms/RoutersEditor/RouterRow.vue b/proxy-ui-app/src/components/3_organisms/RoutersEditor/RouterRow.vue index 43c697c..cd9d841 100644 --- a/proxy-ui-app/src/components/3_organisms/RoutersEditor/RouterRow.vue +++ b/proxy-ui-app/src/components/3_organisms/RoutersEditor/RouterRow.vue @@ -13,6 +13,54 @@ export default { default: -1, type: Number }, + isCbOn: { + default: false, + type: Boolean + }, + isOnline: { + default: false, + type: Boolean + }, + path: { + default: "", + type: String + }, + role: { + default: null, + type: Number + }, + description: { + default: "", + type: String + }, + errorPercent: { + default: 0, + type: Number + }, + intervalDuration: { + default: 0, + type: Number + }, + minRequests: { + default: 0, + type: Number + }, + openStateTimeout: { + default: 0, + type: Number + }, + requestLimit: { + default: 0, + type: Number + }, + deepness: { + default: 0, + type: Number + }, + order: { + default: 0, + type: Number + }, }, data() { return { @@ -23,51 +71,7 @@ export default { } }, computed: { - ...mapGetters('proxy', ["selectedSite", "routes", 'routeOptions', 'routesLib']), - path() { - return this.routesLib[this.id]?.path || "" - }, - role() { - return this.routesLib[this.id]?.role || "" - }, - description() { - return this.routesLib[this.id]?.description || "" - }, - errorPercent() { - if (!this.routesLib[this.id]?.cb_error_threshold_percentage && this.routesLib[this.id]?.cb_error_threshold_percentage !== 0) return "" - return this.routesLib[this.id]?.cb_error_threshold_percentage - }, - intervalDuration() { - if (!this.routesLib[this.id]?.cb_interval_duration && this.routesLib[this.id]?.cb_interval_duration !== 0) return "" - return this.routesLib[this.id]?.cb_interval_duration - }, - minRequests() { - if (!this.routesLib[this.id]?.cb_min_requests && this.routesLib[this.id]?.cb_min_requests !== 0) return "" - return this.routesLib[this.id]?.cb_min_requests - }, - openStateTimeout() { - if (!this.routesLib[this.id]?.cb_open_state_timeout && this.routesLib[this.id]?.cb_open_state_timeout !== 0) return "" - return this.routesLib[this.id]?.cb_open_state_timeout - }, - requestLimit() { - if (!this.routesLib[this.id]?.cb_request_limit && this.routesLib[this.id]?.cb_request_limit !== 0) return "" - return this.routesLib[this.id]?.cb_request_limit - }, - deepness() { - if (!this.routesLib[this.id]?.deepness && this.routesLib[this.id]?.deepness !== 0) return "" - return this.routesLib[this.id]?.deepness - }, - order() { - if (!this.routesLib[this.id]?.order && this.routesLib[this.id]?.order !== 0) return "" - return this.routesLib[this.id]?.order - }, - isCbOn() { - return this.routesLib[this.id]?.is_cb_on - }, - isOnline() { - return this.routesLib[this.id]?.is_online - }, - + ...mapGetters('proxy', ["selectedSite", "routes", 'routeOptions', 'newRoute']), }, methods: { ...mapActions('proxy', ["updateRouteRow", "removeRoute", "breateAddingRoute"]), @@ -77,17 +81,21 @@ export default { }, setValue(key, value) { this.updateRouteRow({ - ...this.routesLib[this.id], + id: this.id, [key]: value }) }, setInputValue(params) { - const value = params.isNumber ? parseFloat(params.value) : params.value + const value = params.isNumber ? this.parseNumber(params.value) : params.value this.updateRouteRow({ - ...this.routesLib[this.id], + id: this.id, [params.key]: value }) }, + parseNumber (value) { + if (!value || value !== 0) return 0 + return parseFloat(value) + }, removeCurrentRoute() { this.removeRoute({id: this.id}) }, diff --git a/proxy-ui-app/src/store/modules/proxy/helpers.js b/proxy-ui-app/src/store/modules/proxy/helpers.js index a235710..e0837b2 100644 --- a/proxy-ui-app/src/store/modules/proxy/helpers.js +++ b/proxy-ui-app/src/store/modules/proxy/helpers.js @@ -1,5 +1,6 @@ const addedSite = (addedSite, sites) => { - return [addedSite,...sites] + const sitesWithoutNewSite = removedNewSite(sites) + return [addedSite,...sitesWithoutNewSite] } const updatedSite = (updatedSite, sites) => { @@ -41,6 +42,7 @@ const updatedRoute = (updatedRoute, routes) => { return routes.reduce((acc, cur) => { if (cur.id === updatedRoute.id) { return [...acc, { + ...cur, ...updatedRoute, action: updatedRoute.action === "create" ? "create" : "update" }] diff --git a/proxy-ui-app/src/store/modules/proxy/index.js b/proxy-ui-app/src/store/modules/proxy/index.js index d2eec99..ee4f4af 100644 --- a/proxy-ui-app/src/store/modules/proxy/index.js +++ b/proxy-ui-app/src/store/modules/proxy/index.js @@ -15,8 +15,8 @@ const initState = { selectedSite: null, routes: [], + newRoute: null, routesState: "await", - routesLib: {}, }; const state = { @@ -27,14 +27,11 @@ const getters = { isSaveData: (state) => state.isSaveData, sites: (state) => state.sites, routes: (state) => state.routes.filter(({action}) => !["remove", "delete"].includes(action)), - routesLib: (state) => state.routes.reduce((acc, cur) => ({ - ...acc, - [cur.id]: cur - }), {}), routesState: (state) => state.routesState, sitesState: (state) => state.sitesState, routeOptions: () => routeOptions, selectedSite: (state) => state.selectedSite, + newRoute: (state) => state.newRoute, }; const mutations = { @@ -44,6 +41,7 @@ const mutations = { setSelectedSite: (state, payload) => state.selectedSite = payload, setRoutes: (state, payload) => state.routes = payload, setRoutesState: (state, payload) => state.routesState = payload, + setNewRoute: (state, payload) => state.newRoute = payload, }; const actions = { @@ -114,14 +112,20 @@ const actions = { action: "create", server_id: getters.selectedSite.id } + commit('setNewRoute', newRoute) commit('setRoutes', [newRoute, ...state.routes]) }, updateRouteRow: ({commit, state}, editRoute) => { - const updatedRoutes = updatedRoute(editRoute, state.routes) + const editedRoute = state.newRoute ? {...state.newRoute, ...editRoute} : editRoute + const updatedRoutes = updatedRoute(editedRoute, state.routes) + if (state.newRoute && state.newRoute.id === editRoute.id) { + commit('setNewRoute', {...state.newRoute, ...editRoute}) + } commit('setRoutes', updatedRoutes) }, updateRoutesWithApi: async ({commit, state}, payload) => { commit('setRoutesState', "loading") + if (!state.routes || isEmpty(state.routes)) return commit('setRoutesState', "await") let updatedRoutes = state.routes.filter(({action}) => action) updatedRoutes = updatedRoutes.map((el) => { if (el.action === "create") return dissoc('id', el) @@ -132,6 +136,7 @@ const actions = { routes = sortedRoutes(routes) commit('setRoutes', routes) commit('setRoutesState', "await") + commit('setNewRoute', null) }, removeRoute: ({commit, state}, {id}) => { const updatedRoutes = deletedRoute(id, state.routes) diff --git a/proxy-ui-app/tests/views/3_organisms/RoutersEditor/RoutersEditor.test.js b/proxy-ui-app/tests/views/3_organisms/RoutersEditor/RoutersEditor.test.js index 50e21f6..8d2677e 100644 --- a/proxy-ui-app/tests/views/3_organisms/RoutersEditor/RoutersEditor.test.js +++ b/proxy-ui-app/tests/views/3_organisms/RoutersEditor/RoutersEditor.test.js @@ -1,8 +1,9 @@ import {mount} from '@vue/test-utils' import {expect, it, describe} from 'vitest' import RoutesList from "@organisms/RoutersEditor/index.vue" -// import RoutersEditor from "@organisms/RoutersEditor/index.vue" +import RouterRow from '@organisms/RoutersEditor/RouterRow.vue' import routeOptions from '@store/modules/proxy/routeOptions.json' +import { deletedRoute } from '@store/modules/proxy/helpers' import {createStore} from 'vuex' const defaultRoutes = [{ @@ -76,7 +77,10 @@ const store = createStore({ getters: { routes: (state) => state.routes, routesState: (state) => state.routesState, - routesLib: (state) => state.routesLib, + routesLib: (state) => state.routes.reduce((acc, cur) => ({ + ...acc, + [cur.id]: cur + }), {}), routeOptions: (state) => state.routeOptions, }, mutations: { @@ -90,7 +94,10 @@ const store = createStore({ commit('setRoutes', defaultRoutes) }, updateRouteRow: () => ({}), - removeRoute: () => ({}), + removeRoute: ({commit, state}, id) => { + const updatedRoutes = deletedRoute(id, state.routes) + commit('setRoutes', updatedRoutes) + }, breateAddingRoute: () => ({}), }, namespaced: true, @@ -140,38 +147,79 @@ describe("Routes", () => { expect(wrapper.html()).not.toContain('ri-delete-bin-line') }) - it("Renders routes and buttons in RoutesList, if routesState value 'active' and not empty routes array", async () => { + it("Renders route in RoutesList, if routesState value 'active' and default props", async () => { - store.commit('proxy/setRoutesState', 'active') - store.commit('proxy/setRoutes', defaultRoutes) - - const getters = {...store.getters } - const routesState = getters['proxy/routesState'] - const routes = getters['proxy/routes'] - - const wrapper = mount(RoutesList, { + const wrapper = mount(RouterRow, { global: { plugins: [store], }, - data() { - return { - open: false, - } + }) + + expect(wrapper.html()).toContain('ri-delete-bin-line') + }) + + it("Renders route in RoutesList, with set props", async () => { + + const wrapper = mount(RouterRow, { + global: { + plugins: [store], + stubs: ['Input', 'Textarea', 'DoubleSwitch'], + }, + props: { + id: 1, + path: "/route1", + description: "default", + minRequests: 3, }, }) - console.log('routes 3 test', routes) + expect(wrapper.html()).toContain('/route1') // default props + expect(wrapper.html()).toContain('/route1') // default props + expect(wrapper.html()).toContain('3') // default props - if (routesState === 'active') { - await wrapper.setData({ open: true }) - } - - console.log('wrapper 3 test', wrapper.html()) + await wrapper.setProps({ path: '/route2', minRequests: 7, description: 'test route' }) - expect(wrapper.html()).toContain('Добавить роут') - expect(wrapper.html()).toContain('Закрыть') - // expect(wrapper.html()).toContain('ri-delete-bin-line') + expect(wrapper.html()).toContain('ri-delete-bin-line') + expect(wrapper.html()).toContain('test route') // updated props + expect(wrapper.html()).toContain('/route2') // updated props + expect(wrapper.html()).toContain('7') // updated props }) + + it("Renders buttons delete and cancel in route, after click button delete", async () => { + + const wrapper = mount(RouterRow, { + global: { + plugins: [store], + stubs: ['Input', 'Textarea', 'DoubleSwitch'], + }, + }) + + await wrapper.get('.ri-delete-bin-line').trigger('click') + + expect(wrapper.html()).not.toContain('ri-delete-bin-line') + expect(wrapper.html()).toContain('Отменить') + expect(wrapper.html()).toContain('Удалить') + }) + + it("Renders default route state, after click button delete and click button cancel", async () => { + + const wrapper = mount(RouterRow, { + global: { + plugins: [store], + stubs: ['Input', 'Textarea', 'DoubleSwitch'], + }, + }) + + await wrapper.get('.ri-delete-bin-line').trigger('click') + await wrapper.get('.bg-gray-700').trigger('click') + + // console.log('wrapper 6 test', wrapper.html()) + + expect(wrapper.html()).toContain('ri-delete-bin-line') + expect(wrapper.html()).not.toContain('Отменить') + expect(wrapper.html()).not.toContain('Удалить') + }) + })