Web console
Web console OpenShift Dedicated 4 Getting started with web console in Red Hat OpenShift Dedicated Red Hat OpenShift Documentation Team
conster Header: React.FC = () => { const { t } = useTranslation('plugin__console-demo-plugin'); return <h1>{t('Hello, World!')}</h1>; }; conster Header: React.FC = () => { const { t } = useTranslation('plugin__console-demo-plugin'); return <h1>{t('Hello, World!')}</h1>; }; spec: backend: service: basePath: / name: console-demo-plugin namespace: console-demo-plugin port: 9001 type: Service displayName: OpenShift Console Demo Plugin i18n: loadType: Preload 1 { "type": "console.navigation/section", "properties": { "id": "admin-demo-section", "perspective": "admin", "name": "%plugin__console-plugin-template~Plugin Template%" } } // t('plugin__console-demo-plugin~Demo Plugin') yarn i18n yarn install yarn run start oc login yarn run start-console podman machine ssh sudo -i rpm-ostree install qemu-user-static systemctl reboot docker build -t quay.io/my-repositroy/my-plugin:latest . docker run -it --rm -d -p 9001:80 quay.io/my-repository/my-plugin:latest docker push quay.io/my-repository/my-plugin:latest helm upgrade -i my-plugin charts/openshift-console-plugin -n my-plugin-namespace --create-namespace --set plugin.image=my-plugin-image-location plugin: name: "" description: "" image: "" imagePullPolicy: IfNotPresent replicas: 2 port: 9443 securityContext: enabled: true podSecurityContext: enabled: true runAsNonRoot: true seccompProfile: type: RuntimeDefault containerSecurityContext: enabled: true allowPrivilegeEscalation: false capabilities: drop: - ALL resources: requests: cpu: 10m memory: 50Mi basePath: / certificateSecretName: "" serviceAccount: create: true annotations: {} name: "" patcherServiceAccount: create: true annotations: {} name: "" jobs: patchConsoles: enabled: true image: "registry.redhat.io/openshift4/ose-tools-rhel8@sha256:e44074f21e0cca6464e50cb6ff934747e0bd11162ea01d522433a1a1ae116103" podSecurityContext: enabled: true runAsNonRoot: true seccompProfile: type: RuntimeDefault containerSecurityContext: enabled: true allowPrivilegeEscalation: false capabilities: drop: - ALL resources: requests: cpu: 10m memory: 50Mi apiVersion: console.openshift.io/v1 kind: ConsolePlugin metadata: name:<plugin-name> spec: proxy: - alias: helm-charts 1 authorization: UserToken 2 caCertificate: '-----BEGIN CERTIFICATE-----\nMIID....'en 3 endpoint: 4 service: name: <service-name> namespace: <service-namespace> port: <service-port> type: Service "consolePlugin": { "name": "my-plugin", 1 "version": "0.0.1", 2 "displayName": "My Plugin", 3 "description": "Enjoy this shiny, new console plugin!", 4 "exposedModules": { "ExamplePage": "./components/ExamplePage" }, "dependencies": { "@console/pluginAPI": "/*" } } { "type": "console.tab/horizontalNav", "properties": { "page": { "name": "Example Tab", "href": "example" }, "model": { "group": "core", "version": "v1", "kind": "Pod" }, "component": { "USDcodeRef": "ExampleTab" } } } "exposedModules": { "ExamplePage": "./components/ExamplePage", "ExampleTab": "./components/ExampleTab" } import * as React from 'react'; export default function ExampleTab() { return ( <p>This is a custom tab added to a resource using a dynamic plugin.</p> ); } helm upgrade -i my-plugin charts/openshift-console-plugin -n my-plugin-namespace --create-namespace --set plugin.image=my-plugin-image-location const Component: React.FC = (props) => { const [activePerspective, setActivePerspective] = useActivePerspective(); return <select value={activePerspective} onChange={(e) => setActivePerspective(e.target.value)} > { // ...perspective options } </select> } <GreenCheckCircleIcon title="Healthy" /> <RedExclamationCircleIcon title="Failed" /> <YellowExclamationTriangleIcon title="Warning" /> <BlueInfoCircleIcon title="Info" /> <ErrorStatus title={errorMsg} /> <InfoStatus title={infoMsg} /> <ProgressStatus title={progressMsg} /> <SuccessStatus title={successMsg} /> const [navItemExtensions, navItemsResolved] = useResolvedExtensions<NavItem>(isNavItem); // process adapted extensions and render your component const HomePage: React.FC = (props) => { const page = { href: '/home', name: 'Home', component: () => <>Home</> } return <HorizontalNav match={props.match} pages={[page]} /> } const MachineList: React.FC<MachineListProps> = (props) => { return ( <VirtualizedTable<MachineKind> {...props} aria-label='Machines' columns={getMachineColumns} Row={getMachineTableRow} /> ); } const PodRow: React.FC<RowProps<K8sResourceCommon>> = ({ obj, activeColumnIDs }) => { return ( <> <TableData id={columns[0].id} activeColumnIDs={activeColumnIDs}> <ResourceLink kind="Pod" name={obj.metadata.name} namespace={obj.metadata.namespace} /> </TableData> <TableData id={columns[1].id} activeColumnIDs={activeColumnIDs}> <ResourceLink kind="Namespace" name={obj.metadata.namespace} /> </TableData> </> ); }; // See implementation for more details on TableColumn type const [activeColumns, userSettingsLoaded] = useActiveColumns({ columns, showNamespaceOverride: false, columnManagementID, }); return userSettingsAreLoaded ? <VirtualizedTable columns={activeColumns} {...otherProps} /> : null const exampleList: React.FC = () => { return ( <> <ListPageHeader title="Example List Page"/> </> ); }; const exampleList: React.FC<MyProps> = () => { return ( <> <ListPageHeader title="Example Pod List Page"/> <ListPageCreate groupVersionKind="Pod">Create Pod</ListPageCreate> </ListPageHeader> </> ); }; const exampleList: React.FC<MyProps> = () => { return ( <> <ListPageHeader title="Example Pod List Page"/> <ListPageCreateLink to={'/link/to/my/page'}>Create Item</ListPageCreateLink> </ListPageHeader> </> ); }; const exampleList: React.FC<MyProps> = () => { return ( <> <ListPageHeader title="Example Pod List Page"/> <ListPageCreateButton createAccessReview={access}>Create Pod</ListPageCreateButton> </ListPageHeader> </> ); }; const exampleList: React.FC<MyProps> = () => { const items = { SAVE: 'Save', DELETE: 'Delete', } return ( <> <ListPageHeader title="Example Pod List Page"/> <ListPageCreateDropdown createAccessReview={access} items={items}>Actions</ListPageCreateDropdown> </ListPageHeader> </> ); }; // See implementation for more details on RowFilter and FilterValue types const [staticData, filteredData, onFilterChange] = useListPageFilter( data, rowFilters, staticFilters, ); // ListPageFilter updates filter state based on user interaction and resulting filtered data can be rendered in an independent component. return ( <> <ListPageHeader .../> <ListPagBody> <ListPageFilter data={staticData} onFilterChange={onFilterChange} /> <List data={filteredData} /> </ListPageBody> </> ) // See implementation for more details on RowFilter and FilterValue types const [staticData, filteredData, onFilterChange] = useListPageFilter( data, rowFilters, staticFilters, ); // ListPageFilter updates filter state based on user interaction and resulting filtered data can be rendered in an independent component. return ( <> <ListPageHeader .../> <ListPagBody> <ListPageFilter data={staticData} onFilterChange={onFilterChange} /> <List data={filteredData} /> </ListPageBody> </> ) <ResourceLink kind="Pod" name="testPod" title={metadata.uid} /> <ResourceIcon kind="Pod"/> const Component: React.FC = () => { const [model, inFlight] = useK8sModel({ group: 'app'; version: 'v1'; kind: 'Deployment' }); return } const Component: React.FC = () => { const [models, inFlight] = UseK8sModels(); return } const Component: React.FC = () => { const watchRes = { } const [data, loaded, error] = useK8sWatchResource(watchRes) return } const Component: React.FC = () => { const watchResources = { 'deployment': {...}, 'pod': {...} } const {deployment, pod} = useK8sWatchResources(watchResources) return } <StatusPopupSection firstColumn={ <> <span>{title}</span> <span className="text-secondary"> My Example Item </span> </> } secondColumn='Status' > <StatusPopupSection firstColumn='Example' secondColumn='Status' > <StatusPopupItem icon={healthStateMapping[MCGMetrics.state]?.icon}> Complete </StatusPopupItem> <StatusPopupItem icon={healthStateMapping[RGWMetrics.state]?.icon}> Pending </StatusPopupItem> </StatusPopupSection> <Overview> <OverviewGrid mainCards={mainCards} leftCards={leftCards} rightCards={rightCards} /> </Overview> <Overview> <OverviewGrid mainCards={mainCards} leftCards={leftCards} rightCards={rightCards} /> </Overview> return ( <InventoryItem> <InventoryItemTitle>{title}</InventoryItemTitle> <InventoryItemBody error={loadError}> {loaded && <InventoryItemStatus count={workerNodes.length} icon={<MonitoringIcon />} />} </InventoryItemBody> </InventoryItem> ) return ( <InventoryItem> <InventoryItemTitle>{title}</InventoryItemTitle> <InventoryItemBody error={loadError}> {loaded && <InventoryItemStatus count={workerNodes.length} icon={<MonitoringIcon />} />} </InventoryItemBody> </InventoryItem> ) return ( <InventoryItem> <InventoryItemTitle>{title}</InventoryItemTitle> <InventoryItemBody error={loadError}> {loaded && <InventoryItemStatus count={workerNodes.length} icon={<MonitoringIcon />} />} </InventoryItemBody> </InventoryItem> ) return ( <InventoryItem> <InventoryItemTitle>{title}</InventoryItemTitle> <InventoryItemBody error={loadError}> {loaded && <InventoryItemStatus count={workerNodes.length} icon={<MonitoringIcon />} />} </InventoryItemBody> </InventoryItem> ) if (loadError) { title = <Link to={workerNodesLink}>{t('Worker Nodes')}</Link>; } else if (!loaded) { title = <><InventoryItemLoading /><Link to={workerNodesLink}>{t('Worker Nodes')}</Link></>; } return ( <InventoryItem> <InventoryItemTitle>{title}</InventoryItemTitle> </InventoryItem> ) <React.Suspense fallback={<LoadingBox />}> <CodeEditor value={code} language="yaml" /> </React.Suspense> <React.Suspense fallback={<LoadingBox />}> <ResourceYAMLEditor initialResource={resource} header="Create resource" onSave={(content) => updateResource(content)} /> </React.Suspense> const [resource, loaded, loadError] = useK8sWatchResource(clusterResource); return <ResourceEventStream resource={resource} /> const context: AppPage: React.FC = () => {<br/> const [launchModal] = useModal();<br/> const onClick = () => launchModal(ModalComponent);<br/> return (<br/> <Button onClick={onClick}>Launch a Modal</Button><br/> )<br/>}<br/>` const context: ActionContext = { 'a-context-id': { dataFromDynamicPlugin } }; <ActionServiceProvider context={context}> {({ actions, options, loaded }) => loaded && ( <ActionMenu actions={actions} options={options} variant={ActionMenuVariant.DROPDOWN} /> ) } </ActionServiceProvider> const logNamespaceChange = (namespace) => console.log(`New namespace: USD{namespace}`); <NamespaceBar onNamespaceChange={logNamespaceChange}> <NamespaceBarApplicationSelector /> </NamespaceBar> <Page> //in ErrorBoundary component return ( if (this.state.hasError) { return <ErrorBoundaryFallbackPage errorMessage={errorString} componentStack={componentStackString} stack={stackTraceString} title={errorString}/>; } return this.props.children; ) <QueryBrowser defaultTimespan={15 * 60 * 1000} namespace={namespace} pollInterval={30 * 1000} queries={[ 'process_resident_memory_bytes{job="console"}', 'sum(irate(container_network_receive_bytes_total[6h:5m])) by (pod)', ]} /> const PodAnnotationsButton = ({ pod }) => { const { t } = useTranslation(); const launchAnnotationsModal = useAnnotationsModal<PodKind>(pod); return <button onClick={launchAnnotationsModal}>{t('Edit Pod Annotations')}</button> } const DeletePodButton = ({ pod }) => { const { t } = useTranslation(); const launchDeleteModal = useDeleteModal<PodKind>(pod); return <button onClick={launchDeleteModal}>{t('Delete Pod')}</button> } const PodLabelsButton = ({ pod }) => { const { t } = useTranslation(); const launchLabelsModal = useLabelsModal<PodKind>(pod); return <button onClick={launchLabelsModal}>{t('Edit Pod Labels')}</button> } const Component: React.FC = (props) => { const [activeNamespace, setActiveNamespace] = useActiveNamespace(); return <select value={activeNamespace} onChange={(e) => setActiveNamespace(e.target.value)} > { // ...namespace options } </select> } const Component: React.FC = (props) => { const [state, setState, loaded] = useUserSettings( 'devconsole.addPage.showDetails', true, true, ); return loaded ? ( <WrappedComponent {...props} userSettingState={state} setUserSettingState={setState} /> ) : null; }; const OpenQuickStartButton = ({ quickStartId }) => { const { setActiveQuickStart } = useQuickStartContext(); const onClick = React.useCallback(() => { setActiveQuickStart(quickStartId); }, [quickStartId]); return <button onClick={onClick}>{t('Open Quick Start')}</button> }; <React.Suspense fallback={<LoadingBox />}> <YAMLEditor value={code} /> </React.Suspense> oc get console.operator.openshift.io cluster -o jsonpath='{.spec.plugins}' apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-from-openshift-console spec: ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: openshift-console podSelector: {} policyTypes: - Ingress apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-from-openshift-operators spec: ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: openshift-operators podSelector: {} policyTypes: - Ingress oc delete devworkspaces.workspace.devfile.io --all-namespaces --all --wait oc delete devworkspaceroutings.controller.devfile.io --all-namespaces --all --wait oc delete all --selector app.kubernetes.io/part-of=devworkspace-operator,app.kubernetes.io/name=devworkspace-webhook-server -n openshift-operators oc delete serviceaccounts devworkspace-webhook-server -n openshift-operators oc delete clusterrole devworkspace-webhook-server oc delete clusterrolebinding devworkspace-webhook-server