diff --git a/src/main/webui/src/app/components/ComponentConstants.js b/src/main/webui/src/app/components/ComponentConstants.js index 1752ff4..40e3bd9 100644 --- a/src/main/webui/src/app/components/ComponentConstants.js +++ b/src/main/webui/src/app/components/ComponentConstants.js @@ -26,5 +26,7 @@ const hostedOptionLegend = [ {icon: 'D', title: 'Deployment allowed'} ]; +const STORE_API_BASE_URL = "/api/admin/stores"; -export {remoteOptionLegend, hostedOptionLegend}; + +export {remoteOptionLegend, hostedOptionLegend, STORE_API_BASE_URL}; diff --git a/src/main/webui/src/app/components/content/common/ListControl.test.jsx b/src/main/webui/src/app/components/content/common/ListControl.test.jsx index 4add198..75ad934 100644 --- a/src/main/webui/src/app/components/content/common/ListControl.test.jsx +++ b/src/main/webui/src/app/components/content/common/ListControl.test.jsx @@ -15,9 +15,8 @@ */ import React from "react"; -import {render, screen, cleanup, waitFor} from '@testing-library/react'; +import {render, screen, cleanup} from '@testing-library/react'; import {MemoryRouter} from 'react-router-dom'; -import userEvent from "@testing-library/user-event"; import '@testing-library/jest-dom'; import ListControl from "./ListControl.jsx"; import {remoteOptionLegend as remoteOptions} from "../../ComponentConstants.js"; @@ -36,14 +35,10 @@ describe('ListControl tests', () => { /> ); expect(screen.getByRole("button", {Name: "New..."})).toBeInTheDocument(); - expect(screen.getByText(/Search:/u)).toBeInTheDocument(); - expect(screen.getByText(/Sort by:/u)).toBeInTheDocument(); expect(screen.getByRole("option", {name: "Remote URL"})).toBeInTheDocument(); - expect(screen.getByText(/Capability Legend:/u)).toBeInTheDocument(); - expect(screen.queryByRole("checkbox", {Name: "enableDebug"})).not.toBeInTheDocument(); }); @@ -57,11 +52,8 @@ describe('ListControl tests', () => { ); expect(screen.getByRole("button", {name: "Hide All"})).toBeInTheDocument(); - expect(screen.queryByText(/Sort by:/u)).not.toBeInTheDocument(); - expect(screen.queryByText(/Capability Legend:/u)).not.toBeInTheDocument(); - expect(screen.getByRole("checkbox", {Name: "enableDebug"})).toBeInTheDocument(); }); }); diff --git a/src/main/webui/src/app/components/content/common/StoreControlPanels.jsx b/src/main/webui/src/app/components/content/common/StoreControlPanels.jsx index 775a9ac..c461c51 100644 --- a/src/main/webui/src/app/components/content/common/StoreControlPanels.jsx +++ b/src/main/webui/src/app/components/content/common/StoreControlPanels.jsx @@ -19,6 +19,7 @@ import {useNavigate} from 'react-router-dom'; import {PropTypes} from 'prop-types'; import {Utils} from '#utils/AppUtils'; import {jsonRest,http} from '#utils/RestClient'; +import {STORE_API_BASE_URL} from '../../ComponentConstants'; const StoreViewControlPanel = function({store}){ const handleEnable = () =>{ @@ -31,7 +32,7 @@ const StoreViewControlPanel = function({store}){ const navigate = useNavigate(); const [pkgType, storeType, storeName] = [store.packageType, store.type, store.name]; - const storeUrl = `/api/admin/stores/${pkgType}/${storeType}/${storeName}`; + const storeUrl = `${STORE_API_BASE_URL}/${pkgType}/${storeType}/${storeName}`; const handleRemove = async ()=>{ const response = await http.delete(storeUrl); if(!response.ok && response.status >= 400){ @@ -68,7 +69,7 @@ StoreViewControlPanel.propTypes={ const StoreEditControlPanel = ({mode, store}) =>{ const navigate = useNavigate(); const handleSave = () => { - const saveUrl = `/api/admin/stores/${store.packageType}/${store.type}/${store.name}`; + const saveUrl = `${STORE_API_BASE_URL}/${store.packageType}/${store.type}/${store.name}`; const saveStore = async () => { let response = {}; if(mode==="new"){ @@ -99,7 +100,7 @@ const StoreEditControlPanel = ({mode, store}) =>{ const handleRemove = () => { // Only edit page should handle delete logic if(mode==="edit"){ - const deleteUrl = `/api/admin/stores/${store.packageType}/${store.type}/${store.name}`; + const deleteUrl = `${STORE_API_BASE_URL}/${store.packageType}/${store.type}/${store.name}`; const deleteStore = async () => { const response = await http.delete(deleteUrl); if (!response.ok){ diff --git a/src/main/webui/src/app/components/content/common/StoreControlPanels.test.jsx b/src/main/webui/src/app/components/content/common/StoreControlPanels.test.jsx new file mode 100644 index 0000000..b89382f --- /dev/null +++ b/src/main/webui/src/app/components/content/common/StoreControlPanels.test.jsx @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2023 Red Hat, Inc. (https://github.com/Commonjava/indy-ui-service) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from "react"; +import {render, screen, cleanup} from '@testing-library/react'; +import {MemoryRouter} from 'react-router-dom'; +import '@testing-library/jest-dom'; +import {StoreViewControlPanel, StoreEditControlPanel} from "./StoreControlPanels.jsx"; + +afterEach(() => { + cleanup(); +}); + +describe('StoreControlPanels tests', () => { + it("Verify StoreViewControlPanel with remote", ()=>{ + const mockRemoteStore = {name: "central", type: "remote", packageType: "maven", + key: "maven:remote:central", disabled: false, "allow_snapshots": true, + "allow_releases": true, url: "https://repo.maven.apache.org/maven2/", + description: "official maven central"}; + render( + + ); + + expect(screen.getByRole('button', {name: "Edit"})).toBeInTheDocument(); + expect(screen.getByRole('button', {name: "New..."})).toBeInTheDocument(); + expect(screen.getByRole('button', {name: "Delete"})).toBeInTheDocument(); + + expect(screen.getByRole('button', {name: "Disable"})).toBeInTheDocument(); + }); + + it("Verify StoreViewControlPanel with group", ()=>{ + const mockGroup = {name: "public", type: "group", packageType: "maven", + key: "maven:group:public", disabled: true, description: "public group", + constituents: ["maven:remote:central", "maven:hosted:local-deployments",]}; + render( + + ); + + expect(screen.getByRole('button', {name: "Edit"})).toBeInTheDocument(); + expect(screen.getByRole('button', {name: "New..."})).toBeInTheDocument(); + expect(screen.getByRole('button', {name: "Delete"})).toBeInTheDocument(); + + expect(screen.getByRole('button', {name: "Enable"})).toBeInTheDocument(); + + }); + + it("Verify StoreEditControlPanel of mode edit", ()=>{ + const mockRemoteStore = {name: "central", type: "remote", packageType: "maven", + key: "maven:remote:central", disabled: false, "allow_snapshots": true, + "allow_releases": true, url: "https://repo.maven.apache.org/maven2/", + description: "official maven central"}; + render( + + ); + + expect(screen.getByRole('button', {name: "Save"})).toBeInTheDocument(); + expect(screen.getByRole('button', {name: "Cancel"})).toBeInTheDocument(); + expect(screen.getByRole('button', {name: "Delete"})).toBeInTheDocument(); + }); + + it("Verify StoreEditControlPanel of mode new", ()=>{ + const mockRemoteStore = {name: "central", type: "remote", packageType: "maven", + key: "maven:remote:central", disabled: false, "allow_snapshots": true, + "allow_releases": true, url: "https://repo.maven.apache.org/maven2/", + description: "official maven central"}; + render( + + ); + + expect(screen.getByRole('button', {name: "Save"})).toBeInTheDocument(); + expect(screen.getByRole('button', {name: "Cancel"})).toBeInTheDocument(); + expect(screen.queryByRole('button', {name: "Delete"})).not.toBeInTheDocument(); + }); +}); diff --git a/src/main/webui/src/app/components/content/remote/RemoteEdit.jsx b/src/main/webui/src/app/components/content/remote/RemoteEdit.jsx index ea09e2c..7b7a84a 100644 --- a/src/main/webui/src/app/components/content/remote/RemoteEdit.jsx +++ b/src/main/webui/src/app/components/content/remote/RemoteEdit.jsx @@ -21,12 +21,13 @@ import {StoreEditControlPanel as EditControlPanel} from '../common/StoreControlP import {DisableTimeoutHint, DurationHint, PrefetchHint, Hint} from '../common/Hints.jsx'; import {PackageTypeSelect} from '../common/PackageTypeSelect.jsx'; // import ViewJsonDebugger from './Debugger.jsx'; -import {Utils} from '../../../utils/AppUtils.js'; -import {TimeUtils} from '../../../utils/TimeUtils.js'; -import {jsonRest} from '../../../utils/RestClient.js'; +import {Utils} from '#utils/AppUtils.js'; +import {TimeUtils} from '#utils/TimeUtils.js'; +import {jsonRest} from '#utils/RestClient.js'; +import {STORE_API_BASE_URL} from "../../ComponentConstants.js"; const init = (pkgType, storeName, setState) => { - const getUrl = `/api/admin/stores/${pkgType}/remote/${storeName}`; + const getUrl = `${STORE_API_BASE_URL}/${pkgType}/remote/${storeName}`; useEffect(()=>{ const fetchStore = async () =>{ // get Store data diff --git a/src/main/webui/src/app/components/content/remote/RemoteList.jsx b/src/main/webui/src/app/components/content/remote/RemoteList.jsx index be21265..91af495 100644 --- a/src/main/webui/src/app/components/content/remote/RemoteList.jsx +++ b/src/main/webui/src/app/components/content/remote/RemoteList.jsx @@ -17,7 +17,7 @@ import React, {useEffect, useState} from 'react'; import {ListJsonDebugger} from '../common/Debugger.jsx'; import ListControl from "../common/ListControl.jsx"; -import {remoteOptionLegend as options} from "../../ComponentConstants.js"; +import {remoteOptionLegend as options, STORE_API_BASE_URL} from "../../ComponentConstants.js"; import {StoreListingWidget} from '../common/StoreListingWidget.jsx'; import {Utils} from '#utils/AppUtils.js'; import {jsonRest} from '#utils/RestClient.js'; @@ -25,7 +25,7 @@ import {jsonRest} from '#utils/RestClient.js'; const init = (state, setState) => { useEffect(()=>{ const fetchdData = async ()=>{ - const response = await jsonRest.get(`/api/admin/stores/_all/remote`); + const response = await jsonRest.get(`${STORE_API_BASE_URL}/_all/remote`); if (response.ok){ const timeoutResponse = await jsonRest.get('/api/admin/schedule/store/all/disable-timeout'); let disabledMap = {}; diff --git a/src/main/webui/src/app/components/content/remote/RemoteView.jsx b/src/main/webui/src/app/components/content/remote/RemoteView.jsx index 78cd793..c6fc362 100644 --- a/src/main/webui/src/app/components/content/remote/RemoteView.jsx +++ b/src/main/webui/src/app/components/content/remote/RemoteView.jsx @@ -26,9 +26,10 @@ import {Filters} from '#utils/Filters.js'; import {Utils} from '#utils/AppUtils.js'; import {TimeUtils} from '#utils/TimeUtils.js'; import {jsonRest} from '#utils/RestClient.js'; +import {STORE_API_BASE_URL} from '../../ComponentConstants.js'; const init = (pkgType, storeName, setState) => { - const storeUrl = `/api/admin/stores/${pkgType}/remote/${storeName}`; + const storeUrl = `${STORE_API_BASE_URL}/${pkgType}/remote/${storeName}`; useEffect(()=>{ const fetchStore = async () => { const response = await jsonRest.get(storeUrl); diff --git a/src/main/webui/src/server/app.js b/src/main/webui/src/server/app.js index dfa7ed4..1380840 100644 --- a/src/main/webui/src/server/app.js +++ b/src/main/webui/src/server/app.js @@ -5,6 +5,7 @@ import {Config} from './config/AppConfig'; const projectRoot = path.resolve(__dirname, '../../dist'); const indexHtml=path.join(projectRoot+'/index.html'); +const STORE_API_BASE = "/api/admin/stores"; const app = express(); app.use(compression()); @@ -35,17 +36,17 @@ app.get('/api/stats/version-info', (req, res) => { }); }); -app.get('/api/admin/stores/_all/remote', (req, res) => { +app.get(`${STORE_API_BASE}/_all/remote`, (req, res) => { const remoteList = require('./mock/list/FakeRemoteList.json'); res.status(200).json(remoteList); }); -app.get('/api/admin/stores/_all/hosted', (req, res) => { +app.get(`${STORE_API_BASE}/_all/hosted`, (req, res) => { const hostedList = require('./mock/list/FakeHostedList.json'); res.status(200).json(hostedList); }); -app.get('/api/admin/stores/_all/group', (req, res) => { +app.get(`${STORE_API_BASE}/_all/group`, (req, res) => { const groupList = require('./mock/list/FakeGroupList.json'); res.status(200).json(groupList); }); @@ -68,7 +69,7 @@ app.get('/api/admin/schedule/store/:packageType/:type/:name/disable-timeout', (r } }); -app.get('/api/admin/stores/maven/remote/:name', (req, res) => { +app.get(`${STORE_API_BASE}/maven/remote/:name`, (req, res) => { const name = req.params.name; if(name){ const remoteList = require('./mock/list/FakeRemoteList.json'); @@ -83,7 +84,7 @@ app.get('/api/admin/stores/maven/remote/:name', (req, res) => { } }); -app.get('/api/admin/stores/maven/hosted/:name', (req, res) => { +app.get(`${STORE_API_BASE}/maven/hosted/:name`, (req, res) => { const name=req.params.name; if(name){ const remoteList = require('./mock/list/FakeHostedList.json'); @@ -98,7 +99,7 @@ app.get('/api/admin/stores/maven/hosted/:name', (req, res) => { } }); -app.get('/api/admin/stores/maven/group/:name', (req, res) => { +app.get(`${STORE_API_BASE}/maven/group/:name`, (req, res) => { const name=req.params.name; if(name){ const remoteList = require('./mock/list/FakeGroupList.json'); @@ -130,7 +131,7 @@ app.get('/api/admin/stores/maven/group/:name', (req, res) => { // return repo; // }; -app.post('/api/admin/stores/:packageType/:type/:name', (req, res) => { +app.post(`${STORE_API_BASE}/:packageType/:type/:name`, (req, res) => { const newRepo = req.body; if(req.headers['content-type']==="application/json"){ if (newRepo.packageType&&newRepo.type&&newRepo.name){ @@ -144,7 +145,7 @@ app.post('/api/admin/stores/:packageType/:type/:name', (req, res) => { } }); -app.put('/api/admin/stores/:packageType/:type/:name', (req, res) => { +app.put(`${STORE_API_BASE}/:packageType/:type/:name`, (req, res) => { const updatedRepo = req.body; if(req.headers['content-type']==="application/json"){ if (updatedRepo.packageType&&updatedRepo.type&&updatedRepo.name){