Features/15 add azure app configuration (#16)
* Adding app config module * adding app context * adding app context and feature flag hooks --------- Co-authored-by: Noah Spannbauer <nspannbauer@sensonix.com>
This commit was merged in pull request #16.
This commit is contained in:
2
api/.gitignore
vendored
2
api/.gitignore
vendored
@@ -54,3 +54,5 @@ pids
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
local.settings.json
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"IsEncrypted": false,
|
||||
"Values": {
|
||||
"AzureWebJobsStorage": "",
|
||||
"FUNCTIONS_WORKER_RUNTIME": "node"
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@noahspan/noahspan-modules": "^0.1.2",
|
||||
"@schematics/angular": "^17.3.7",
|
||||
"dotenv": "^16.4.5",
|
||||
"reflect-metadata": "0.1.13",
|
||||
|
||||
@@ -1,12 +1,34 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { Controller, Get, Query } from '@nestjs/common';
|
||||
import { AppService } from './app.service';
|
||||
import { AppConfigService, AuthService } from '@noahspan/noahspan-modules';
|
||||
import { FeatureFlagValue } from '@azure/app-configuration';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
constructor(
|
||||
private readonly appConfigService: AppConfigService,
|
||||
private readonly authService: AuthService
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
getHello(): string {
|
||||
return this.appService.getHello();
|
||||
@Get('featureFlags')
|
||||
async getFeatureFlags(@Query() query: any): Promise<FeatureFlagValue[]> {
|
||||
try {
|
||||
const token: string = await this.authService.getToken(
|
||||
'client_credentials',
|
||||
process.env.CLIENT_ID,
|
||||
process.env.CLIENT_SECRET,
|
||||
'https://azconfig.io'
|
||||
);
|
||||
const featureFlags: FeatureFlagValue[] =
|
||||
await this.appConfigService.getFeatureFlags(
|
||||
token,
|
||||
`${query.key}`,
|
||||
query.label
|
||||
);
|
||||
|
||||
return featureFlags;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { AppConfigModule, AuthModule } from '@noahspan/noahspan-modules';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
imports: [
|
||||
AppConfigModule.register({
|
||||
url: process.env.APP_CONFIG_URL
|
||||
}),
|
||||
AuthModule.register({
|
||||
tenantId: process.env.TENANT_ID
|
||||
})
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService]
|
||||
})
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"@azure/msal-react": "^2.0.15",
|
||||
"@nextui-org/react": "^2.3.6",
|
||||
"axios": "^1.7.2",
|
||||
"framer-motion": "^11.1.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -1,16 +1,40 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import Flights from './components/flights/Flights';
|
||||
import Logbook from './components/logbook/Logbook';
|
||||
import Checklists from './components/checklists/Checklists';
|
||||
import Pilots from './components/pilots/Pilots';
|
||||
import { useAppContext } from './hooks/appContext/UseAppContext';
|
||||
import axios, { AxiosResponse } from 'axios';
|
||||
import { useFeatureFlag } from './hooks/featureFlag/UseFeatureFlag';
|
||||
|
||||
const App: React.FC<unknown> = () => {
|
||||
const appContext = useAppContext();
|
||||
|
||||
useEffect(() => {
|
||||
const getFeatureFlags = async () => {
|
||||
try {
|
||||
const response: AxiosResponse = await axios.get(
|
||||
`http://localhost:7071/api/featureFlags?key=flying*&label=${process.env.NODE_ENV}`
|
||||
);
|
||||
const featureFlags: unknown[] = response.data;
|
||||
|
||||
if (featureFlags.length > 0) {
|
||||
appContext.dispatch({
|
||||
type: 'SET_FEATURE_FLAGS',
|
||||
payload: featureFlags
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
getFeatureFlags();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<Flights />} />
|
||||
<Route path="logbook" element={<Logbook />} />
|
||||
<Route path="checklists" element={<Checklists />} />
|
||||
<Route path="pilots" element={<Pilots />} />
|
||||
{useFeatureFlag('flying-pilots')?.enabled && (
|
||||
<Route path="/" element={<Pilots />} />
|
||||
)}
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from '@nextui-org/react';
|
||||
import { Link as ReactRouterLink } from 'react-router-dom';
|
||||
import { useIsAuthenticated, useMsal } from '@azure/msal-react';
|
||||
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||
|
||||
const SiteNav: React.FC<unknown> = () => {
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
@@ -16,6 +17,7 @@ const SiteNav: React.FC<unknown> = () => {
|
||||
const initializeLogin = () => {
|
||||
instance.loginRedirect();
|
||||
};
|
||||
const appContext = useAppContext();
|
||||
|
||||
console.log(accounts);
|
||||
|
||||
@@ -24,24 +26,13 @@ const SiteNav: React.FC<unknown> = () => {
|
||||
<NavbarBrand>Site Logo Goes Here</NavbarBrand>
|
||||
<NavbarContent justify="center">
|
||||
<NavbarItem>
|
||||
{appContext.state.featureFlags.find(
|
||||
(featureFlag) => featureFlag.id === 'flying-pilots'
|
||||
)?.enabled && (
|
||||
<Link>
|
||||
<ReactRouterLink to="/">Flights</ReactRouterLink>
|
||||
</Link>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<Link>
|
||||
<ReactRouterLink to="/logbook">Logbook</ReactRouterLink>
|
||||
</Link>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<Link>
|
||||
<ReactRouterLink to="/checklists">Checklists</ReactRouterLink>
|
||||
</Link>
|
||||
</NavbarItem>
|
||||
<NavbarItem>
|
||||
<Link>
|
||||
<ReactRouterLink to="/pilots">Pilots</ReactRouterLink>
|
||||
<ReactRouterLink to="/">Pilots</ReactRouterLink>
|
||||
</Link>
|
||||
)}
|
||||
</NavbarItem>
|
||||
</NavbarContent>
|
||||
<NavbarContent justify="end">
|
||||
|
||||
5
app/src/context/appContext/AppContext.tsx
Normal file
5
app/src/context/appContext/AppContext.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import { Context, createContext } from 'react';
|
||||
import { IAppContextProps } from './IAppContextProps';
|
||||
|
||||
export const AppContext: Context<IAppContextProps> =
|
||||
createContext<IAppContextProps>({} as IAppContextProps);
|
||||
29
app/src/context/appContext/AppContextProvider.tsx
Normal file
29
app/src/context/appContext/AppContextProvider.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { useMemo, useReducer } from 'react';
|
||||
import { AppContext } from './AppContext';
|
||||
import { IAppContextProviderProps } from './IAppContextProviderProps';
|
||||
import { IAppContextProps } from './IAppContextProps';
|
||||
import { IAppContextState } from './IAppContextState';
|
||||
import { reducer } from './reducer';
|
||||
|
||||
const AppContextProvider: React.FC<IAppContextProviderProps> = (
|
||||
props: IAppContextProviderProps
|
||||
) => {
|
||||
const intialState: IAppContextState = {
|
||||
featureFlags: []
|
||||
};
|
||||
const [state, dispatch] = useReducer(reducer, intialState);
|
||||
const contextValue: IAppContextProps = useMemo(() => {
|
||||
return {
|
||||
state,
|
||||
dispatch
|
||||
};
|
||||
}, [state, dispatch]);
|
||||
|
||||
return (
|
||||
<AppContext.Provider value={contextValue}>
|
||||
{props.children}
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default AppContextProvider;
|
||||
7
app/src/context/appContext/IAppContextProps.ts
Normal file
7
app/src/context/appContext/IAppContextProps.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Action } from './reducer';
|
||||
import { IAppContextState } from './IAppContextState';
|
||||
|
||||
export interface IAppContextProps {
|
||||
state: IAppContextState;
|
||||
dispatch: React.Dispatch<Action>;
|
||||
}
|
||||
3
app/src/context/appContext/IAppContextProviderProps.ts
Normal file
3
app/src/context/appContext/IAppContextProviderProps.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface IAppContextProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
3
app/src/context/appContext/IAppContextState.ts
Normal file
3
app/src/context/appContext/IAppContextState.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export interface IAppContextState {
|
||||
featureFlags: unknown[];
|
||||
}
|
||||
20
app/src/context/appContext/reducer.ts
Normal file
20
app/src/context/appContext/reducer.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { IAppContextState } from './IAppContextState';
|
||||
|
||||
export type Action = { type: 'SET_FEATURE_FLAGS'; payload: unknown[] };
|
||||
|
||||
export const reducer = (
|
||||
state: IAppContextState,
|
||||
action: Action
|
||||
): IAppContextState => {
|
||||
switch (action.type) {
|
||||
case 'SET_FEATURE_FLAGS': {
|
||||
return {
|
||||
...state,
|
||||
featureFlags: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
11
app/src/hooks/appContext/UseAppContext.tsx
Normal file
11
app/src/hooks/appContext/UseAppContext.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { useContext } from 'react';
|
||||
import { AppContext } from '../../context/appContext/AppContext';
|
||||
|
||||
export const useAppContext = () => {
|
||||
const { state, dispatch } = useContext(AppContext);
|
||||
|
||||
return {
|
||||
state,
|
||||
dispatch
|
||||
};
|
||||
};
|
||||
10
app/src/hooks/featureFlag/UseFeatureFlag.tsx
Normal file
10
app/src/hooks/featureFlag/UseFeatureFlag.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import { useAppContext } from '../appContext/UseAppContext';
|
||||
|
||||
export const useFeatureFlag = (featureFlagId: string) => {
|
||||
const appContext = useAppContext();
|
||||
const featureFlag = appContext.state.featureFlags.find(
|
||||
(featureFlag) => featureFlag.id === featureFlagId
|
||||
);
|
||||
|
||||
return featureFlag;
|
||||
};
|
||||
@@ -4,8 +4,9 @@ import { MsalProvider } from '@azure/msal-react';
|
||||
import { Configuration, PublicClientApplication } from '@azure/msal-browser';
|
||||
import { NextUIProvider } from '@nextui-org/react';
|
||||
import App from './App.tsx';
|
||||
import './index.css';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import AppContextProvider from './context/appContext/AppContextProvider.tsx';
|
||||
import './index.css';
|
||||
|
||||
const configuration: Configuration = {
|
||||
auth: {
|
||||
@@ -21,11 +22,13 @@ const pca = new PublicClientApplication(configuration);
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<MsalProvider instance={pca}>
|
||||
<AppContextProvider>
|
||||
<NextUIProvider>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</NextUIProvider>
|
||||
</AppContextProvider>
|
||||
</MsalProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ export default {
|
||||
content: [
|
||||
'./index.html',
|
||||
'./src/**/*.{js,ts,jsx,tsx}',
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
'../node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
],
|
||||
theme: {
|
||||
extend: {}
|
||||
|
||||
165
package-lock.json
generated
165
package-lock.json
generated
@@ -9,9 +9,12 @@
|
||||
"version": "1.0.0",
|
||||
"workspaces": [
|
||||
"api",
|
||||
"client",
|
||||
"app",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"@azure/app-configuration": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
@@ -34,6 +37,7 @@
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@noahspan/noahspan-modules": "^0.1.2",
|
||||
"@schematics/angular": "^17.3.7",
|
||||
"dotenv": "^16.4.5",
|
||||
"reflect-metadata": "0.1.13",
|
||||
@@ -57,9 +61,37 @@
|
||||
"typescript": "^5.1.3"
|
||||
}
|
||||
},
|
||||
"app": {
|
||||
"name": "@noahspan/flying-client",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@azure/msal-react": "^2.0.15",
|
||||
"@nextui-org/react": "^2.3.6",
|
||||
"axios": "^1.7.2",
|
||||
"framer-motion": "^11.1.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.51.4",
|
||||
"react-router-dom": "^6.23.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.66",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"postcss": "^8.4.38",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"client": {
|
||||
"name": "@noahspan/flying-client",
|
||||
"version": "0.1.0",
|
||||
"extraneous": true,
|
||||
"dependencies": {
|
||||
"@azure/msal-react": "^2.0.15",
|
||||
"@nextui-org/react": "^2.3.6",
|
||||
@@ -299,6 +331,27 @@
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/app-configuration": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@azure/app-configuration/-/app-configuration-1.6.0.tgz",
|
||||
"integrity": "sha512-5Ae4SB0g4VbTnF7B+bwlkRLesRIYcaeg6e2Qxf0RlOEIetIgfAZiX6S5e7hD83X5RkwiPmzDm8rJm6HDpnVcvQ==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^1.0.0",
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-client": "^1.5.0",
|
||||
"@azure/core-http-compat": "^2.0.0",
|
||||
"@azure/core-lro": "^2.5.1",
|
||||
"@azure/core-paging": "^1.4.0",
|
||||
"@azure/core-rest-pipeline": "^1.6.0",
|
||||
"@azure/core-tracing": "^1.0.0",
|
||||
"@azure/core-util": "^1.6.1",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"tslib": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-auth": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz",
|
||||
@@ -351,6 +404,55 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-http-compat": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz",
|
||||
"integrity": "sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
"@azure/core-client": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-http-compat/node_modules/@azure/abort-controller": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
|
||||
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-lro": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz",
|
||||
"integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==",
|
||||
"dependencies": {
|
||||
"@azure/abort-controller": "^2.0.0",
|
||||
"@azure/core-util": "^1.2.0",
|
||||
"@azure/logger": "^1.0.0",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-lro/node_modules/@azure/abort-controller": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
|
||||
"integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/core-paging": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz",
|
||||
@@ -4297,9 +4399,28 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@noahspan/flying-client": {
|
||||
"resolved": "client",
|
||||
"resolved": "app",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@noahspan/noahspan-modules": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@noahspan/noahspan-modules/-/noahspan-modules-0.1.2.tgz",
|
||||
"integrity": "sha512-cD1PUgcFvy/9LTvxfzjk43+n+wZ4eTfWIZk1XFyM+NjjvP9cks2QnpQJ+di+7LYuzO8EPRX0/Ln34ywwwOCZaQ==",
|
||||
"dependencies": {
|
||||
"@azure/app-configuration": "^1.6.0",
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"axios": "^1.7.2",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@noahspan/noahspan-modules/node_modules/reflect-metadata": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
|
||||
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
||||
@@ -6852,8 +6973,7 @@
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.19",
|
||||
@@ -6892,6 +7012,16 @@
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz",
|
||||
"integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-jest": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
|
||||
@@ -7609,7 +7739,6 @@
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
@@ -7899,7 +8028,6 @@
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
@@ -8837,6 +8965,25 @@
|
||||
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.6",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
||||
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
||||
@@ -8906,7 +9053,6 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
@@ -12199,6 +12345,11 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/punycode": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||
|
||||
@@ -14,15 +14,18 @@
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.6",
|
||||
"husky": "^9.0.11",
|
||||
"lint-staged": "^15.2.2",
|
||||
"prettier": "3.2.5"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*": "prettier --write \"**/src/**/*.ts\" \"**/test/**/*.ts\" --ignore-unknown"
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/app-configuration": "^1.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user