mirror of https://github.com/portainer/portainer
refactor(app): migrate the yaml inspector to react [EE-5356] (#10058)
Co-authored-by: testa113 <testa113>pull/10077/head
parent
23295d2736
commit
0f6607e703
|
@ -1,34 +0,0 @@
|
|||
<div>
|
||||
<web-editor-form
|
||||
identifier="application-details-yaml"
|
||||
value="$ctrl.data"
|
||||
yml="true"
|
||||
placeholder="Define or paste the content of your manifest here"
|
||||
read-only="true"
|
||||
hide-title="true"
|
||||
height="{{ $ctrl.expanded ? '800px' : '500px' }}"
|
||||
>
|
||||
</web-editor-form>
|
||||
<div class="py-5">
|
||||
<span class="btn btn-light btn-sm" ng-click="$ctrl.copyYAML()">
|
||||
<pr-icon class="vertical-center" icon="'copy'"></pr-icon>
|
||||
Copy to clipboard
|
||||
</span>
|
||||
<span class="btn btn-light btn-sm space-left !ml-0" ng-click="$ctrl.toggleYAMLInspectorExpansion()">
|
||||
<pr-icon class="vertical-center" icon="'minus'" size="'sm'" ng-if="$ctrl.expanded"></pr-icon>
|
||||
<pr-icon class="vertical-center" icon="'plus'" size="'sm'" ng-if="!$ctrl.expanded"></pr-icon>
|
||||
{{ $ctrl.expanded ? 'Collapse' : 'Expand' }}
|
||||
</span>
|
||||
<span id="copyNotificationYAML" style="display: none" class="small vertical-center ml-1">
|
||||
<pr-icon class="vertical-center" icon="'check'" size="'md'" mode="'success'"></pr-icon> copied
|
||||
</span>
|
||||
|
||||
<be-teaser-button
|
||||
class="float-right"
|
||||
feature-id="$ctrl.limitedFeature"
|
||||
message="'Applies any changes that you make in the YAML editor by calling the Kubernetes API to patch the relevant resources. Any resource removals or unexpected resource additions that you make in the YAML will be ignored. Note that editing is disabled for resources in namespaces marked as system.'"
|
||||
heading="'Apply YAML changes'"
|
||||
button-text="'Apply changes'"
|
||||
></be-teaser-button>
|
||||
</div>
|
||||
</div>
|
|
@ -1,8 +0,0 @@
|
|||
angular.module('portainer.kubernetes').component('kubernetesYamlInspector', {
|
||||
templateUrl: './yamlInspector.html',
|
||||
controller: 'KubernetesYamlInspectorController',
|
||||
bindings: {
|
||||
key: '@',
|
||||
data: '<',
|
||||
},
|
||||
});
|
|
@ -1,46 +0,0 @@
|
|||
import angular from 'angular';
|
||||
import YAML from 'yaml';
|
||||
import { FeatureId } from '@/react/portainer/feature-flags/enums';
|
||||
|
||||
class KubernetesYamlInspectorController {
|
||||
/* @ngInject */
|
||||
|
||||
constructor(clipboard) {
|
||||
this.clipboard = clipboard;
|
||||
this.expanded = false;
|
||||
}
|
||||
|
||||
cleanYamlUnwantedFields(yml) {
|
||||
try {
|
||||
const ymls = yml.split('---');
|
||||
const cleanYmls = ymls.map((yml) => {
|
||||
const y = YAML.parse(yml);
|
||||
if (y.metadata) {
|
||||
delete y.metadata.managedFields;
|
||||
delete y.metadata.resourceVersion;
|
||||
}
|
||||
return YAML.stringify(y);
|
||||
});
|
||||
return cleanYmls.join('---\n');
|
||||
} catch (e) {
|
||||
return yml;
|
||||
}
|
||||
}
|
||||
|
||||
copyYAML() {
|
||||
this.clipboard.copyText(this.data);
|
||||
$('#copyNotificationYAML').show().fadeOut(2500);
|
||||
}
|
||||
|
||||
toggleYAMLInspectorExpansion() {
|
||||
this.expanded = !this.expanded;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.data = this.cleanYamlUnwantedFields(this.data);
|
||||
this.limitedFeature = FeatureId.K8S_EDIT_YAML;
|
||||
}
|
||||
}
|
||||
|
||||
export default KubernetesYamlInspectorController;
|
||||
angular.module('portainer.kubernetes').controller('KubernetesYamlInspectorController', KubernetesYamlInspectorController);
|
|
@ -21,6 +21,7 @@ import { ApplicationContainersDatatable } from '@/react/kubernetes/applications/
|
|||
import { withFormValidation } from '@/react-tools/withFormValidation';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { PlacementsDatatable } from '@/react/kubernetes/applications/ItemView/PlacementsDatatable';
|
||||
import { YAMLInspector } from '@/react/kubernetes/components/YAMLInspector';
|
||||
|
||||
export const ngModule = angular
|
||||
.module('portainer.kubernetes.react.components', [])
|
||||
|
@ -96,6 +97,13 @@ export const ngModule = angular
|
|||
'supportGlobalDeployment',
|
||||
])
|
||||
)
|
||||
.component(
|
||||
'kubeYamlInspector',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(YAMLInspector))), [
|
||||
'identifier',
|
||||
'data',
|
||||
])
|
||||
)
|
||||
.component(
|
||||
'applicationSummaryWidget',
|
||||
r2a(
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<uib-tab index="3" ng-if="ctrl.application.Yaml" select="ctrl.showEditor()" classes="btn-sm">
|
||||
<uib-tab-heading> <pr-icon icon="'code'"></pr-icon> YAML </uib-tab-heading>
|
||||
<div class="px-5" ng-if="ctrl.state.showEditorTab">
|
||||
<kubernetes-yaml-inspector key="application-yaml" data="ctrl.application.Yaml"></kubernetes-yaml-inspector>
|
||||
<kube-yaml-inspector identifier="'application-yaml'" data="ctrl.application.Yaml" />
|
||||
</div>
|
||||
</uib-tab>
|
||||
</uib-tabset>
|
||||
|
|
|
@ -247,7 +247,7 @@
|
|||
<div class="flex-center gap-1"> <pr-icon icon="'code'" size="'sm'"></pr-icon> YAML </div>
|
||||
</uib-tab-heading>
|
||||
<div style="padding-right: 25px" ng-if="ctrl.state.showEditorTab">
|
||||
<kubernetes-yaml-inspector key="node-yaml" data="ctrl.node.Yaml"> </kubernetes-yaml-inspector>
|
||||
<kube-yaml-inspector identifier="'node-yaml'" data="ctrl.node.Yaml" />
|
||||
</div>
|
||||
</uib-tab>
|
||||
</uib-tabset>
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
YAML
|
||||
</uib-tab-heading>
|
||||
<div class="px-5 !pt-5" ng-if="ctrl.state.showEditorTab">
|
||||
<kubernetes-yaml-inspector key="configuration-yaml" data="ctrl.configuration.Yaml"></kubernetes-yaml-inspector>
|
||||
<kube-yaml-inspector identifier="'configuration-yaml'" data="ctrl.configuration.Yaml" />
|
||||
</div>
|
||||
</uib-tab>
|
||||
</uib-tabset>
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
YAML
|
||||
</uib-tab-heading>
|
||||
<div class="px-5 !pt-5" ng-if="ctrl.state.showEditorTab">
|
||||
<kubernetes-yaml-inspector key="configuration-yaml" data="ctrl.configuration.Yaml"></kubernetes-yaml-inspector>
|
||||
<kube-yaml-inspector identifier="'secret-yaml'" data="ctrl.configuration.Yaml" />
|
||||
</div>
|
||||
</uib-tab>
|
||||
</uib-tabset>
|
||||
|
|
|
@ -305,7 +305,7 @@
|
|||
<uib-tab index="2" ng-if="ctrl.pool.Yaml" select="ctrl.showEditor()" classes="btn-sm">
|
||||
<uib-tab-heading class="vertical-center"><pr-icon icon="'code'"></pr-icon> YAML </uib-tab-heading>
|
||||
<div class="px-5" ng-if="ctrl.state.showEditorTab">
|
||||
<kubernetes-yaml-inspector key="resource-pool-yaml" data="ctrl.pool.Yaml"></kubernetes-yaml-inspector>
|
||||
<kube-yaml-inspector identifier="'namespace-yaml'" data="ctrl.pool.Yaml" />
|
||||
</div>
|
||||
</uib-tab>
|
||||
</uib-tabset>
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<uib-tab index="2" ng-if="ctrl.volume.PersistentVolumeClaim.Yaml" select="ctrl.showEditor()" classes="btn-sm">
|
||||
<uib-tab-heading class="vertical-center" data-cy="k8sVolDetail-volYamlTab"> <pr-icon icon="'code'"></pr-icon> YAML </uib-tab-heading>
|
||||
<div class="px-5" ng-if="ctrl.state.showEditorTab">
|
||||
<kubernetes-yaml-inspector key="volume-yaml" data="ctrl.volume.PersistentVolumeClaim.Yaml"></kubernetes-yaml-inspector>
|
||||
<kube-yaml-inspector identifier="'volume-yaml'" data="ctrl.volume.PersistentVolumeClaim.Yaml" />
|
||||
</div>
|
||||
</uib-tab>
|
||||
</uib-tabset>
|
||||
|
|
|
@ -84,23 +84,19 @@ export function CodeEditor({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-2 flex flex-col">
|
||||
<div className="flex">
|
||||
<div className="flex-1">
|
||||
{!!placeholder && <TextTip color="blue">{placeholder}</TextTip>}
|
||||
</div>
|
||||
|
||||
<div className="ml-auto">
|
||||
<CopyButton
|
||||
copyText={value}
|
||||
color="none"
|
||||
className="!text-sm !font-medium text-blue-9 hover:!text-blue-11 th-highcontrast:text-blue-7 hover:th-highcontrast:!text-blue-6 th-dark:text-blue-7 hover:th-dark:!text-blue-6"
|
||||
indicatorPosition="left"
|
||||
>
|
||||
Copy to clipboard
|
||||
</CopyButton>
|
||||
</div>
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<div className="flex flex-1 items-center">
|
||||
{!!placeholder && <TextTip color="blue">{placeholder}</TextTip>}
|
||||
</div>
|
||||
|
||||
<CopyButton
|
||||
copyText={value}
|
||||
color="link"
|
||||
className="!pr-0 !text-sm !font-medium hover:no-underline focus:no-underline"
|
||||
indicatorPosition="left"
|
||||
>
|
||||
Copy to clipboard
|
||||
</CopyButton>
|
||||
</div>
|
||||
<CodeMirror
|
||||
className={styles.root}
|
||||
|
|
|
@ -56,6 +56,7 @@ interface Props {
|
|||
readonly?: boolean;
|
||||
hideTitle?: boolean;
|
||||
error?: string;
|
||||
height?: string;
|
||||
}
|
||||
|
||||
export function WebEditorForm({
|
||||
|
@ -68,6 +69,7 @@ export function WebEditorForm({
|
|||
yaml,
|
||||
children,
|
||||
error,
|
||||
height,
|
||||
}: PropsWithChildren<Props>) {
|
||||
return (
|
||||
<div>
|
||||
|
@ -98,6 +100,7 @@ export function WebEditorForm({
|
|||
yaml={yaml}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
height={height}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -82,12 +82,12 @@ export function ApplicationServicesTable({
|
|||
)}
|
||||
<td data-cy="k8sAppDetail-containerPort">
|
||||
{service.spec?.ports?.map((port) => (
|
||||
<div key={port.port}>{port.targetPort}</div>
|
||||
<div key={port.name}>{port.targetPort}</div>
|
||||
))}
|
||||
</td>
|
||||
<td>
|
||||
{service.spec?.ports?.map((port) => (
|
||||
<div key={port.port}>
|
||||
<div key={port.name}>
|
||||
{environment?.PublicURL && port.nodePort && (
|
||||
<a
|
||||
className="vertical-center hyperlink"
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import { useMemo, useState } from 'react';
|
||||
import YAML from 'yaml';
|
||||
import { Minus, Plus } from 'lucide-react';
|
||||
|
||||
import { FeatureId } from '@/react/portainer/feature-flags/enums';
|
||||
|
||||
import { WebEditorForm } from '@@/WebEditorForm';
|
||||
import { Button } from '@@/buttons';
|
||||
import { BETeaserButton } from '@@/BETeaserButton';
|
||||
|
||||
type Props = {
|
||||
identifier: string;
|
||||
data: string;
|
||||
};
|
||||
|
||||
export function YAMLInspector({ identifier, data }: Props) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const yaml = useMemo(() => cleanYamlUnwantedFields(data), [data]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<WebEditorForm
|
||||
value={yaml}
|
||||
placeholder="Define or paste the content of your manifest here"
|
||||
readonly
|
||||
hideTitle
|
||||
id={identifier}
|
||||
yaml
|
||||
height={expanded ? '800px' : '500px'}
|
||||
onChange={() => {}} // all kube yaml inspectors in CE are read only
|
||||
/>
|
||||
<div className="flex items-center justify-between py-5">
|
||||
<Button
|
||||
icon={expanded ? Minus : Plus}
|
||||
color="default"
|
||||
className="!ml-0"
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
>
|
||||
{expanded ? 'Collapse' : 'Expand'}
|
||||
</Button>
|
||||
<BETeaserButton
|
||||
featureId={FeatureId.K8S_EDIT_YAML}
|
||||
heading="Apply YAML changes"
|
||||
message="Applies any changes that you make in the YAML editor by calling the Kubernetes API to patch the relevant resources. Any resource removals or unexpected resource additions that you make in the YAML will be ignored. Note that editing is disabled for resources in namespaces marked as system."
|
||||
buttonText="Apply changes"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function cleanYamlUnwantedFields(yml: string) {
|
||||
try {
|
||||
const ymls = yml.split('---');
|
||||
const cleanYmls = ymls.map((yml) => {
|
||||
const y = YAML.parse(yml);
|
||||
if (y.metadata) {
|
||||
const { managedFields, resourceVersion, ...metadata } = y.metadata;
|
||||
y.metadata = metadata;
|
||||
}
|
||||
return YAML.stringify(y);
|
||||
});
|
||||
return cleanYmls.join('---\n');
|
||||
} catch (e) {
|
||||
return yml;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue