Skip to content

Commit

Permalink
Merge pull request #504 from FraunhoferISST/feat/490-erp-button
Browse files Browse the repository at this point in the history
feat(Dashboard): add button to schedule erp update manually
  • Loading branch information
mhellmeier authored Jul 18, 2024
2 parents 5ebdd4a + 8208501 commit a7c7e04
Show file tree
Hide file tree
Showing 16 changed files with 247 additions and 19 deletions.
3 changes: 2 additions & 1 deletion charts/puris/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ dependencies:
| frontend.autoscaling.minReplicas | int | `1` | Number of minimum replica pods for autoscaling |
| frontend.autoscaling.targetCPUUtilizationPercentage | int | `80` | Value of CPU usage in percentage for autoscaling decisions |
| frontend.env | object | `{}` | Extra environment variables that will be passed onto the frontend deployment pods |
| frontend.image.pullPolicy | string | `"IfNotPresent"` | THe policy for the image pull process |
| frontend.image.pullPolicy | string | `"Always"` | THe policy for the image pull process |
| frontend.image.repository | string | `"tractusx/app-puris-frontend"` | Repository of the docker image |
| frontend.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. |
| frontend.imagePullSecrets | list | `[]` | List of used secrets |
Expand All @@ -172,6 +172,7 @@ dependencies:
| frontend.puris.endpointCustomer | string | `"stockView/customer?ownMaterialNumber="` | The endpoint for the customers who buy a material identified via the own material number for the stock view |
| frontend.puris.endpointDelivery | string | `"delivery"` | The endpoint for the delivery submodel |
| frontend.puris.endpointDemand | string | `"demand"` | The endpoint for the demand submodel |
| frontend.puris.endpointErpScheduleUpdate | string | `"erp-adapter/trigger"` | The endpoint for scheduling an update of erp data (currently only stock supported) |
| frontend.puris.endpointMaterialStocks | string | `"stockView/material-stocks"` | The endpoint for material stocks for the stock view |
| frontend.puris.endpointMaterials | string | `"stockView/materials"` | The endpoint for materials for the stock view |
| frontend.puris.endpointPartners | string | `"partners"` | The endpoint for partner information |
Expand Down
2 changes: 2 additions & 0 deletions charts/puris/templates/frontend-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ spec:
value: "{{ .Values.frontend.puris.endpointUpdateReportedMaterialStocks }}"
- name: ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS
value: "{{ .Values.frontend.puris.endpointUpdateReportedProductStocks }}"
- name: ENDPOINT_ERP_SCHEDULE_UPDATE
value: "{{ .Values.frontend.puris.endpointErpScheduleUpdate }}"
- name: ENDPOINT_PARTNER
value: "{{ .Values.frontend.puris.endpointPartners }}"
- name: ENDPOINT_DEMAND
Expand Down
4 changes: 3 additions & 1 deletion charts/puris/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ frontend:
# -- Repository of the docker image
repository: tractusx/app-puris-frontend
# -- THe policy for the image pull process
pullPolicy: IfNotPresent
pullPolicy: Always
# -- Overrides the image tag whose default is the chart appVersion.
tag: ""

Expand Down Expand Up @@ -183,6 +183,8 @@ frontend:
endpointUpdateReportedMaterialStocks: stockView/update-reported-material-stocks?ownMaterialNumber=
# -- The endpoint for triggering an update of your product stocks on your partners side
endpointUpdateReportedProductStocks: stockView/update-reported-product-stocks?ownMaterialNumber=
# -- The endpoint for scheduling an update of erp data (currently only stock supported)
endpointErpScheduleUpdate: erp-adapter/trigger
# -- The endpoint for partner information
endpointPartners: partners
# -- The endpoint for the demand submodel
Expand Down
1 change: 1 addition & 0 deletions frontend/.env
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ VITE_ENDPOINT_REPORTED_MATERIAL_STOCKS=stockView/reported-material-stocks?ownMat
VITE_ENDPOINT_REPORTED_PRODUCT_STOCKS=stockView/reported-product-stocks?ownMaterialNumber=
VITE_ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS=stockView/update-reported-material-stocks?ownMaterialNumber=
VITE_ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS=stockView/update-reported-product-stocks?ownMaterialNumber=
VITE_ENDPOINT_ERP_SCHEDULE_UPDATE=erp-adapter/trigger
VITE_ENDPOINT_PARTNER=partners
VITE_ENDPOINT_DEMAND=demand
VITE_ENDPOINT_PRODUCTION=production
Expand Down
1 change: 1 addition & 0 deletions frontend/.env.dockerbuild
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ VITE_ENDPOINT_REPORTED_MATERIAL_STOCKS=\$ENDPOINT_REPORTED_MATERIAL_STOCKS
VITE_ENDPOINT_REPORTED_PRODUCT_STOCKS=\$ENDPOINT_REPORTED_PRODUCT_STOCKS
VITE_ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS=\$ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS
VITE_ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS=\$ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS
VITE_ENDPOINT_ERP_SCHEDULE_UPDATE=\$ENDPOINT_ERP_SCHEDULE_UPDATE
VITE_ENDPOINT_PARTNER=\$ENDPOINT_PARTNER
VITE_ENDPOINT_DEMAND=\$ENDPOINT_DEMAND
VITE_ENDPOINT_PRODUCTION=\$ENDPOINT_PRODUCTION
Expand Down
2 changes: 1 addition & 1 deletion frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#
# SPDX-License-Identifier: Apache-2.0
#
FROM node:lts-alpine as build
FROM node:lts-alpine AS build

ARG NPM_BUILD_MODE=dockerbuild

Expand Down
1 change: 1 addition & 0 deletions frontend/src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"ENDPOINT_REPORTED_PRODUCT_STOCKS": "$ENDPOINT_REPORTED_PRODUCT_STOCKS",
"ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS":"$ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS",
"ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS":"$ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS",
"ENDPOINT_ERP_SCHEDULE_UPDATE":"$ENDPOINT_ERP_SCHEDULE_UPDATE",
"ENDPOINT_PARTNER": "$ENDPOINT_PARTNER",
"ENDPOINT_DEMAND": "$ENDPOINT_DEMAND",
"ENDPOINT_PRODUCTION": "$ENDPOINT_PRODUCTION",
Expand Down
113 changes: 106 additions & 7 deletions frontend/src/features/dashboard/components/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright (c) 2024 Volkswagen AG
Copyright (c) 2024 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V. (represented by Fraunhofer ISST)
Copyright (c) 2024 Contributors to the Eclipse Foundation
See the NOTICE file(s) distributed with this work for additional
Expand All @@ -21,15 +22,15 @@ import { usePartnerStocks } from '@features/stock-view/hooks/usePartnerStocks';
import { useStocks } from '@features/stock-view/hooks/useStocks';
import { MaterialDescriptor } from '@models/types/data/material-descriptor';
import { Site } from '@models/types/edc/site';
import { useCallback, useReducer } from 'react';
import { useCallback, useReducer, useState } from 'react';
import { DashboardFilters } from './DashboardFilters';
import { DemandTable } from './DemandTable';
import { ProductionTable } from './ProductionTable';
import { Box, Button, Stack, Typography, capitalize } from '@mui/material';
import { Box, Button, capitalize, Stack, Typography } from '@mui/material';
import { Delivery } from '@models/types/data/delivery';
import { DeliveryInformationModal } from './DeliveryInformationModal';
import { getPartnerType } from '../util/helpers';
import { LoadingButton } from '@catena-x/portal-shared-components';
import { LoadingButton, PageSnackbar, PageSnackbarStack } from '@catena-x/portal-shared-components';
import { Refresh } from '@mui/icons-material';
import { Demand } from '@models/types/data/demand';
import { DemandCategoryModal } from './DemandCategoryModal';
Expand All @@ -41,12 +42,13 @@ import { PlannedProductionModal } from './PlannedProductionModal';
import { useProduction } from '../hooks/useProduction';
import { useReportedProduction } from '../hooks/useReportedProduction';

import { requestReportedStocks } from '@services/stocks-service';
import { requestReportedStocks, scheduleErpUpdateStocks } from '@services/stocks-service';
import { useDelivery } from '../hooks/useDelivery';
import { requestReportedDeliveries } from '@services/delivery-service';
import { requestReportedProductions } from '@services/productions-service';
import { requestReportedDemands } from '@services/demands-service';
import { ModalMode } from '@models/types/data/modal-mode';
import { Notification } from "@models/types/data/notification.ts";

const NUMBER_OF_DAYS = 28;

Expand All @@ -61,6 +63,7 @@ type DashboardState = {
demand: Partial<Demand> | null;
production: Partial<Production> | null;
isRefreshing: boolean;
isErpRefreshing: false;
};

type DashboardAction = {
Expand All @@ -83,6 +86,7 @@ const initialState: DashboardState = {
demand: null,
production: null,
isRefreshing: false,
isErpRefreshing: false,
};

export const Dashboard = ({ type }: { type: 'customer' | 'supplier' }) => {
Expand All @@ -104,15 +108,68 @@ export const Dashboard = ({ type }: { type: 'customer' | 'supplier' }) => {
state.selectedSite?.bpns ?? null
);

const [notifications, setNotifications] = useState<Notification[]>([]);

const handleRefresh = () => {
dispatch({ type: 'isRefreshing', payload: true });
dispatch({type: 'isRefreshing', payload: true});
Promise.all([
requestReportedStocks(type === 'customer' ? 'material' : 'product', state.selectedMaterial?.ownMaterialNumber ?? null),
requestReportedDeliveries(state.selectedMaterial?.ownMaterialNumber ?? null),
type === 'customer'
? requestReportedProductions(state.selectedMaterial?.ownMaterialNumber ?? null)
: requestReportedDemands(state.selectedMaterial?.ownMaterialNumber ?? null)
]).finally(() => dispatch({ type: 'isRefreshing', payload: false }));
]).then(() => {
setNotifications(ns => [
...ns,
{
title: 'Update requested',
description: `Requested update from partners for ${state.selectedMaterial?.ownMaterialNumber}. Please reload dialog later.`,
severity: 'success',
},
]);
}).catch((error: unknown) => {
const msg = error !== null && typeof error === 'object' && 'message' in error && typeof error.message === 'string' ? error.message : 'Unknown Error';
setNotifications(ns => [
...ns,
{
title: 'Error requesting update',
description: msg,
severity: 'error',
},
]);
}).finally(() => dispatch({type: 'isRefreshing', payload: false}))
};
// };
const handleScheduleErpUpdate = () => {
dispatch({ type: 'isErpRefreshing', payload: true });
if (state.selectedPartnerSites){
const promises: Promise<void>[] = state.selectedPartnerSites.map((ps: Site) => {
return scheduleErpUpdateStocks(type === 'customer' ? 'material' : 'product', ps.belongsToPartnerBpnl, state.selectedMaterial?.ownMaterialNumber ?? null);
});
Promise.all(promises)
.then(() => {
setNotifications(ns => [
...ns,
{
title: 'Update requested',
description: `Scheduled ERP data update of stocks for ${state.selectedMaterial?.ownMaterialNumber} in your role as ${type}. Please reload dialog later.`,
severity: 'success',
},
]);
})
.catch((error: unknown) => {
const msg = error !== null && typeof error === 'object' && 'message' in error && typeof error.message === 'string' ? error.message : 'Unknown Error';
setNotifications(ns => [
...ns,
{
title: 'Error scheduling ERP update',
description: msg,
severity: 'error',
},
]);
})
.finally(() => dispatch({type: 'isErpRefreshing', payload:false }));
}
};
const openDeliveryDialog = useCallback(
(d: Partial<Delivery>, mode: ModalMode, direction: 'incoming' | 'outgoing' = 'outgoing', site: Site | null) => {
Expand Down Expand Up @@ -193,12 +250,40 @@ export const Dashboard = ({ type }: { type: 'customer' | 'supplier' }) => {
</Box>
{state.selectedSite && (
<Stack width="100%">
<Box display="flex" justifyContent="space-between">
<Box
display="flex"
justifyContent="start"
alignItems="center"
width="100%"
gap="0.5rem"
marginBlock="0.5rem"
paddingLeft=".5rem"
>
<Typography variant="h5" component="h2">
{`${capitalize(getPartnerType(type))} Information ${
state.selectedMaterial ? `for ${state.selectedMaterial.description} (${state.selectedMaterial.ownMaterialNumber})` : ''
}`}
</Typography>
<Box marginLeft="auto" display="flex" gap="1rem">
{state.selectedPartnerSites?.length &&
(state.isErpRefreshing ? (
<LoadingButton
label="Schedule ERP Update"
loadIndicator="scheduling..."
loading={state.isErpRefreshing}
variant="contained"
onButtonClick={handleScheduleErpUpdate}
sx={{ width: '15rem' }}
/>
) : (
<Button
variant="contained"
onClick={handleScheduleErpUpdate}
sx={{ display: 'flex', alignItems: 'center', gap: '0.5rem', width: '15rem' }}
>
<Refresh></Refresh> Schedule ERP Update
</Button>
))}
{state.selectedPartnerSites?.length &&
(state.isRefreshing ? (
<LoadingButton
Expand All @@ -218,6 +303,7 @@ export const Dashboard = ({ type }: { type: 'customer' | 'supplier' }) => {
<Refresh></Refresh> Refresh
</Button>
))}
</Box>
</Box>
<Stack spacing={4}>
{state.selectedPartnerSites ? (
Expand Down Expand Up @@ -280,6 +366,19 @@ export const Dashboard = ({ type }: { type: 'customer' | 'supplier' }) => {
delivery={state.delivery}
deliveries={deliveries ?? []}
/>
<PageSnackbarStack>
{notifications.map((notification, index) => (
<PageSnackbar
key={index}
open={!!notification}
severity={notification?.severity}
title={notification?.title}
description={notification?.description}
autoClose={true}
onCloseNotification={() => setNotifications((ns) => ns.filter((_, i) => i !== index) ?? [])}
/>
))}
</PageSnackbarStack>
</>
);
}
11 changes: 9 additions & 2 deletions frontend/src/features/dashboard/components/DashboardFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright (c) 2024 Volkswagen AG
Copyright (c) 2024 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V. (represented by Fraunhofer ISST)
Copyright (c) 2024 Contributors to the Eclipse Foundation
See the NOTICE file(s) distributed with this work for additional
Expand All @@ -24,7 +25,7 @@ import { usePartners } from '@features/stock-view/hooks/usePartners';
import { useSites } from '@features/stock-view/hooks/useSites';
import { MaterialDescriptor } from '@models/types/data/material-descriptor';
import { Site } from '@models/types/edc/site';
import { Autocomplete, Grid, InputLabel, capitalize } from '@mui/material';
import { Autocomplete, capitalize, Grid, InputLabel } from '@mui/material';
import { getPartnerType } from '../util/helpers';
import { LabelledAutoComplete } from '@components/ui/LabelledAutoComplete';

Expand Down Expand Up @@ -80,7 +81,13 @@ export const DashboardFilters = ({
<Autocomplete
id="partner-site"
value={partnerSites ?? []}
options={partners?.reduce((acc: Site[], p) => [...acc, ...p.sites], []) ?? []}
options={partners?.reduce((acc: Site[], p) => {
const sitesWithBpnl = p.sites.map(site => ({
...site,
belongsToPartnerBpnl: p.bpnl
}));
return [...acc, ...sitesWithBpnl];
}, []) ?? [] }
disabled={!site}
getOptionLabel={(option) => `${option.name} (${option.bpns})`}
isOptionEqualToValue={(option, value) => option.bpns === value.bpns}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/models/constants/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const app = {
ENDPOINT_REPORTED_PRODUCT_STOCKS: import.meta.env.VITE_ENDPOINT_REPORTED_PRODUCT_STOCKS.trim() as string,
ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS: import.meta.env.VITE_ENDPOINT_UPDATE_REPORTED_MATERIAL_STOCKS.trim() as string,
ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS: import.meta.env.VITE_ENDPOINT_UPDATE_REPORTED_PRODUCT_STOCKS.trim() as string,
ENDPOINT_ERP_SCHEDULE_UPDATE: import.meta.env.VITE_ENDPOINT_ERP_SCHEDULE_UPDATE.trim() as string,
ENDPOINT_PARTNER: import.meta.env.VITE_ENDPOINT_PARTNER.trim() as string,
ENDPOINT_DEMAND: import.meta.env.VITE_ENDPOINT_DEMAND.trim() as string,
ENDPOINT_PRODUCTION: import.meta.env.VITE_ENDPOINT_PRODUCTION.trim() as string,
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/models/types/edc/site.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
Copyright (c) 2024 Volkswagen AG
Copyright (c) 2024 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V. (represented by Fraunhofer ISST)
Copyright (c) 2024 Contributors to the Eclipse Foundation
See the NOTICE file(s) distributed with this work for additional
Expand All @@ -19,10 +20,11 @@ SPDX-License-Identifier: Apache-2.0
*/

import { Address } from './address';
import { BPNS } from './bpn';
import { BPNL, BPNS } from './bpn';

export type Site = {
bpns: BPNS;
name: string;
addresses: Address[];
belongsToPartnerBpnl: BPNL;
};
27 changes: 27 additions & 0 deletions frontend/src/models/types/erp/assetType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2024 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V. (represented by Fraunhofer ISST)
* Copyright (c) 2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
*/

export enum AssetType {
ItemStock = 'ITEM_STOCK_SUBMODEL',
Production = 'PRODUCTION_SUBMODEL',
Delivery = 'DELIVERY_INFORMATION_SUBMODEL',
Demand = 'DEMAND_SUBMODEL',
PartType = 'PART_TYPE_INFORMATION_SUBMODEL',
}
24 changes: 24 additions & 0 deletions frontend/src/models/types/erp/directionType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2024 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V. (represented by Fraunhofer ISST)
* Copyright (c) 2024 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://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.
*
* SPDX-License-Identifier: Apache-2.0
*/

export enum DirectionType {
Inbound = 'INBOUND',
Outbound = 'OUTBOUND',
}
Loading

0 comments on commit a7c7e04

Please sign in to comment.