Skip to content

Commit

Permalink
Add loading spiner and use it for remote content fetching
Browse files Browse the repository at this point in the history
  • Loading branch information
ligangty committed Dec 2, 2023
1 parent 81511ed commit 2ef20a3
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/main/webui/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@
"nonblock-statement-body-position": 2,
"object-curly-newline": 2,
"object-curly-spacing": [
2,
1,
"never"
],
"object-property-newline": 0,
Expand Down
22 changes: 22 additions & 0 deletions src/main/webui/src/app/components/content/common/LoadingSpiner.jsx
Original file line number Diff line number Diff line change
@@ -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 = () =><div>
<span className="loader">Loading...</span>
</div>;

Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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){
Expand Down Expand Up @@ -81,10 +84,15 @@ export default function RemoteList() {
});
});
}
setLoading(false);
};
fetchdData();
}, [packageType]);

if (loading) {
return <LoadingSpiner />;
}

return (
<React.Fragment>
<ListControl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {StoreViewControlPanel as ControlPanel} from '../common/StoreControlPanel
import {Hint, PasswordMask} from '../common/Hints.jsx';
import {StoreViewBasicSection as BasicSection} from '../common/StoreBasicSections.jsx';
import {StoreViewCapabilitiesSection} from '../common/StoreCapabilitiesSections.jsx';
import {LoadingSpiner} from '../common/LoadingSpiner.jsx';
// import ViewJsonDebugger from './Debugger.jsx';
import {Filters} from '#utils/Filters.js';
import {Utils} from '#utils/AppUtils.js';
Expand Down Expand Up @@ -155,9 +156,11 @@ export default function RemoteView() {
raw: {},
message: ''
});
const [loading, setLoading] = useState(true);
const {packageType, name} = useParams();

useEffect(()=>{
setLoading(true);
const fetchStore = async () => {
const response = await jsonRest.get(`${STORE_API_BASE_URL}/${packageType}/remote/${name}`);
if (response.ok){
Expand Down Expand Up @@ -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 <LoadingSpiner />;
}

const store = state.store;
if(!Utils.isEmptyObj(store)) {
return (
Expand Down
9 changes: 9 additions & 0 deletions src/main/webui/src/app/components/styles/indy.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
37 changes: 26 additions & 11 deletions src/main/webui/src/server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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"});
Expand Down

0 comments on commit 2ef20a3

Please sign in to comment.