diff --git a/src/main/webui/.eslintrc.json b/src/main/webui/.eslintrc.json
index f91204b..053a2f9 100644
--- a/src/main/webui/.eslintrc.json
+++ b/src/main/webui/.eslintrc.json
@@ -230,7 +230,7 @@
"nonblock-statement-body-position": 2,
"object-curly-newline": 2,
"object-curly-spacing": [
- 2,
+ 1,
"never"
],
"object-property-newline": 0,
diff --git a/src/main/webui/src/app/components/content/common/LoadingSpiner.jsx b/src/main/webui/src/app/components/content/common/LoadingSpiner.jsx
new file mode 100644
index 0000000..d9c90b0
--- /dev/null
+++ b/src/main/webui/src/app/components/content/common/LoadingSpiner.jsx
@@ -0,0 +1,22 @@
+/**
+ * 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';
+
+export const LoadingSpiner = () =>
+ Loading...
+
;
+
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 df6f139..0ab6f6e 100644
--- a/src/main/webui/src/app/components/content/remote/RemoteList.jsx
+++ b/src/main/webui/src/app/components/content/remote/RemoteList.jsx
@@ -20,6 +20,7 @@ import {ListJsonDebugger} from '../common/Debugger.jsx';
import ListControl from "../common/ListControl.jsx";
import {remoteOptionLegend as options, STORE_API_BASE_URL} from "../../ComponentConstants.js";
import {StoreListingWidget} from '../common/StoreListingWidget.jsx';
+import {LoadingSpiner} from "../common/LoadingSpiner.jsx";
import {Utils} from '#utils/AppUtils.js';
import {jsonRest} from '#utils/RestClient.js';
@@ -52,8 +53,10 @@ export default function RemoteList() {
enableDebug: false,
message: ''
});
+ const [loading, setLoading] = useState(true);
useEffect(()=>{
+ setLoading(true);
const fetchdData = async ()=>{
const response = await jsonRest.get(`${STORE_API_BASE_URL}/${packageType}/remote`);
if (response.ok){
@@ -81,10 +84,15 @@ export default function RemoteList() {
});
});
}
+ setLoading(false);
};
fetchdData();
}, [packageType]);
+ if (loading) {
+ return ;
+ }
+
return (
{
+ setLoading(true);
const fetchStore = async () => {
const response = await jsonRest.get(`${STORE_API_BASE_URL}/${packageType}/remote/${name}`);
if (response.ok){
@@ -186,11 +189,16 @@ export default function RemoteView() {
Utils.logMessage(`Failed to get store data. Error reason: ${response.status}->${data}`);
});
}
+ setLoading(false);
};
fetchStore();
}, [packageType, name]);
+ if (loading) {
+ return ;
+ }
+
const store = state.store;
if(!Utils.isEmptyObj(store)) {
return (
diff --git a/src/main/webui/src/app/components/styles/indy.css b/src/main/webui/src/app/components/styles/indy.css
index 200b45e..8b8d102 100644
--- a/src/main/webui/src/app/components/styles/indy.css
+++ b/src/main/webui/src/app/components/styles/indy.css
@@ -445,3 +445,12 @@ label, .label{
float: right;
margin-bottom: 6px;
}
+
+.loader {
+ color: rgb(0, 0, 0);
+ display: inline-block;
+ position: relative;
+ font-size: 24px;
+ font-family: Arial, Helvetica, sans-serif;
+ box-sizing: border-box;
+}
diff --git a/src/main/webui/src/server/app.js b/src/main/webui/src/server/app.js
index 8a426b0..b96d59e 100644
--- a/src/main/webui/src/server/app.js
+++ b/src/main/webui/src/server/app.js
@@ -3,6 +3,7 @@ import compression from 'compression';
import express from 'express';
import path from 'path';
import {Config} from './config/AppConfig';
+import {existsSync} from 'fs';
const projectRoot = path.resolve(__dirname, '../../dist');
const indexHtml=path.join(projectRoot+'/index.html');
@@ -38,33 +39,47 @@ app.get('/api/stats/version-info', (req, res) => {
});
const decideMockListFile = (packgeType, type) => {
- const pkgToFileMapping = {"maven": "Maven", "npm": "NPM"};
+ const pkgToFileMapping = {"maven": "Maven", "generic-http": "Generic", "npm": "NPM"};
const typeToFileMapping = {"remote": "Remote", "hosted": "Hosted", "group": "Group"};
- return `./mock/list/Fake${pkgToFileMapping[packgeType]}${typeToFileMapping[type]}List.json`;
+ path.resolve(__dirname, './file-location');
+ return path.resolve(__dirname, `./mock/list/Fake${pkgToFileMapping[packgeType]}${typeToFileMapping[type]}List.json`);
};
+
+const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
+
// For store listing
-app.get(`${STORE_API_BASE}/:packageType/:type`, (req, res) => {
+app.get(`${STORE_API_BASE}/:packageType/:type`, async (req, res) => {
+ await sleep(2000);
const [pkgType, type] = [req.params.packageType, req.params.type];
if(pkgType==="_all"){
// TODO: do all packageType for type handling here
}
const mockFile = decideMockListFile(pkgType, type);
- const list = require(mockFile);
- res.status(200).json(list);
+ if(existsSync(mockFile)){
+ const list = require(mockFile);
+ res.status(200).json(list);
+ }else{
+ res.status(404).json({error: "No such stores!"});
+ }
});
// For single store get
-app.get(`${STORE_API_BASE}/:packageType/:type/:name`, (req, res) => {
+app.get(`${STORE_API_BASE}/:packageType/:type/:name`, async (req, res) => {
+ await sleep(1000);
const [pkgType, type, name] = [req.params.packageType, req.params.type, req.params.name];
if(pkgType && type && name){
const mockListFile = decideMockListFile(pkgType, type);
- const repoList = require(mockListFile);
- const result = repoList.items.find(item=>item.name===name);
- if(result){
- res.status(200).json(result);
+ if(existsSync(mockListFile)){
+ const repoList = require(mockListFile);
+ const result = repoList.items.find(item=>item.name===name);
+ if(result){
+ res.status(200).json(result);
+ }else{
+ res.status(404).json({error: "No such store!"});
+ }
}else{
- res.status(404).json({error: "No such store!"});
+ res.status(404).json({error: "No such stores!"});
}
}else{
res.status(400).json({error: "Missing store name"});