Skip to content

Commit

Permalink
US1200527 show legacy or application-based discovery info
Browse files Browse the repository at this point in the history
Discovery needs to remain backwards compatible with Okapi APIs; ditto
the `/settings/about` page that displays module and interface version
information.

There is not really as much work here as it appears. All the new
components were split out of `About` in order to allow sub-sections to
be reused with both application-based and module-based discovery
information. Likewise, `loginServices.js` and `discoveryServices.js`
were modestly refactored to handled both APIs.

And there are Jest/RTL tests to replace the BTOG test that could not be
easily updated to handle the new APIs since its `stripes-config` stub is
part of `@folio/stripes-cli` instead of being declared locally.

Refs US1200527
  • Loading branch information
zburke committed Dec 20, 2023
1 parent f321435 commit 06d4cc9
Show file tree
Hide file tree
Showing 24 changed files with 1,011 additions and 275 deletions.
253 changes: 47 additions & 206 deletions src/components/About/About.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
import _ from 'lodash';
import React, { useRef, useEffect } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import stripesConnect from '@folio/stripes-connect/package';
import stripesComponents from '@folio/stripes-components/package';
import stripesLogger from '@folio/stripes-logger/package';

import { okapi as okapiConfig } from 'stripes-config';
import {
Pane,
Headline,
List,
Loading
Loading,
Pane,
} from '@folio/stripes-components';

import AboutInstallMessages from './AboutInstallMessages';
import WarningBanner from './WarningBanner';
import { withModules } from '../Modules';
import stripesCore from '../../../package';
import css from './About.css';
import { useStripes } from '../../StripesContext';
import AboutOkapi from './AboutOkapi';
import AboutApplicationVersions from './AboutApplicationVersions';
import AboutStripes from './AboutStripes';
import AboutAPIGateway from './AboutAPIGateway';
import AboutUIDependencies from './AboutUIDependencies';
import AboutUIModuleDetails from './AboutUIModuleDetails';
import stripesCore from '../../../package';

const About = (props) => {
const titleRef = useRef(null);
const bannerRef = useRef(null);
const stripes = useStripes();

useEffect(() => {
if (bannerRef.current) {
Expand All @@ -30,120 +34,18 @@ const About = (props) => {
}
}, []);

function renderDependencies(m, interfaces) {
const base = `${m.module} ${m.version}`;
if (!interfaces) {
return base;
}

const okapiInterfaces = m.okapiInterfaces;
if (!okapiInterfaces) {
return <FormattedMessage id="stripes-core.about.noDependencies" values={{ base }} />;
}

const itemFormatter = (key) => {
const text = okapiInterfaces[key];

return (
<li key={key}>
{key}
{' '}
{text}
</li>
);
};

return (
<span>
<Headline size="small" faded>
<FormattedMessage id="stripes-core.about.moduleDependsOn" values={{ module: `${m.module} ${m.version || ''}` }} />
</Headline>
<List
items={Object.keys(okapiInterfaces).sort()}
itemFormatter={itemFormatter}
listStyle="bullets"
/>
</span>
);
}

function listModules(caption, list, interfaces) {
const itemFormatter = m => (<li key={m.module}>{renderDependencies(m, interfaces)}</li>);
let headlineMsg;
switch (caption) {
case 'app':
headlineMsg = <FormattedMessage id="stripes-core.about.appModuleCount" values={{ count: list.length }} />;
break;
case 'settings':
headlineMsg = <FormattedMessage id="stripes-core.about.settingsModuleCount" values={{ count: list.length }} />;
break;
case 'plugin':
headlineMsg = <FormattedMessage id="stripes-core.about.pluginModuleCount" values={{ count: list.length }} />;
break;
default:
headlineMsg = <FormattedMessage id="stripes-core.about.moduleTypeCount" values={{ count: list.length, type: caption }} />;
}

list.sort();

return (
<div key={caption}>
<Headline>{headlineMsg}</Headline>
<div data-test-stripes-core-about-module={caption}>
<List
listStyle="bullets"
items={list}
itemFormatter={itemFormatter}
/>
</div>
</div>
);
}

const applications =
_.get(props.stripes, ['discovery', 'applications']) || {};
const interfaces = _.get(props.stripes, ['discovery', 'interfaces']) || {};
const isLoadingFinished = _.get(props.stripes, ['discovery', 'isFinished']);
const applications = stripes.discovery?.applications || {};
const interfaces = stripes.discovery?.interfaces || {};
const isLoadingFinished = stripes.discovery?.isFinished;
const na = Object.keys(applications).length;

const unknownMsg = <FormattedMessage id="stripes-core.about.unknown" />;
const numApplicationsMsg = (
<FormattedMessage
id="stripes-core.about.applicationCount"
values={{ count: na }}
/>
);

const renderInterfaces = (list) => {
return (
<List
listStyle="square"
listClass={css.paddingLeftOfListItems}
items={list}
itemFormatter={(item) => <li key={item.name}>{item.name}</li>}
/>
);
};
const renderModules = (list) => {
return (
<List
listStyle="bullet"
listClass={css.paddingLeftOfListItems}
items={list}
itemFormatter={(item) => {
return (
<li>
<Headline weight="medium" margin="xx-small">
{item.name}
</Headline>
{renderInterfaces(item.interfaces)}
</li>
);
}}
/>
);
};

return (
<Pane
defaultWidth="fill"
Expand All @@ -159,106 +61,45 @@ const About = (props) => {
bannerRef={bannerRef}
/>
)}
<AboutInstallMessages stripes={props.stripes} />
<AboutInstallMessages />
<div className={css.versionsContainer}>
<div className={css.versionsColumn}>
<Headline size="large">
<FormattedMessage id="stripes-core.about.applicationsVersionsTitle" />
</Headline>
<Headline>{numApplicationsMsg}</Headline>
{Object.values(applications)
.map((app) => {
return (
<ul key={app.name}>
<li>
<Headline>{app.name}</Headline>
{renderModules(app.modules)}
</li>
</ul>
);
})}
</div>

<div className={css.versionsColumn}>
<Headline size="large">
<FormattedMessage id="stripes-core.about.userInterface" />
</Headline>
<Headline>
<FormattedMessage id="stripes-core.about.foundation" />
</Headline>
<span
id="platform-versions"
data-stripes-core={stripesCore.version}
data-stripes-connect={stripesConnect.version}
data-stripes-components={stripesComponents.version}
data-okapi-version={_.get(props.stripes, ['discovery', 'okapi']) || unknownMsg}
data-okapi-url={_.get(props.stripes, ['okapi', 'url']) || unknownMsg}
/>
<List
listStyle="bullets"
items={[
{
key: 'stripes-core',
value: `stripes-core ${stripesCore.version}`,
},
{
key: 'stripes-connect',
value: `stripes-connect ${stripesConnect.version}`,
},
{
key: 'stripes-components',
value: `stripes-components ${stripesComponents.version}`,
},
{
key: 'stripes-logger',
value: `stripes-logger ${stripesLogger.version}`,
},
]}
itemFormatter={item => (<li key={item.key}>{item.value}</li>)}
/>

<br />
<Headline size="large">
<FormattedMessage id="stripes-core.about.okapiServices" />
</Headline>
<Headline>
<FormattedMessage id="stripes-core.about.foundation" />
</Headline>
<List
listStyle="bullets"
itemFormatter={(item, i) => (<li key={i}>{item}</li>)}
items={[
<FormattedMessage id="stripes-core.about.version" values={{ version: _.get(props.stripes, ['discovery', 'okapi']) || unknownMsg }} />,
<FormattedMessage id="stripes-core.about.forTenant" values={{ tenant: _.get(props.stripes, ['okapi', 'tenant']) || unknownMsg }} />,
<FormattedMessage id="stripes-core.about.onUrl" values={{ url: _.get(props.stripes, ['okapi', 'url']) || unknownMsg }} />
]}
/>
<br />
<Headline size="large">
<FormattedMessage id="stripes-core.about.uiOrServiceDependencies" />
</Headline>
<Headline>
<FormattedMessage id="stripes-core.about.foundation" />
</Headline>
{renderDependencies(Object.assign({}, stripesCore.stripes || {}, { module: 'stripes-core' }), interfaces)}
<br />
{Object.keys(props.modules).map(key => listModules(key, props.modules[key], interfaces))}
</div>
{okapiConfig.tenantEntitlementUrl ? (
<>
<div className={css.versionsColumn} data-test-stripes-core-about-module-versions>
<AboutApplicationVersions message={numApplicationsMsg} applications={applications} />
</div>
<div className={css.versionsColumn}>
<AboutStripes />
<br />
<AboutAPIGateway />
<br />
<Headline size="large">
<FormattedMessage id="stripes-core.about.uiOrServiceDependencies" />
</Headline>
<Headline>
<FormattedMessage id="stripes-core.about.foundation" />
</Headline>
<AboutUIModuleDetails
module={{
...stripesCore.stripes,
module: 'stripes-core',
version: stripesCore.version
}}
showDependencies
/>
<AboutUIDependencies modules={props.modules} showDependencies />
</div>
</>
) : (
<AboutOkapi discovery={stripes.discovery} />
)}
</div>
</Pane>
);
};

About.propTypes = {
modules: PropTypes.object,
stripes: PropTypes.shape({
discovery: PropTypes.shape({
modules: PropTypes.object,
interfaces: PropTypes.object,
}),
connect: PropTypes.func,
hasPerm: PropTypes.func.isRequired,
}).isRequired,
};

export default withModules(About);
Loading

0 comments on commit 06d4cc9

Please sign in to comment.