diff --git a/app/docker/containers/components/ContainersDatatable/ContainersDatatable.tsx b/app/docker/containers/components/ContainersDatatable/ContainersDatatable.tsx index d4183e21b..fd8e0bd1e 100644 --- a/app/docker/containers/components/ContainersDatatable/ContainersDatatable.tsx +++ b/app/docker/containers/components/ContainersDatatable/ContainersDatatable.tsx @@ -50,9 +50,10 @@ import { useColumns } from './columns'; export interface ContainerTableProps { isAddActionVisible: boolean; dataset: DockerContainer[]; - onRefresh(): Promise; + onRefresh?(): Promise; isHostColumnVisible: boolean; autoFocusSearch: boolean; + tableKey?: string; } export function ContainersDatatable({ @@ -150,7 +151,7 @@ export function ContainersDatatable({ } > - + diff --git a/app/docker/containers/components/ContainersDatatable/ContainersDatatableContainer.tsx b/app/docker/containers/components/ContainersDatatable/ContainersDatatableContainer.tsx index 58dc99d7d..866daadc4 100644 --- a/app/docker/containers/components/ContainersDatatable/ContainersDatatableContainer.tsx +++ b/app/docker/containers/components/ContainersDatatable/ContainersDatatableContainer.tsx @@ -13,7 +13,11 @@ interface Props extends ContainerTableProps { endpoint: Environment; } -export function ContainersDatatableContainer({ endpoint, ...props }: Props) { +export function ContainersDatatableContainer({ + endpoint, + tableKey = 'containers', + ...props +}: Props) { const defaultSettings = { autoRefreshRate: 0, truncateContainerName: 32, @@ -25,8 +29,8 @@ export function ContainersDatatableContainer({ endpoint, ...props }: Props) { return ( - - + + {/* eslint-disable-next-line react/jsx-props-no-spreading */} @@ -40,13 +44,10 @@ export const ContainersDatatableAngular = react2angular( [ 'endpoint', 'isAddActionVisible', - 'containerService', - 'httpRequestHelper', - 'notifications', - 'modalService', 'dataset', 'onRefresh', 'isHostColumnVisible', 'autoFocusSearch', + 'tableKey', ] ); diff --git a/app/docker/containers/components/ContainersDatatable/ContainersDatatableSettings.tsx b/app/docker/containers/components/ContainersDatatable/ContainersDatatableSettings.tsx index 174c790b3..0062390ee 100644 --- a/app/docker/containers/components/ContainersDatatable/ContainersDatatableSettings.tsx +++ b/app/docker/containers/components/ContainersDatatable/ContainersDatatableSettings.tsx @@ -3,10 +3,13 @@ import { useTableSettings } from '@/portainer/components/datatables/components/u import { Checkbox } from '@/portainer/components/form-components/Checkbox'; import type { ContainersTableSettings } from '@/docker/containers/types'; -export function ContainersDatatableSettings() { - const { settings, setTableSettings } = useTableSettings< - ContainersTableSettings - >(); +interface Props { + isRefreshVisible: boolean; +} + +export function ContainersDatatableSettings({ isRefreshVisible }: Props) { + const { settings, setTableSettings } = + useTableSettings(); return ( <> @@ -22,10 +25,12 @@ export function ContainersDatatableSettings() { } /> - + {isRefreshVisible && ( + + )} ); diff --git a/app/portainer/components/datatables/components/SearchBar.tsx b/app/portainer/components/datatables/components/SearchBar.tsx index 2c4f200f6..6550f125f 100644 --- a/app/portainer/components/datatables/components/SearchBar.tsx +++ b/app/portainer/components/datatables/components/SearchBar.tsx @@ -30,20 +30,22 @@ const SearchBarContext = createContext< interface SearchBarProviderProps { defaultValue?: string; + storageKey: string; } export function SearchBarProvider({ children, + storageKey, defaultValue = '', }: PropsWithChildren) { - const [value, setValue] = useLocalStorage( - 'datatable_text_filter_containers', + const state = useLocalStorage( + `datatable_text_filter_${storageKey}`, defaultValue, sessionStorage ); return ( - + {children} ); diff --git a/app/portainer/components/datatables/components/useRepeater.ts b/app/portainer/components/datatables/components/useRepeater.ts index 02c3a99ea..f2fb7d8d6 100644 --- a/app/portainer/components/datatables/components/useRepeater.ts +++ b/app/portainer/components/datatables/components/useRepeater.ts @@ -2,7 +2,7 @@ import { useEffect, useCallback, useState } from 'react'; export function useRepeater( refreshRate: number, - onRefresh: () => Promise + onRefresh?: () => Promise ) { const [intervalId, setIntervalId] = useState(null); @@ -17,7 +17,7 @@ export function useRepeater( const startRepeater = useCallback( (refreshRate) => { - if (intervalId) { + if (intervalId || !onRefresh) { return; } @@ -27,16 +27,16 @@ export function useRepeater( }, refreshRate * 1000) ); }, - [intervalId] + [intervalId, onRefresh] ); useEffect(() => { - if (!refreshRate) { + if (!refreshRate || !onRefresh) { stopRepeater(); } else { startRepeater(refreshRate); } return stopRepeater; - }, [refreshRate, startRepeater, stopRepeater, intervalId]); + }, [refreshRate, startRepeater, stopRepeater, intervalId, onRefresh]); } diff --git a/app/portainer/rest/stack.js b/app/portainer/rest/stack.js index bf8dc29b6..9410caf85 100644 --- a/app/portainer/rest/stack.js +++ b/app/portainer/rest/stack.js @@ -5,7 +5,7 @@ angular.module('portainer.app').factory('Stack', StackFactory); /* @ngInject */ function StackFactory($resource, API_ENDPOINT_STACKS) { return $resource( - API_ENDPOINT_STACKS + '/:id/:action', + API_ENDPOINT_STACKS + '/:id/:action/:subaction', {}, { get: { method: 'GET', params: { id: '@id' } }, diff --git a/app/portainer/views/stacks/edit/stack.html b/app/portainer/views/stacks/edit/stack.html index c599d32ae..985b1f083 100644 --- a/app/portainer/views/stacks/edit/stack.html +++ b/app/portainer/views/stacks/edit/stack.html @@ -15,16 +15,14 @@ Stack -
+
-
- Information -
+
Information

- + This stack was created outside of Portainer. Control over this stack is limited. This stack is orphaned. You can reassociate it with the current environment using the "Associate to this environment" feature.

@@ -34,9 +32,7 @@
-
- Stack details -
+
Stack details
{{ stackName }} @@ -81,12 +77,8 @@
-
- Associate to this environment -
-

- This feature allows you to reassociate this stack to the current environment. -

+
Associate to this environment
+

This feature allows you to reassociate this stack to the current environment.

@@ -97,13 +89,13 @@ ng-disabled="state.actionInProgress" ng-click="associateStack()" button-spinner="state.actionInProgress" - style="margin-left: -5px;" + style="margin-left: -5px" > - + Associate Association in progress... - {{ state.formValidationError }} + {{ state.formValidationError }}
@@ -128,12 +120,12 @@ Editor -
+
- + This stack will be deployed using the equivalent of docker-compose. Only Compose file format version 2 is supported at the moment. - + This stack will be deployed using docker-compose. @@ -163,24 +155,20 @@
-
- Options -
+
Options
- +
-
- Actions -
+
Actions
diff --git a/package.json b/package.json index df605bb74..d0aafc7a6 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "format": "prettier --loglevel warn --write \"**/*.{js,css,html,jsx,tsx,ts}\"", "lint": "yarn lint:client; yarn lint:server", "lint:server": "cd api && golangci-lint run -E exportloopref", - "lint:client": "eslint --cache --fix ./**/*.{js,jsx,ts,tsx}", + "lint:client": "eslint --cache --fix './**/*.{js,jsx,ts,tsx}'", "lint:pr": "make lint-pr", "test": "yarn test:client; yarn test:server", "test:server": "cd api && go test ./...",