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
33 changes: 6 additions & 27 deletions src/gitops/components/application/ApplicationDetailsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import Revision from '@gitops/Revision/Revision';
import HealthStatus from '@gitops/Statuses/HealthStatus';
import { OperationState } from '@gitops/Statuses/OperationState';
import SyncStatus from '@gitops/Statuses/SyncStatus';
import { ArgoServer, getArgoServer, getFriendlyClusterName } from '@gitops/utils/gitops';
import { useArgoServer } from '@gitops/hooks/useArgoServer';
import { getApplicationArgoUrl, getFriendlyClusterName } from '@gitops/utils/gitops';
import { labelControllerNamespaceKey } from '@gitops/utils/gitops';
import { useGitOpsTranslation } from '@gitops/utils/hooks/useGitOpsTranslation';
import { useObjectModifyPermissions } from '@gitops/utils/utils';
import { k8sUpdate, ResourceLink, useK8sModel } from '@openshift-console/dynamic-plugin-sdk';
import { k8sUpdate, ResourceLink } from '@openshift-console/dynamic-plugin-sdk';
import { Label as PfLabel, ToggleGroup, ToggleGroupItem } from '@patternfly/react-core';
import {
DescriptionList,
Expand Down Expand Up @@ -43,22 +44,10 @@ type ApplicationDetailsTabProps = RouteComponentProps<{

const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) => {
const { t } = useGitOpsTranslation();
const [model] = useK8sModel({ group: 'route.openshift.io', version: 'v1', kind: 'Route' });

const [canPatch, canUpdate] = useObjectModifyPermissions(obj, ApplicationModel);

const [argoServer, setArgoServer] = React.useState<ArgoServer>({ host: '', protocol: '' });
React.useEffect(() => {
(async () => {
getArgoServer(model, obj)
.then((server) => {
setArgoServer(server);
})
.catch((err) => {
console.error('Error:', err);
});
})();
}, [model, obj]);
const argoServer = useArgoServer(obj);
const argoUrl = getApplicationArgoUrl(argoServer, obj);
Comment on lines +49 to +50

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- files ---\n'
git ls-files 'src/gitops/components/application/*' 'src/gitops/hooks/*' | sed -n '1,200p'

printf '\n--- relevant symbols ---\n'
rg -n "useArgoServer|getApplicationArgoUrl|ArgoCDLink|View in Argo CD|useApplicationActionsProvider" src/gitops/components src/gitops/hooks -S

printf '\n--- ApplicationDetailsTab excerpt ---\n'
sed -n '1,220p' src/gitops/components/application/ApplicationDetailsTab.tsx

printf '\n--- ApplicationResourcesTab excerpt ---\n'
sed -n '1,220p' src/gitops/components/application/ApplicationResourcesTab.tsx

printf '\n--- ApplicationSourcesTab excerpt ---\n'
sed -n '1,220p' src/gitops/components/application/ApplicationSourcesTab.tsx

printf '\n--- useArgoServer / url helper excerpts ---\n'
rg -n "function useArgoServer|const useArgoServer|export .*useArgoServer|function getApplicationArgoUrl|const getApplicationArgoUrl|export .*getApplicationArgoUrl" src -S

Repository: redhat-developer/gitops-console-plugin

Length of output: 267


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- files ---'
git ls-files 'src/gitops/components/application/*' 'src/gitops/hooks/*' | sed -n '1,200p'

echo
echo '--- relevant symbols ---'
rg -n "useArgoServer|getApplicationArgoUrl|ArgoCDLink|View in Argo CD|useApplicationActionsProvider" src/gitops/components src/gitops/hooks -S

echo
echo '--- ApplicationDetailsTab excerpt ---'
sed -n '1,220p' src/gitops/components/application/ApplicationDetailsTab.tsx

echo
echo '--- ApplicationResourcesTab excerpt ---'
sed -n '1,220p' src/gitops/components/application/ApplicationResourcesTab.tsx

echo
echo '--- ApplicationSourcesTab excerpt ---'
sed -n '1,220p' src/gitops/components/application/ApplicationSourcesTab.tsx

echo
echo '--- useArgoServer / url helper excerpts ---'
rg -n "function useArgoServer|const useArgoServer|export .*useArgoServer|function getApplicationArgoUrl|const getApplicationArgoUrl|export .*getApplicationArgoUrl" src -S

Repository: redhat-developer/gitops-console-plugin

Length of output: 30790


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- useArgoServer.ts ---'
cat -n src/gitops/hooks/useArgoServer.ts

echo
echo '--- utils/gitops.ts around getApplicationArgoUrl ---'
sed -n '80,150p' src/gitops/utils/gitops.ts | cat -n

echo
echo '--- ArgoCDLink.tsx ---'
cat -n src/gitops/components/shared/ArgoCDLink/ArgoCDLink.tsx

echo
echo '--- ApplicationDetailsTab around the link ---'
sed -n '120,150p' src/gitops/components/application/ApplicationDetailsTab.tsx | cat -n

echo
echo '--- ApplicationResourcesTab around the link ---'
sed -n '105,125p' src/gitops/components/application/ApplicationResourcesTab.tsx | cat -n

echo
echo '--- ApplicationSourcesTab around the link ---'
sed -n '190,215p' src/gitops/components/application/ApplicationSourcesTab.tsx | cat -n

Repository: redhat-developer/gitops-console-plugin

Length of output: 8354


Hide Argo CD links until the URL is ready

  • ApplicationDetailsTab.tsx and ApplicationResourcesTab.tsx pass '' to ArgoCDLink while useArgoServer is still resolving.
  • ApplicationSourcesTab.tsx turns that same state into a query-only relative link (?resource=...).

Gate these links on the final argoUrl before rendering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/gitops/components/application/ApplicationDetailsTab.tsx` around lines 49
- 50, Gate the Argo CD link rendering in ApplicationDetailsTab so it only
appears once the final argoUrl is available instead of passing an empty or
partial URL to ArgoCDLink. Update the logic around useArgoServer and
getApplicationArgoUrl to conditionally render the link only when argoUrl is
ready, and apply the same pattern in the related ApplicationResourcesTab and
ApplicationSourcesTab link paths so no query-only relative links are shown while
the server is still resolving.


const onChangeAutomated = (event: React.MouseEvent<any> | React.KeyboardEvent | MouseEvent) => {
const id = event.currentTarget.id;
Expand Down Expand Up @@ -144,17 +133,7 @@ const ApplicationDetailsTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
model={ApplicationModel}
nameLink={
<>
<ArgoCDLink
href={
argoServer.protocol +
'://' +
argoServer.host +
'/applications/' +
obj?.metadata?.namespace +
'/' +
obj?.metadata?.name
}
/>
<ArgoCDLink href={argoUrl} />
</>
}
/>
Expand Down
6 changes: 5 additions & 1 deletion src/gitops/components/application/ApplicationNavPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as React from 'react';

import { useApplicationActionsProvider } from '@gitops/hooks/useApplicationActionsProvider';
import { useArgoServer } from '@gitops/hooks/useArgoServer';
import { ApplicationKind, ApplicationModel } from '@gitops/models/ApplicationModel';
import { getApplicationArgoUrl } from '@gitops/utils/gitops';
import { useGitOpsTranslation } from '@gitops/utils/hooks/useGitOpsTranslation';
import { HorizontalNav, useK8sWatchResource } from '@openshift-console/dynamic-plugin-sdk';
import { Bullseye, Spinner } from '@patternfly/react-core';
Expand Down Expand Up @@ -35,7 +37,9 @@ const ApplicationNavPage: React.FC<ApplicationPageProps> = ({ name, namespace, k
namespace,
});

const [actions] = useApplicationActionsProvider(application);
const argoServer = useArgoServer(application);
const argoUrl = getApplicationArgoUrl(argoServer, application);
const [actions] = useApplicationActionsProvider(application, argoUrl);

const pages = React.useMemo(
() => [
Expand Down
45 changes: 6 additions & 39 deletions src/gitops/components/application/ApplicationResourcesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { RouteComponentProps } from 'react-router';
import classNames from 'classnames';

import { useResourceActionsProvider } from '@gitops/hooks/useResourceActionsProvider';
import { useArgoServer } from '@gitops/hooks/useArgoServer';
import HealthStatus from '@gitops/Statuses/HealthStatus';
import SyncStatus from '@gitops/Statuses/SyncStatus';
import ActionDropDown from '@gitops/utils/components/ActionDropDown/ActionDropDown';
Expand All @@ -15,7 +16,6 @@ import {
ResourceLink,
RowFilter,
RowFilterItem,
useK8sModel,
useListPageFilter,
} from '@openshift-console/dynamic-plugin-sdk';
import {
Expand All @@ -33,7 +33,7 @@ import { DataViewTh, DataViewTr } from '@patternfly/react-data-view/dist/esm/Dat
import { CubesIcon } from '@patternfly/react-icons';
import { Tbody, Td, Tr } from '@patternfly/react-table';

import { ArgoServer, getArgoServer } from '../../utils/gitops';
import { getApplicationArgoUrl } from '../../utils/gitops';
import ArgoCDLink from '../shared/ArgoCDLink/ArgoCDLink';
import { GitOpsDataViewTable, useGitOpsDataViewSort } from '../shared/DataView';

Expand All @@ -47,21 +47,8 @@ type ApplicationResourcesTabProps = RouteComponentProps<{
};

const ApplicationResourcesTab: React.FC<ApplicationResourcesTabProps> = ({ obj }) => {
const [model] = useK8sModel({ group: 'route.openshift.io', version: 'v1', kind: 'Route' });

const [argoServer, setArgoServer] = React.useState<ArgoServer>({ host: '', protocol: '' });

React.useEffect(() => {
(async () => {
getArgoServer(model, obj)
.then((server) => {
setArgoServer(server);
})
.catch((err) => {
console.error('Error:', err);
});
})();
}, [model, obj]);
const argoServer = useArgoServer(obj);
const argoUrl = getApplicationArgoUrl(argoServer, obj);
Comment on lines +50 to +51

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether useResourceActionsProvider conditionally handles an empty argoBaseURL
# similar to useApplicationActionsProvider's href-truthy check.
fd -e ts -e tsx useResourceActionsProvider
rg -n -A 20 'useResourceActionsProvider' --type=tsx --type=ts

Repository: redhat-developer/gitops-console-plugin

Length of output: 252


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== outline: ApplicationResourcesTab =="
ast-grep outline src/gitops/components/application/ApplicationResourcesTab.tsx --view expanded || true

echo
echo "== outline: useResourceActionsProvider =="
ast-grep outline src/gitops/hooks/useResourceActionsProvider.tsx --view expanded || true

echo
echo "== outline: useApplicationActionsProvider =="
fd -a useApplicationActionsProvider src/gitops/hooks src/gitops/components || true
if [ -f src/gitops/hooks/useApplicationActionsProvider.tsx ]; then
  ast-grep outline src/gitops/hooks/useApplicationActionsProvider.tsx --view expanded || true
fi

echo
echo "== relevant matches =="
rg -n -A 30 -B 10 'useResourceActionsProvider|useApplicationActionsProvider|argoBaseURL|argoUrl|View in Argo CD' src/gitops/components/application/ApplicationResourcesTab.tsx src/gitops/hooks/useResourceActionsProvider.tsx src/gitops/hooks/useApplicationActionsProvider.tsx || true

Repository: redhat-developer/gitops-console-plugin

Length of output: 38061


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== useResourceActionsProvider =="
cat -n src/gitops/hooks/useResourceActionsProvider.tsx | sed -n '1,260p'

echo
echo "== useApplicationActionsProvider =="
fd -a useApplicationActionsProvider src/gitops/hooks src/gitops/components || true
if [ -f src/gitops/hooks/useApplicationActionsProvider.tsx ]; then
  cat -n src/gitops/hooks/useApplicationActionsProvider.tsx | sed -n '1,260p'
fi

echo
echo "== ApplicationResourcesTab around the caller =="
cat -n src/gitops/components/application/ApplicationResourcesTab.tsx | sed -n '280,340p'

Repository: redhat-developer/gitops-console-plugin

Length of output: 13126


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,260p' src/gitops/hooks/useResourceActionsProvider.tsx | cat -n
printf '\n---\n'
sed -n '1,260p' src/gitops/hooks/useApplicationActionsProvider.tsx | cat -n
printf '\n---\n'
sed -n '280,340p' src/gitops/components/application/ApplicationResourcesTab.tsx | cat -n

Repository: redhat-developer/gitops-console-plugin

Length of output: 12947


Guard the resource-level Argo CD action on argoBaseURL The kebab action still always renders and calls window.open(getResourceURL(argoBaseURL, resource), '_blank'), so it can still open a broken/empty Argo CD URL when the server URL isn’t ready. Hide or disable this action until the URL exists, like the application action does.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/gitops/components/application/ApplicationResourcesTab.tsx` around lines
50 - 51, Guard the resource-level Argo CD action in ApplicationResourcesTab so
it only renders or becomes enabled when argoBaseURL/argoUrl is available,
matching the application-level action behavior. Update the kebab action path
that calls window.open(getResourceURL(argoBaseURL, resource), '_blank') to check
for a valid server URL first, and hide or disable the action until
useArgoServer(obj) and getApplicationArgoUrl(...) have produced a usable URL.


let resources: ApplicationResourceStatus[];
if (obj?.status?.resources) {
Expand Down Expand Up @@ -91,17 +78,7 @@ const ApplicationResourcesTab: React.FC<ApplicationResourcesTabProps> = ({ obj }
const memoizedFilteredResources = React.useMemo(() => [...filteredData], [filteredData]);
const isEmptyResources = memoizedFilteredResources.length === 0;

const rows = useResourceRowsDV(
memoizedFilteredResources,
obj,
argoServer.protocol +
'://' +
argoServer.host +
'/applications/' +
obj?.metadata?.namespace +
'/' +
obj?.metadata?.name,
);
const rows = useResourceRowsDV(memoizedFilteredResources, obj, argoUrl);

const empty = (
<Tbody>
Expand Down Expand Up @@ -135,17 +112,7 @@ const ApplicationResourcesTab: React.FC<ApplicationResourcesTabProps> = ({ obj }
<PageBody>
<Flex style={{ marginTop: '15px' }} flex={{ default: 'flexDefault' }}>
<FlexItem>
<ArgoCDLink
href={
argoServer.protocol +
'://' +
argoServer.host +
'/applications/' +
obj?.metadata?.namespace +
'/' +
obj?.metadata?.name
}
/>
<ArgoCDLink href={argoUrl} />
</FlexItem>
</Flex>
<>
Expand Down
28 changes: 4 additions & 24 deletions src/gitops/components/application/ApplicationSourcesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import ExternalLink from '@gitops/utils/components/ExternalLink/ExternalLink';
import { GitIcon } from '@gitops/utils/components/Icons/GitIcon';
import { HelmIcon } from '@gitops/utils/components/Icons/HelmIcon';
import { OciIcon } from '@gitops/utils/components/Icons/OciIcon';
import { ArgoServer, getArgoServer } from '@gitops/utils/gitops';
import { useArgoServer } from '@gitops/hooks/useArgoServer';
import { ArgoServer, getApplicationArgoUrl } from '@gitops/utils/gitops';
import { t } from '@gitops/utils/hooks/useGitOpsTranslation';
import { repoUrl, revisionUrl } from '@gitops/utils/urls';
import { useK8sModel } from '@openshift-console/dynamic-plugin-sdk';
import {
EmptyState,
EmptyStateBody,
Expand Down Expand Up @@ -199,13 +199,7 @@ export const SourceList: React.FC<SourceListProps> = ({ sources, obj, argoServer
<>
<ArgoCDLink
href={
argoServer.protocol +
'://' +
argoServer.host +
'/applications/' +
obj?.metadata?.namespace +
'/' +
obj?.metadata?.name +
getApplicationArgoUrl(argoServer, obj) +
'?resource=&node=argoproj.io%2FApplication%2F' +
obj?.metadata?.namespace +
'%2F' +
Expand All @@ -225,7 +219,7 @@ export const SourceList: React.FC<SourceListProps> = ({ sources, obj, argoServer
};

const ApplicationSourcesTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) => {
const [model] = useK8sModel({ group: 'route.openshift.io', version: 'v1', kind: 'Route' });
const argoServer = useArgoServer(obj);

let sources: ApplicationSource[];
if (obj?.spec?.source) {
Expand All @@ -237,20 +231,6 @@ const ApplicationSourcesTab: React.FC<ApplicationDetailsTabProps> = ({ obj }) =>
sources = [];
}

const [argoServer, setArgoServer] = React.useState<ArgoServer>({ host: '', protocol: '' });

React.useEffect(() => {
(async () => {
getArgoServer(model, obj)
.then((server) => {
setArgoServer(server);
})
.catch((err) => {
console.error('Error:', err);
});
})();
}, [model, obj]);

return (
<div>
<PageSection
Expand Down
33 changes: 5 additions & 28 deletions src/gitops/components/application/ApplicationSyncStatusTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { useResourceActionsProvider } from '@gitops/hooks/useResourceActionsProv
import { OperationState } from '@gitops/Statuses/OperationState';
import SyncStatus from '@gitops/Statuses/SyncStatus';
import ActionDropDown from '@gitops/utils/components/ActionDropDown/ActionDropDown';
import { ArgoServer, getArgoServer, getDuration } from '@gitops/utils/gitops';
import { useArgoServer } from '@gitops/hooks/useArgoServer';
import { getApplicationArgoUrl, getDuration } from '@gitops/utils/gitops';
import { t } from '@gitops/utils/hooks/useGitOpsTranslation';
import { ApplicationKind, ApplicationResourceStatus } from '@gitops-models/ApplicationModel';
import {
Action,
K8sGroupVersionKind,
ResourceLink,
Timestamp,
useK8sModel,
} from '@openshift-console/dynamic-plugin-sdk';
import {
DescriptionList,
Expand Down Expand Up @@ -49,21 +49,8 @@ type ApplicationSyncStatusTabProps = RouteComponentProps<{
};

const ApplicationSyncStatusTab: React.FC<ApplicationSyncStatusTabProps> = ({ obj }) => {
const [model] = useK8sModel({ group: 'route.openshift.io', version: 'v1', kind: 'Route' });

const [argoServer, setArgoServer] = React.useState<ArgoServer>({ host: '', protocol: '' });

React.useEffect(() => {
(async () => {
getArgoServer(model, obj)
.then((server) => {
setArgoServer(server);
})
.catch((err) => {
console.error('Error:', err);
});
})();
}, [model, obj]);
const argoServer = useArgoServer(obj);
const argoUrl = getApplicationArgoUrl(argoServer, obj);

let resources: ApplicationResourceStatus[];
if (obj?.status?.operationState?.syncResult?.resources) {
Expand All @@ -83,17 +70,7 @@ const ApplicationSyncStatusTab: React.FC<ApplicationSyncStatusTabProps> = ({ obj
return sortData(resources, sortBy, direction);
}, [resources, sortBy, direction]);

const rows = useResourceRowsDV(
sortedResources,
obj,
argoServer.protocol +
'://' +
argoServer.host +
'/applications/' +
obj?.metadata?.namespace +
'/' +
obj?.metadata?.name,
);
const rows = useResourceRowsDV(sortedResources, obj, argoUrl);

const empty = (
<Tbody>
Expand Down
29 changes: 6 additions & 23 deletions src/gitops/components/application/History/History.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { useTranslation } from 'react-i18next';
import ArgoCDLink from '@gitops/components/shared/ArgoCDLink/ArgoCDLink';
import Revision from '@gitops/Revision/Revision';
import ExternalLink from '@gitops/utils/components/ExternalLink/ExternalLink';
import { ArgoServer, getArgoServer } from '@gitops/utils/gitops';
import { useArgoServer } from '@gitops/hooks/useArgoServer';
import { getApplicationArgoUrl } from '@gitops/utils/gitops';
import { repoUrl } from '@gitops/utils/urls';
import { ApplicationHistory, ApplicationKind } from '@gitops-models/ApplicationModel';
import { Timestamp, useK8sModel } from '@openshift-console/dynamic-plugin-sdk';
import { Timestamp } from '@openshift-console/dynamic-plugin-sdk';
import { EmptyState, EmptyStateBody } from '@patternfly/react-core';
import { DataViewTh, DataViewTr } from '@patternfly/react-data-view/dist/esm/DataViewTable';
import { CubesIcon } from '@patternfly/react-icons';
Expand Down Expand Up @@ -38,20 +39,8 @@ const HistoryList: React.FC<HistoryListProps> = ({ history, obj }) => {

const rows = useRowsDV(sortedHistory, obj);

const [model] = useK8sModel({ group: 'route.openshift.io', version: 'v1', kind: 'Route' });
const [argoServer, setArgoServer] = React.useState<ArgoServer>({ host: '', protocol: '' });

React.useEffect(() => {
(async () => {
getArgoServer(model, obj)
.then((server) => {
setArgoServer(server);
})
.catch((err) => {
console.error('Error:', err);
});
})();
}, [model, obj]);
const argoServer = useArgoServer(obj);
const argoUrl = getApplicationArgoUrl(argoServer, obj);

const empty = (
<Tbody>
Expand All @@ -71,13 +60,7 @@ const HistoryList: React.FC<HistoryListProps> = ({ history, obj }) => {
<div>
<ArgoCDLink
href={
argoServer.protocol +
'://' +
argoServer.host +
'/applications/' +
obj?.metadata?.namespace +
'/' +
obj?.metadata?.name +
argoUrl +
'?resource=&node=argoproj.io%2FApplication%2F' +
obj?.metadata?.namespace +
'%2F' +
Expand Down
Loading
Loading