Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,871 changes: 878 additions & 993 deletions GUI/package-lock.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions GUI/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@
"test:coverage": "vitest run --coverage",
"typecheck": "./typecheck.sh"
},
"overrides": {
"sanitize-html": {
"htmlparser2": "10.1.0"
}
},
"browserslist": [
"defaults",
"not IE 11"
Expand Down
5 changes: 5 additions & 0 deletions GUI/src/components/Flow/NodeTypes/Node.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
}
}

.jump-to-service-link-disabled {
color: get-color(black-coral-6);
text-decoration: line-through;
}

.file-name-extension {
color: get-color(black-coral-6);
}
Expand Down
6 changes: 5 additions & 1 deletion GUI/src/components/Flow/NodeTypes/StepNode.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ const jumpToServiceData: NodeDataProps = {
describe('StepNode jump-to-service navigation', () => {
beforeEach(() => {
mockNavigate.mockClear();
useServiceStore.setState({ hasUnsavedChanges: false, nextLocation: null });
useServiceStore.setState({
hasUnsavedChanges: false,
nextLocation: null,
navigableServices: new Map([['other-service-id', 'Other Service']]),
});
});

it('navigates directly to the target service when there are no unsaved changes', () => {
Expand Down
27 changes: 19 additions & 8 deletions GUI/src/components/Flow/NodeTypes/StepNode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@
const { t } = useTranslation();
const navigate = useNavigate();
const endpoints = useServiceStore((state) => state.endpoints);
const navigableServices = useServiceStore((state) => state.navigableServices);
const [isTestedAndPassed, setIsTestedAndPassed] = useState<boolean | null>(null);

const jumpToServiceId = data.jumpToService?.serviceId;
const isJumpToServiceValid = !!jumpToServiceId && navigableServices.has(jumpToServiceId);
const jumpToServiceName =
(jumpToServiceId && navigableServices.get(jumpToServiceId)) || data.jumpToService?.serviceName;

const handleJumpToServiceClick = (event: MouseEvent) => {
event.stopPropagation();

const serviceId = data.jumpToService?.serviceId;
if (!serviceId) return;
if (!isJumpToServiceValid || !jumpToServiceId) return;

navigateToService(serviceId, navigate);
navigateToService(jumpToServiceId, navigate);
};

const boldText = {
Expand Down Expand Up @@ -148,13 +153,19 @@
<p style={boldText}>{t('serviceFlow.popup.redirectToCustomerSupport')}</p>
)}
{data.stepType === StepType.JumpToService && data.jumpToService?.serviceName && (
<p
style={{ ...boldText, cursor: data.jumpToService.serviceId ? 'pointer' : 'default' }}
className={data.jumpToService.serviceId ? 'jump-to-service-link' : undefined}
onClick={data.jumpToService.serviceId ? handleJumpToServiceClick : undefined}
title={data.jumpToService.serviceId ? t('serviceFlow.element.jumpToService.navigateToService') : undefined}
style={{ ...boldText, cursor: isJumpToServiceValid ? 'pointer' : 'not-allowed' }}
className={isJumpToServiceValid ? 'jump-to-service-link' : 'jump-to-service-link-disabled'}
onClick={isJumpToServiceValid ? handleJumpToServiceClick : undefined}
title={
isJumpToServiceValid
? t('serviceFlow.element.jumpToService.navigateToService')
: t('serviceFlow.element.jumpToService.deletedService', {
serviceName: jumpToServiceName,
})
}
>

Check warning on line 167 in GUI/src/components/Flow/NodeTypes/StepNode.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Visible, non-interactive elements with click handlers must have at least one keyboard listener.

See more on https://sonarcloud.io/project/issues?id=buerokratt_Service-Module&issues=AZ-3JMr4yCwa84bhmC4w&open=AZ-3JMr4yCwa84bhmC4w&pullRequest=1135

Check warning on line 167 in GUI/src/components/Flow/NodeTypes/StepNode.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Non-interactive elements should not be assigned mouse or keyboard event listeners.

See more on https://sonarcloud.io/project/issues?id=buerokratt_Service-Module&issues=AZ-3JMr4yCwa84bhmC4v&open=AZ-3JMr4yCwa84bhmC4v&pullRequest=1135
&rarr; {data.jumpToService.serviceName}
&rarr; {jumpToServiceName}
</p>
)}
{data.stepType === StepType.Rule && (
Expand Down
14 changes: 12 additions & 2 deletions GUI/src/components/FlowElementsPopup/JumpToServiceContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ const JumpToServiceContent: FC<JumpToServiceContentProps> = ({ node, jumpToServi
) ?? null)
: null;

const isLinkedServiceDeleted =
!isLoading && !!jumpToService.serviceId && !services.some((s) => s.serviceId === jumpToService.serviceId);

const handleServiceChange = (selection: { label: string; value: { name: string; serviceId: string } } | null) => {
if (!selection) return;
const service = services.find((s) => s.serviceId === selection.value.serviceId);
Expand Down Expand Up @@ -92,7 +95,7 @@ const JumpToServiceContent: FC<JumpToServiceContentProps> = ({ node, jumpToServi
onSelectionChange={handleServiceChange}
/>
</div>
{jumpToService.serviceId && (
{jumpToService.serviceId && !isLinkedServiceDeleted && (
<Button
appearance="icon"
size="s"
Expand All @@ -104,7 +107,14 @@ const JumpToServiceContent: FC<JumpToServiceContentProps> = ({ node, jumpToServi
</Button>
)}
</Track>
{services.length === 0 && (
{isLinkedServiceDeleted && (
<p style={{ color: '#c00', fontSize: '13px' }}>
{t('serviceFlow.element.jumpToService.deletedService', {
serviceName: jumpToService.serviceName,
})}
</p>
)}
{!isLinkedServiceDeleted && services.length === 0 && (
<p style={{ color: '#888', fontSize: '13px' }}>
{t('serviceFlow.element.jumpToService.noActiveServices')}
</p>
Expand Down
3 changes: 2 additions & 1 deletion GUI/src/i18n/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@
"selectService": "Select a service...",
"noActiveServices": "No active services available",
"parameters": "Parameters",
"navigateToService": "Open this service"
"navigateToService": "Open this service",
"deletedService": "{{serviceName}} service has been deleted and can no longer be opened"
}
},
"popup": {
Expand Down
3 changes: 2 additions & 1 deletion GUI/src/i18n/et/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,8 @@
"selectService": "Vali teenus...",
"noActiveServices": "Aktiivseid teenuseid pole saadaval",
"parameters": "Parameetrid",
"navigateToService": "Ava see teenus"
"navigateToService": "Ava see teenus",
"deletedService": "Teenus {{serviceName}} on kustutatud ja seda ei saa enam avada"
}
},
"popup": {
Expand Down
7 changes: 6 additions & 1 deletion GUI/src/pages/ServiceFlowPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const ServiceFlowPage: FC = () => {
if (!id) {
await Promise.all([
useServiceStore.getState().loadStepPreferences(),
useServiceStore.getState().loadNavigableServiceIds(),
useServiceStore.getState().loadAllEndpoints(
false,
1,
Expand All @@ -41,7 +42,11 @@ const ServiceFlowPage: FC = () => {
}

setLoading(true);
await Promise.all([useServiceStore.getState().loadService(id), useServiceStore.getState().loadStepPreferences()]);
await Promise.all([
useServiceStore.getState().loadService(id),
useServiceStore.getState().loadStepPreferences(),
useServiceStore.getState().loadNavigableServiceIds(),
]);
setLoading(false);
};

Expand Down
14 changes: 14 additions & 0 deletions GUI/src/store/new-services.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import i18next from 'i18next';
import {
getAllEndpoints,
getEndpointValidation,
getNavigableServicesList,
getSecretVariables,
getServiceById,
getTaraAuthResponseVariables,
Expand Down Expand Up @@ -94,6 +95,8 @@ export interface ServiceStoreState {
isYesNoQuestion: boolean;
stepPreferences: string[];
endpointsResponseVariables: EndpointResponseVariable[];
navigableServices: Map<string, string>;
loadNavigableServiceIds: () => Promise<void>;
setIsYesNoQuestion: (value: boolean) => void;
changeAssignNode: (assign: Assign[]) => void;
changeRulesNode: (rules: GroupOrRule[]) => void;
Expand Down Expand Up @@ -261,6 +264,7 @@ const useServiceStore = create<ServiceStoreState>((set, get) => ({
isYesNoQuestion: false,
stepPreferences: [],
endpointsResponseVariables: [],
navigableServices: new Map(),
history: [{ nodes: initialNodes, edges: initialEdges }],
historyIndex: 0,
setIsYesNoQuestion: (value: boolean) => set({ isYesNoQuestion: value }),
Expand Down Expand Up @@ -587,6 +591,16 @@ const useServiceStore = create<ServiceStoreState>((set, get) => ({
console.error('Failed to load step preferences:', error);
}
},
loadNavigableServiceIds: async () => {
try {
const response =
await api.get<{ readonly serviceId: string; readonly name: string }[]>(getNavigableServicesList());
const data = Array.isArray(response.data) ? response.data : [];
set({ navigableServices: new Map(data.map((s) => [s.serviceId, s.name])) });
} catch (error) {
console.error('Failed to load navigable services:', error);
}
},
loadSecretVariables: async () => {
const result = await api.get(getSecretVariables());
const data: { prod: string[]; test: string[] } = result.data;
Expand Down
Loading