mirror of
https://github.com/portainer/portainer.git
synced 2025-08-08 07:15:23 +02:00
refactor(ui): remove global providers [EE-4128] (#7578)
This commit is contained in:
parent
d3f094cb18
commit
fad376b415
46 changed files with 372 additions and 214 deletions
|
@ -6,7 +6,6 @@ import settingsModule from './settings';
|
|||
import featureFlagModule from './feature-flags';
|
||||
import userActivityModule from './user-activity';
|
||||
import servicesModule from './services';
|
||||
import homeModule from './home';
|
||||
import { reactModule } from './react';
|
||||
import { sidebarModule } from './react/views/sidebar';
|
||||
import environmentsModule from './environments';
|
||||
|
@ -29,7 +28,6 @@ async function initAuthentication(authManager, Authentication, $rootScope, $stat
|
|||
|
||||
angular
|
||||
.module('portainer.app', [
|
||||
homeModule,
|
||||
'portainer.oauth',
|
||||
'portainer.rbac',
|
||||
componentsModule,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { useRouter } from '@uirouter/react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
|
||||
import { PageHeader } from '@@/PageHeader';
|
||||
|
||||
import * as notifications from '../services/notifications';
|
||||
|
@ -73,8 +71,6 @@ export function HomeView() {
|
|||
}
|
||||
}
|
||||
|
||||
export const HomeViewAngular = r2a(HomeView, []);
|
||||
|
||||
async function confirmEndpointSnapshot() {
|
||||
return confirmAsync({
|
||||
title: buildTitle('Are you sure?'),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useQuery } from 'react-query';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { useUIState } from '@/portainer/hooks/UIStateProvider';
|
||||
import { useUIState } from '@/portainer/hooks/useUIState';
|
||||
|
||||
import { InformationPanel } from '@@/InformationPanel';
|
||||
|
||||
|
@ -10,9 +10,13 @@ import { getMotd } from './home.service';
|
|||
export function MotdPanel() {
|
||||
const motd = useMotd();
|
||||
|
||||
const [uiState, setUIState] = useUIState();
|
||||
const uiStateStore = useUIState();
|
||||
|
||||
if (!motd || motd.Message === '' || motd.Hash === uiState.dismissedInfoHash) {
|
||||
if (
|
||||
!motd ||
|
||||
motd.Message === '' ||
|
||||
motd.Hash === uiStateStore.dismissedInfoHash
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -34,10 +38,7 @@ export function MotdPanel() {
|
|||
);
|
||||
|
||||
function onDismiss(hash: string) {
|
||||
setUIState({
|
||||
...uiState,
|
||||
dismissedInfoHash: hash,
|
||||
});
|
||||
uiStateStore.dismissMotd(hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1 @@
|
|||
import angular from 'angular';
|
||||
|
||||
import { EnvironmentListAngular } from './EnvironmentList';
|
||||
import { HomeViewAngular } from './HomeView';
|
||||
|
||||
export default angular
|
||||
.module('portainer.app.home', [])
|
||||
.component('homeView', HomeViewAngular)
|
||||
.component('environmentList', EnvironmentListAngular).name;
|
||||
export { HomeView } from './HomeView';
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
import { createContext, PropsWithChildren, useContext } from 'react';
|
||||
|
||||
import { useLocalStorage } from '@/portainer/hooks/useLocalStorage';
|
||||
|
||||
interface UIState {
|
||||
dismissedInfoPanels: Record<string, string>;
|
||||
dismissedInfoHash: string;
|
||||
dismissedUpdateVersion: string;
|
||||
}
|
||||
|
||||
type UIStateService = [UIState, (state: UIState) => void];
|
||||
|
||||
const Context = createContext<null | UIStateService>(null);
|
||||
|
||||
export function useUIState() {
|
||||
const context = useContext(Context);
|
||||
|
||||
if (context == null) {
|
||||
throw new Error('Should be nested under a UIStateProvider component');
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
export function UIStateProvider({ children }: PropsWithChildren<unknown>) {
|
||||
const service = useLocalStorage<UIState>('UI_STATE', {} as UIState);
|
||||
|
||||
return <Context.Provider value={service}>{children}</Context.Provider>;
|
||||
}
|
37
app/portainer/hooks/useUIState.tsx
Normal file
37
app/portainer/hooks/useUIState.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import create from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
import { keyBuilder } from '@/portainer/hooks/useLocalStorage';
|
||||
|
||||
interface UIState {
|
||||
dismissedInfoPanels: Record<string, boolean>;
|
||||
dismissInfoPanel(id: string): void;
|
||||
|
||||
dismissedInfoHash: string;
|
||||
dismissMotd(hash: string): void;
|
||||
|
||||
dismissedUpdateVersion: string;
|
||||
dismissUpdateVersion(version: string): void;
|
||||
}
|
||||
|
||||
export const useUIState = create<UIState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
dismissedInfoPanels: {},
|
||||
dismissInfoPanel(id: string) {
|
||||
set((state) => ({
|
||||
dismissedInfoPanels: { ...state.dismissedInfoPanels, [id]: true },
|
||||
}));
|
||||
},
|
||||
dismissedInfoHash: '',
|
||||
dismissMotd(hash: string) {
|
||||
set({ dismissedInfoHash: hash });
|
||||
},
|
||||
dismissedUpdateVersion: '',
|
||||
dismissUpdateVersion(version: string) {
|
||||
set({ dismissedUpdateVersion: version });
|
||||
},
|
||||
}),
|
||||
{ name: keyBuilder('NEW_UI_STATE') }
|
||||
)
|
||||
);
|
|
@ -23,6 +23,7 @@ interface State {
|
|||
}
|
||||
|
||||
export const UserContext = createContext<State | null>(null);
|
||||
UserContext.displayName = 'UserContext';
|
||||
|
||||
export function useUser() {
|
||||
const context = useContext(UserContext);
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
import angular from 'angular';
|
||||
import { react2angular } from 'react2angular';
|
||||
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
import { CreateAccessToken } from '@/react/portainer/account/CreateAccessTokenView';
|
||||
import {
|
||||
DefaultRegistryAction,
|
||||
DefaultRegistryDomain,
|
||||
DefaultRegistryName,
|
||||
} from '@/react/portainer/registries/ListView/DefaultRegistry';
|
||||
import { Icon } from '@/react/components/Icon';
|
||||
import { ReactQueryDevtoolsWrapper } from '@/react/components/ReactQueryDevtoolsWrapper';
|
||||
import { AccessControlPanel } from '@/react/portainer/access-control';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
import { withI18nSuspense } from '@/react-tools/withI18nSuspense';
|
||||
|
||||
import { PageHeader } from '@@/PageHeader';
|
||||
import { TagSelector } from '@@/TagSelector';
|
||||
|
@ -26,22 +35,25 @@ export const componentsModule = angular
|
|||
.module('portainer.app.react.components', [customTemplatesModule])
|
||||
.component(
|
||||
'tagSelector',
|
||||
r2a(TagSelector, ['allowCreate', 'onChange', 'value'])
|
||||
r2a(withReactQuery(TagSelector), ['allowCreate', 'onChange', 'value'])
|
||||
)
|
||||
.component(
|
||||
'portainerTooltip',
|
||||
react2angular(Tooltip, ['message', 'position', 'className'])
|
||||
r2a(Tooltip, ['message', 'position', 'className'])
|
||||
)
|
||||
.component('fileUploadField', fileUploadField)
|
||||
.component('porSwitchField', switchField)
|
||||
.component(
|
||||
'passwordCheckHint',
|
||||
r2a(PasswordCheckHint, ['forceChangePassword', 'passwordValid'])
|
||||
r2a(withReactQuery(PasswordCheckHint), [
|
||||
'forceChangePassword',
|
||||
'passwordValid',
|
||||
])
|
||||
)
|
||||
.component('rdLoading', r2a(Loading, []))
|
||||
.component(
|
||||
'tableColumnHeader',
|
||||
react2angular(TableColumnHeaderAngular, [
|
||||
r2a(TableColumnHeaderAngular, [
|
||||
'colTitle',
|
||||
'canSort',
|
||||
'isSorted',
|
||||
|
@ -51,13 +63,13 @@ export const componentsModule = angular
|
|||
.component('viewLoading', r2a(ViewLoading, ['message']))
|
||||
.component(
|
||||
'pageHeader',
|
||||
r2a(PageHeader, [
|
||||
'id',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(PageHeader))), [
|
||||
'title',
|
||||
'breadcrumbs',
|
||||
'loading',
|
||||
'onReload',
|
||||
'reload',
|
||||
'id',
|
||||
])
|
||||
)
|
||||
.component(
|
||||
|
@ -75,7 +87,7 @@ export const componentsModule = angular
|
|||
)
|
||||
.component(
|
||||
'prIcon',
|
||||
react2angular(Icon, ['className', 'feather', 'icon', 'mode', 'size'])
|
||||
r2a(Icon, ['className', 'feather', 'icon', 'mode', 'size'])
|
||||
)
|
||||
.component('reactQueryDevTools', r2a(ReactQueryDevtoolsWrapper, []))
|
||||
.component(
|
||||
|
@ -86,13 +98,10 @@ export const componentsModule = angular
|
|||
'datatableSearchbar',
|
||||
r2a(SearchBar, ['data-cy', 'onChange', 'value', 'placeholder'])
|
||||
)
|
||||
.component(
|
||||
'boxSelectorBadgeIcon',
|
||||
react2angular(BadgeIcon, ['featherIcon', 'icon'])
|
||||
)
|
||||
.component('boxSelectorBadgeIcon', r2a(BadgeIcon, ['featherIcon', 'icon']))
|
||||
.component(
|
||||
'accessControlPanel',
|
||||
r2a(AccessControlPanel, [
|
||||
r2a(withReactQuery(withCurrentUser(AccessControlPanel)), [
|
||||
'disableOwnershipChange',
|
||||
'onUpdateSuccess',
|
||||
'resourceControl',
|
||||
|
@ -100,4 +109,23 @@ export const componentsModule = angular
|
|||
'resourceType',
|
||||
'environmentId',
|
||||
])
|
||||
)
|
||||
.component(
|
||||
'defaultRegistryName',
|
||||
r2a(withReactQuery(DefaultRegistryName), [])
|
||||
)
|
||||
.component(
|
||||
'defaultRegistryAction',
|
||||
r2a(withReactQuery(DefaultRegistryAction), [])
|
||||
)
|
||||
.component(
|
||||
'defaultRegistryDomain',
|
||||
r2a(withReactQuery(DefaultRegistryDomain), [])
|
||||
)
|
||||
.component(
|
||||
'createAccessToken',
|
||||
r2a(withI18nSuspense(withUIRouter(CreateAccessToken)), [
|
||||
'onSubmit',
|
||||
'onError',
|
||||
])
|
||||
).name;
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import angular from 'angular';
|
||||
|
||||
import { HomeView } from '@/portainer/home';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
import { CreateAccessToken } from '@/react/portainer/account/CreateAccessTokenView';
|
||||
import {
|
||||
DefaultRegistryAction,
|
||||
DefaultRegistryDomain,
|
||||
DefaultRegistryName,
|
||||
} from '@/react/portainer/registries/ListView/DefaultRegistry';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
|
||||
import { wizardModule } from './wizard';
|
||||
import { teamsModule } from './teams';
|
||||
|
@ -18,10 +16,7 @@ export const viewsModule = angular
|
|||
teamsModule,
|
||||
updateSchedulesModule,
|
||||
])
|
||||
.component('defaultRegistryName', r2a(DefaultRegistryName, []))
|
||||
.component('defaultRegistryAction', r2a(DefaultRegistryAction, []))
|
||||
.component('defaultRegistryDomain', r2a(DefaultRegistryDomain, []))
|
||||
.component(
|
||||
'createAccessToken',
|
||||
r2a(CreateAccessToken, ['onSubmit', 'onError'])
|
||||
'homeView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(HomeView))), [])
|
||||
).name;
|
||||
|
|
|
@ -3,8 +3,14 @@ import angular from 'angular';
|
|||
import { AngularSidebarService } from '@/react/sidebar/useSidebarState';
|
||||
import { Sidebar } from '@/react/sidebar/Sidebar';
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
|
||||
export const sidebarModule = angular
|
||||
.module('portainer.app.sidebar', [])
|
||||
.component('sidebar', r2a(Sidebar, []))
|
||||
.component(
|
||||
'sidebar',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(Sidebar))), [])
|
||||
)
|
||||
.factory('SidebarService', AngularSidebarService).name;
|
||||
|
|
|
@ -3,12 +3,21 @@ import { StateRegistry } from '@uirouter/angularjs';
|
|||
|
||||
import { ItemView, ListView } from '@/react/portainer/users/teams';
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
|
||||
export const teamsModule = angular
|
||||
.module('portainer.app.teams', [])
|
||||
.config(config)
|
||||
.component('teamView', r2a(ItemView, []))
|
||||
.component('teamsView', r2a(ListView, [])).name;
|
||||
.component(
|
||||
'teamView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(ItemView))), [])
|
||||
)
|
||||
.component(
|
||||
'teamsView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(ListView))), [])
|
||||
).name;
|
||||
|
||||
/* @ngInject */
|
||||
function config($stateRegistryProvider: StateRegistry) {
|
||||
|
|
|
@ -7,12 +7,24 @@ import {
|
|||
CreateView,
|
||||
ItemView,
|
||||
} from '@/react/portainer/environments/update-schedules';
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
|
||||
export const updateSchedulesModule = angular
|
||||
.module('portainer.edge.updateSchedules', [])
|
||||
.component('updateSchedulesListView', r2a(ListView, []))
|
||||
.component('updateSchedulesCreateView', r2a(CreateView, []))
|
||||
.component('updateSchedulesItemView', r2a(ItemView, []))
|
||||
.component(
|
||||
'updateSchedulesListView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(ListView))), [])
|
||||
)
|
||||
.component(
|
||||
'updateSchedulesCreateView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(CreateView))), [])
|
||||
)
|
||||
.component(
|
||||
'updateSchedulesItemView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(ItemView))), [])
|
||||
)
|
||||
.config(config).name;
|
||||
|
||||
function config($stateRegistryProvider: StateRegistry) {
|
||||
|
|
|
@ -7,15 +7,30 @@ import {
|
|||
EnvironmentTypeSelectView,
|
||||
HomeView,
|
||||
} from '@/react/portainer/environments/wizard';
|
||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
|
||||
export const wizardModule = angular
|
||||
.module('portainer.app.react.views.wizard', [])
|
||||
.component('wizardEnvironmentCreationView', r2a(EnvironmentCreationView, []))
|
||||
.component(
|
||||
'wizardEnvironmentCreationView',
|
||||
r2a(
|
||||
withUIRouter(withReactQuery(withCurrentUser(EnvironmentCreationView))),
|
||||
[]
|
||||
)
|
||||
)
|
||||
.component(
|
||||
'wizardEnvironmentTypeSelectView',
|
||||
r2a(EnvironmentTypeSelectView, [])
|
||||
r2a(
|
||||
withUIRouter(withReactQuery(withCurrentUser(EnvironmentTypeSelectView))),
|
||||
[]
|
||||
)
|
||||
)
|
||||
.component(
|
||||
'wizardMainView',
|
||||
r2a(withUIRouter(withReactQuery(withCurrentUser(HomeView))), [])
|
||||
)
|
||||
.component('wizardMainView', r2a(HomeView, []))
|
||||
.config(config).name;
|
||||
|
||||
function config($stateRegistryProvider: StateRegistry) {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||
import { r2a } from '@/react-tools/react2angular';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
|
||||
import { Settings } from '../types';
|
||||
|
||||
|
@ -20,7 +22,7 @@ export function EdgeComputeSettingsView({ settings, onSubmit }: Props) {
|
|||
);
|
||||
}
|
||||
|
||||
export const EdgeComputeSettingsViewAngular = r2a(EdgeComputeSettingsView, [
|
||||
'settings',
|
||||
'onSubmit',
|
||||
]);
|
||||
export const EdgeComputeSettingsViewAngular = r2a(
|
||||
withReactQuery(withCurrentUser(EdgeComputeSettingsView)),
|
||||
['settings', 'onSubmit']
|
||||
);
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import { react2angular } from '@/react-tools/react2angular';
|
||||
import { withReactQuery } from '@/react-tools/withReactQuery';
|
||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
|
||||
import { SettingsFDO } from './SettingsFDO';
|
||||
|
||||
const SettingsFDOAngular = react2angular(SettingsFDO, ['settings', 'onSubmit']);
|
||||
const SettingsFDOAngular = react2angular(
|
||||
withUIRouter(withReactQuery(SettingsFDO)),
|
||||
['settings', 'onSubmit']
|
||||
);
|
||||
export { SettingsFDO, SettingsFDOAngular };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue