diff --git a/public/locales/en.json b/public/locales/en.json index c14845ba..bf51c33f 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -371,7 +371,8 @@ "update": "Update" }, "yaml": { - "YAML": "File" + "YAML": "File", + "showOnlyImportant": "Show only important fields" }, "createMCP": { "dialogTitle": "Create Managed Control Plane", diff --git a/src/components/Graphs/Graph.tsx b/src/components/Graphs/Graph.tsx index f4974b54..dd816508 100644 --- a/src/components/Graphs/Graph.tsx +++ b/src/components/Graphs/Graph.tsx @@ -10,7 +10,7 @@ import { Legend, LegendItem } from './Legend'; import { YamlViewDialog } from '../Yaml/YamlViewDialog'; import YamlViewer from '../Yaml/YamlViewer'; import { stringify } from 'yaml'; -import { removeManagedFieldsProperty } from '../../utils/removeManagedFieldsProperty'; +import { removeManagedFieldsAndFilterData, Resource } from '../../utils/removeManagedFieldsAndFilterData.ts'; import { useTranslation } from 'react-i18next'; import { useGraph } from './useGraph'; import { ManagedResourceItem } from '../../lib/shared/types'; @@ -44,7 +44,12 @@ const Graph: React.FC = () => { const { nodes, edges, colorMap, loading, error } = useGraph(colorBy, handleYamlClick); const yamlString = useMemo( - () => (yamlResource ? stringify(removeManagedFieldsProperty(yamlResource)) : ''), + () => (yamlResource ? stringify(removeManagedFieldsAndFilterData(yamlResource as unknown as Resource, true)) : ''), + [yamlResource], + ); + + const yamlStringToCopy = useMemo( + () => (yamlResource ? stringify(removeManagedFieldsAndFilterData(yamlResource as unknown as Resource, false)) : ''), [yamlResource], ); @@ -134,7 +139,9 @@ const Graph: React.FC = () => { } + dialogContent={ + + } /> ); diff --git a/src/components/Yaml/YamlLoader.tsx b/src/components/Yaml/YamlLoader.tsx index 553c2b6b..5e9934c7 100644 --- a/src/components/Yaml/YamlLoader.tsx +++ b/src/components/Yaml/YamlLoader.tsx @@ -1,5 +1,5 @@ import { YamlViewButtonProps } from './YamlViewButtonWithLoader.tsx'; -import { FC } from 'react'; +import { FC, useMemo } from 'react'; import { stringify } from 'yaml'; @@ -9,15 +9,35 @@ import Loading from '../Shared/Loading.tsx'; import IllustratedError from '../Shared/IllustratedError.tsx'; import YamlViewer from './YamlViewer.tsx'; import { useApiResource } from '../../lib/api/useApiResource'; -import { removeManagedFieldsProperty, Resource } from '../../utils/removeManagedFieldsProperty.ts'; +import { removeManagedFieldsAndFilterData, Resource } from '../../utils/removeManagedFieldsAndFilterData.ts'; -export const YamlLoader: FC = ({ workspaceName, resourceType, resourceName }) => { +interface YamlLoaderProps extends YamlViewButtonProps { + showOnlyImportantData?: boolean; + setShowOnlyImportantData?: (showOnlyImportantData: boolean) => void; +} + +export const YamlLoader: FC = ({ + workspaceName, + resourceType, + resourceName, + showOnlyImportantData = false, + setShowOnlyImportantData, +}) => { const { isLoading, data, error } = useApiResource( ResourceObject(workspaceName ?? '', resourceType, resourceName), undefined, true, ); const { t } = useTranslation(); + const yamlString = useMemo(() => { + if (isLoading || error) return ''; + return stringify(removeManagedFieldsAndFilterData(data as Resource, showOnlyImportantData)); + }, [data, error, isLoading, showOnlyImportantData]); + + const yamlStringToCopy = useMemo(() => { + if (isLoading || error) return ''; + return stringify(removeManagedFieldsAndFilterData(data as Resource, false)); + }, [data, error, isLoading]); if (isLoading) return ; if (error) { return ; @@ -25,8 +45,11 @@ export const YamlLoader: FC = ({ workspaceName, resourceTyp return ( ); }; diff --git a/src/components/Yaml/YamlViewButton.tsx b/src/components/Yaml/YamlViewButton.tsx index 2e6b7d78..4f1aef0a 100644 --- a/src/components/Yaml/YamlViewButton.tsx +++ b/src/components/Yaml/YamlViewButton.tsx @@ -4,7 +4,7 @@ import styles from './YamlViewer.module.css'; import { useTranslation } from 'react-i18next'; import YamlViewer from './YamlViewer.tsx'; import { stringify } from 'yaml'; -import { removeManagedFieldsProperty, Resource } from '../../utils/removeManagedFieldsProperty.ts'; +import { removeManagedFieldsAndFilterData, Resource } from '../../utils/removeManagedFieldsAndFilterData.ts'; import { YamlIcon } from './YamlIcon.tsx'; import { YamlViewDialog } from './YamlViewDialog.tsx'; @@ -13,12 +13,16 @@ export type YamlViewButtonProps = { }; export const YamlViewButton: FC = ({ resourceObject }) => { + const [showOnlyImportantData, setShowOnlyImportantData] = useState(true); const [isOpen, setIsOpen] = useState(false); const { t } = useTranslation(); const resource = resourceObject as Resource; const yamlString = useMemo(() => { - return stringify(removeManagedFieldsProperty(resource)); + return stringify(removeManagedFieldsAndFilterData(resource, showOnlyImportantData)); + }, [resource, showOnlyImportantData]); + const yamlStringToCopy = useMemo(() => { + return stringify(removeManagedFieldsAndFilterData(resource, false)); }, [resource]); return ( @@ -27,10 +31,15 @@ export const YamlViewButton: FC = ({ resourceObject }) => { setIsOpen={setIsOpen} dialogContent={ } + setShowOnlyImportantData={setShowOnlyImportantData} + showOnlyImportantData={showOnlyImportantData} /> } diff --git a/src/components/Yaml/YamlViewer.tsx b/src/components/Yaml/YamlViewer.tsx index 090dc85d..e48dab60 100644 --- a/src/components/Yaml/YamlViewer.tsx +++ b/src/components/Yaml/YamlViewer.tsx @@ -7,8 +7,18 @@ import styles from './YamlViewer.module.css'; import { useCopyToClipboard } from '../../hooks/useCopyToClipboard.ts'; import { useTranslation } from 'react-i18next'; import { useTheme } from '../../hooks/useTheme.ts'; -type YamlViewerProps = { yamlString: string; filename: string }; -const YamlViewer: FC = ({ yamlString, filename }) => { +type YamlViewerProps = { + yamlString: string; + yamlStringToCopy: string; + filename: string; + showOnlyImportantData?: boolean; + setShowOnlyImportantData?: (showOnlyImportantData: boolean) => void; +}; + +// Download button is hidden now due to stakeholder request +const SHOW_DOWNLOAD_BUTTON = false; + +const YamlViewer: FC = ({ yamlString, filename, yamlStringToCopy }) => { const { t } = useTranslation(); const { isDarkTheme } = useTheme(); const { copyToClipboard } = useCopyToClipboard(); @@ -27,12 +37,14 @@ const YamlViewer: FC = ({ yamlString, filename }) => { return (
- - + {SHOW_DOWNLOAD_BUTTON && ( + + )} []; + metadata: { + name: string; + namespace?: string; + labels?: Record; + annotations?: { + [LAST_APPLIED_CONFIGURATION_ANNOTATION]?: string; + [key: string]: string | undefined; + }; + managedFields?: unknown; + creationTimestamp?: string; + finalizers?: string[]; + generation?: number; + resourceVersion?: string; + uid?: string; + }; + spec?: unknown; + status?: unknown; +}; + +const cleanUpResource = ( + resource: Omit, + showOnlyImportantData: boolean, +): Omit => { + const newResource = { ...resource }; + + if (newResource.metadata) { + newResource.metadata = { ...newResource.metadata }; + delete newResource.metadata.managedFields; + + if (showOnlyImportantData) { + if (newResource.metadata.annotations) { + newResource.metadata.annotations = { ...newResource.metadata.annotations }; + delete newResource.metadata.annotations[LAST_APPLIED_CONFIGURATION_ANNOTATION]; + } + delete newResource.metadata.generation; + delete newResource.metadata.uid; + } + } + + return newResource; +}; + +export const removeManagedFieldsAndFilterData = ( + resourceObject: Resource, + showOnlyImportantData: boolean, +): Resource => { + if (!resourceObject) { + return {} as Resource; + } + if (resourceObject.items) { + return { + ...cleanUpResource(resourceObject, showOnlyImportantData), + items: resourceObject.items.map((item) => cleanUpResource(item, showOnlyImportantData)), + }; + } + + return cleanUpResource(resourceObject, showOnlyImportantData); +}; diff --git a/src/utils/removeManagedFieldsProperty.ts b/src/utils/removeManagedFieldsProperty.ts deleted file mode 100644 index 2706ead3..00000000 --- a/src/utils/removeManagedFieldsProperty.ts +++ /dev/null @@ -1,36 +0,0 @@ -export type Resource = { - kind: string; - items?: { - metadata: { - name: string; - managedFields?: unknown; - }; - }[]; - metadata: { - name: string; - managedFields?: unknown; - }; -}; - -export const removeManagedFieldsProperty = (resourceObject: Resource) => { - if (resourceObject?.metadata?.managedFields) { - return { - ...resourceObject, - metadata: { - ...resourceObject.metadata, - managedFields: undefined, - }, - }; - } - if (resourceObject?.items) { - return { - ...resourceObject, - items: resourceObject.items.map((item) => ({ - ...item, - metadata: { ...item.metadata, managedFields: undefined }, - })), - }; - } - - return resourceObject; -};