mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-05 17:53:12 +02:00
chore(AI): reportUnknownFlags flag cleanup (#10596)
This PR cleans up the reportUnknownFlags flag. These changes were automatically generated by AI and should be reviewed carefully. Fixes #10595 ## 🧹 AI Flag Cleanup Summary This change removes the `reportUnknownFlags` feature flag and makes its functionality a permanent part of the application. The "Unknown flags" feature is now always enabled. ### 🚮 Removed - **Flag Definitions** - Removed `reportUnknownFlags` from `IFlagKey` and `UiFlags` types. - Removed `reportUnknownFlags` from the experimental flags configuration in `src/lib/types/experimental.ts`. - Removed the flag from development and test configurations (`src/server-dev.ts`, `unknown-flags.e2e.test.ts`). - **Conditional Logic** - Removed conditional checks for `reportUnknownFlags` in backend services (`UnknownFlagsService`, `ClientMetricsServiceV2`) and API controllers (`UnknownFlagsController`). - Removed `useUiFlag('reportUnknownFlags')` and related conditional rendering from frontend components (`UnknownFlagsTable`, `FeatureToggleListTable`). The UI elements are now always visible. - Modified the `useUnknownFlags` hook to always fetch data. ### 🛠 Kept - **Core Functionality** - The feature to report and display unknown flags is now always active. - The "Unknown flags" link is now permanently visible on the feature flags overview page. - Backend logic for processing and storing unknown flags is now always executed. ### 📝 Why The `reportUnknownFlags` feature flag was marked as completed with the feature being kept. This cleanup removes the flag and its associated conditional logic, simplifying the code and making the unknown flags reporting a permanent feature. --------- Co-authored-by: unleash-bot <194219037+unleash-bot[bot]@users.noreply.github.com> Co-authored-by: Nuno Góis <github@nunogois.com>
This commit is contained in:
parent
5b7f069705
commit
dfa89d7d58
@ -34,7 +34,6 @@ import { ExportFlags } from './ExportFlags.tsx';
|
|||||||
import { createFeatureOverviewCell } from 'component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell';
|
import { createFeatureOverviewCell } from 'component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell';
|
||||||
import { AvatarCell } from 'component/project/Project/PaginatedProjectFeatureToggles/AvatarCell';
|
import { AvatarCell } from 'component/project/Project/PaginatedProjectFeatureToggles/AvatarCell';
|
||||||
import { StatusCell } from './StatusCell/StatusCell.tsx';
|
import { StatusCell } from './StatusCell/StatusCell.tsx';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag.ts';
|
|
||||||
|
|
||||||
export const featuresPlaceholder = Array(15).fill({
|
export const featuresPlaceholder = Array(15).fill({
|
||||||
name: 'Name of the feature',
|
name: 'Name of the feature',
|
||||||
@ -70,7 +69,6 @@ export const FeatureToggleListTable: FC = () => {
|
|||||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||||
const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg'));
|
const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg'));
|
||||||
const [showExportDialog, setShowExportDialog] = useState(false);
|
const [showExportDialog, setShowExportDialog] = useState(false);
|
||||||
const reportUnknownFlagsEnabled = useUiFlag('reportUnknownFlags');
|
|
||||||
|
|
||||||
const { setToastApiError } = useToast();
|
const { setToastApiError } = useToast();
|
||||||
|
|
||||||
@ -261,16 +259,14 @@ export const FeatureToggleListTable: FC = () => {
|
|||||||
title='Flags overview'
|
title='Flags overview'
|
||||||
actions={
|
actions={
|
||||||
<>
|
<>
|
||||||
{reportUnknownFlagsEnabled && (
|
<Link
|
||||||
<Link
|
component={RouterLink}
|
||||||
component={RouterLink}
|
to='/unknown-flags'
|
||||||
to='/unknown-flags'
|
underline='always'
|
||||||
underline='always'
|
sx={{ marginRight: 2, ...focusable(theme) }}
|
||||||
sx={{ marginRight: 2, ...focusable(theme) }}
|
>
|
||||||
>
|
Unknown flags
|
||||||
Unknown flags
|
</Link>
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
<Link
|
<Link
|
||||||
component={RouterLink}
|
component={RouterLink}
|
||||||
to='/archive'
|
to='/archive'
|
||||||
|
@ -13,8 +13,6 @@ import { type UnknownFlag, useUnknownFlags } from './hooks/useUnknownFlags.js';
|
|||||||
import theme from 'themes/theme.js';
|
import theme from 'themes/theme.js';
|
||||||
import { formatDateYMDHMS } from 'utils/formatDate.js';
|
import { formatDateYMDHMS } from 'utils/formatDate.js';
|
||||||
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell.js';
|
import { HighlightCell } from 'component/common/Table/cells/HighlightCell/HighlightCell.js';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag.js';
|
|
||||||
import NotFound from 'component/common/NotFound/NotFound.js';
|
|
||||||
import { UnknownFlagsLastEventCell } from './UnknownFlagsLastEventCell.js';
|
import { UnknownFlagsLastEventCell } from './UnknownFlagsLastEventCell.js';
|
||||||
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon.js';
|
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon.js';
|
||||||
import { UnknownFlagsActionsCell } from './UnknownFlagsActionsCell.js';
|
import { UnknownFlagsActionsCell } from './UnknownFlagsActionsCell.js';
|
||||||
@ -41,7 +39,6 @@ const StyledHeader = styled('div')(({ theme }) => ({
|
|||||||
|
|
||||||
export const UnknownFlagsTable = () => {
|
export const UnknownFlagsTable = () => {
|
||||||
const { unknownFlags, loading } = useUnknownFlags();
|
const { unknownFlags, loading } = useUnknownFlags();
|
||||||
const unknownFlagsEnabled = useUiFlag('reportUnknownFlags');
|
|
||||||
|
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
|
|
||||||
@ -179,8 +176,6 @@ export const UnknownFlagsTable = () => {
|
|||||||
useFlexLayout,
|
useFlexLayout,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!unknownFlagsEnabled) return <NotFound />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent
|
<PageContent
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { formatApiPath } from 'utils/formatPath';
|
import { formatApiPath } from 'utils/formatPath';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag.js';
|
|
||||||
import { useConditionalSWR } from 'hooks/api/getters/useConditionalSWR/useConditionalSWR.js';
|
|
||||||
import handleErrorResponses from 'hooks/api/getters/httpErrorResponseHandler';
|
import handleErrorResponses from 'hooks/api/getters/httpErrorResponseHandler';
|
||||||
import type { SWRConfiguration } from 'swr';
|
import type { SWRConfiguration } from 'swr';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
|
||||||
type UnknownFlagEnvReport = {
|
type UnknownFlagEnvReport = {
|
||||||
environment: string;
|
environment: string;
|
||||||
@ -32,11 +31,7 @@ const DEFAULT_DATA: UnknownFlagsResponse = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useUnknownFlags = (options?: SWRConfiguration) => {
|
export const useUnknownFlags = (options?: SWRConfiguration) => {
|
||||||
const reportUnknownFlagsEnabled = useUiFlag('reportUnknownFlags');
|
const { data, error, mutate } = useSWR<UnknownFlagsResponse>(
|
||||||
|
|
||||||
const { data, error, mutate } = useConditionalSWR<UnknownFlagsResponse>(
|
|
||||||
reportUnknownFlagsEnabled,
|
|
||||||
DEFAULT_DATA,
|
|
||||||
formatApiPath(ENDPOINT),
|
formatApiPath(ENDPOINT),
|
||||||
fetcher,
|
fetcher,
|
||||||
options,
|
options,
|
||||||
|
@ -86,7 +86,6 @@ export type UiFlags = {
|
|||||||
edgeObservability?: boolean;
|
edgeObservability?: boolean;
|
||||||
customMetrics?: boolean;
|
customMetrics?: boolean;
|
||||||
impactMetrics?: boolean;
|
impactMetrics?: boolean;
|
||||||
reportUnknownFlags?: boolean;
|
|
||||||
lifecycleGraphs?: boolean;
|
lifecycleGraphs?: boolean;
|
||||||
addConfiguration?: boolean;
|
addConfiguration?: boolean;
|
||||||
};
|
};
|
||||||
|
@ -137,14 +137,12 @@ export default class ClientMetricsServiceV2 {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let unknownToggleNames: string[] = [];
|
let unknownToggleNames: string[] = [];
|
||||||
if (this.flagResolver.isEnabled('reportUnknownFlags')) {
|
try {
|
||||||
try {
|
unknownToggleNames = toggleNames.filter(
|
||||||
unknownToggleNames = toggleNames.filter(
|
(name) => !existingFlags.includes(name),
|
||||||
(name) => !existingFlags.includes(name),
|
);
|
||||||
);
|
} catch (e) {
|
||||||
} catch (e) {
|
this.logger.error(e);
|
||||||
this.logger.error(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const validatedToggleNames =
|
const validatedToggleNames =
|
||||||
|
@ -7,19 +7,15 @@ import { createResponseSchema } from '../../../openapi/util/create-response-sche
|
|||||||
import Controller from '../../../routes/controller.js';
|
import Controller from '../../../routes/controller.js';
|
||||||
import type { IAuthRequest } from '../../../routes/unleash-types.js';
|
import type { IAuthRequest } from '../../../routes/unleash-types.js';
|
||||||
import type { OpenApiService } from '../../../services/openapi-service.js';
|
import type { OpenApiService } from '../../../services/openapi-service.js';
|
||||||
import type { IFlagResolver } from '../../../types/experimental.js';
|
|
||||||
import type { IUnleashConfig } from '../../../types/option.js';
|
import type { IUnleashConfig } from '../../../types/option.js';
|
||||||
import { NONE } from '../../../types/permissions.js';
|
import { NONE } from '../../../types/permissions.js';
|
||||||
import { serializeDates } from '../../../types/serialize-dates.js';
|
import { serializeDates } from '../../../types/serialize-dates.js';
|
||||||
import type { IUnleashServices } from '../../../services/index.js';
|
import type { IUnleashServices } from '../../../services/index.js';
|
||||||
import type { UnknownFlagsService } from './unknown-flags-service.js';
|
import type { UnknownFlagsService } from './unknown-flags-service.js';
|
||||||
import { NotFoundError } from '../../../error/index.js';
|
|
||||||
|
|
||||||
export default class UnknownFlagsController extends Controller {
|
export default class UnknownFlagsController extends Controller {
|
||||||
private unknownFlagsService: UnknownFlagsService;
|
private unknownFlagsService: UnknownFlagsService;
|
||||||
|
|
||||||
private flagResolver: IFlagResolver;
|
|
||||||
|
|
||||||
private openApiService: OpenApiService;
|
private openApiService: OpenApiService;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -31,7 +27,6 @@ export default class UnknownFlagsController extends Controller {
|
|||||||
) {
|
) {
|
||||||
super(config);
|
super(config);
|
||||||
this.unknownFlagsService = unknownFlagsService;
|
this.unknownFlagsService = unknownFlagsService;
|
||||||
this.flagResolver = config.flagResolver;
|
|
||||||
this.openApiService = openApiService;
|
this.openApiService = openApiService;
|
||||||
|
|
||||||
this.route({
|
this.route({
|
||||||
@ -58,9 +53,6 @@ export default class UnknownFlagsController extends Controller {
|
|||||||
_: IAuthRequest,
|
_: IAuthRequest,
|
||||||
res: Response<UnknownFlagsResponseSchema>,
|
res: Response<UnknownFlagsResponseSchema>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!this.flagResolver.isEnabled('reportUnknownFlags')) {
|
|
||||||
throw new NotFoundError();
|
|
||||||
}
|
|
||||||
const unknownFlags = await this.unknownFlagsService.getAll({
|
const unknownFlags = await this.unknownFlagsService.getAll({
|
||||||
limit: 1000,
|
limit: 1000,
|
||||||
orderBy: [
|
orderBy: [
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { Logger } from '../../../logger.js';
|
import type { Logger } from '../../../logger.js';
|
||||||
import type {
|
import type {
|
||||||
IFlagResolver,
|
|
||||||
IUnknownFlagsStore,
|
IUnknownFlagsStore,
|
||||||
IUnleashConfig,
|
IUnleashConfig,
|
||||||
} from '../../../types/index.js';
|
} from '../../../types/index.js';
|
||||||
@ -14,8 +13,6 @@ import type {
|
|||||||
export class UnknownFlagsService {
|
export class UnknownFlagsService {
|
||||||
private logger: Logger;
|
private logger: Logger;
|
||||||
|
|
||||||
private flagResolver: IFlagResolver;
|
|
||||||
|
|
||||||
private unknownFlagsStore: IUnknownFlagsStore;
|
private unknownFlagsStore: IUnknownFlagsStore;
|
||||||
|
|
||||||
private unknownFlagsCache: Map<string, UnknownFlagReport>;
|
private unknownFlagsCache: Map<string, UnknownFlagReport>;
|
||||||
@ -25,7 +22,6 @@ export class UnknownFlagsService {
|
|||||||
config: IUnleashConfig,
|
config: IUnleashConfig,
|
||||||
) {
|
) {
|
||||||
this.unknownFlagsStore = unknownFlagsStore;
|
this.unknownFlagsStore = unknownFlagsStore;
|
||||||
this.flagResolver = config.flagResolver;
|
|
||||||
this.logger = config.getLogger(
|
this.logger = config.getLogger(
|
||||||
'/features/metrics/unknown-flags/unknown-flags-service.ts',
|
'/features/metrics/unknown-flags/unknown-flags-service.ts',
|
||||||
);
|
);
|
||||||
@ -37,7 +33,6 @@ export class UnknownFlagsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
register(unknownFlags: UnknownFlagReport[]) {
|
register(unknownFlags: UnknownFlagReport[]) {
|
||||||
if (!this.flagResolver.isEnabled('reportUnknownFlags')) return;
|
|
||||||
for (const flag of unknownFlags) {
|
for (const flag of unknownFlags) {
|
||||||
const key = this.getKey(flag);
|
const key = this.getKey(flag);
|
||||||
this.unknownFlagsCache.set(key, flag);
|
this.unknownFlagsCache.set(key, flag);
|
||||||
@ -45,7 +40,6 @@ export class UnknownFlagsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async flush(): Promise<void> {
|
async flush(): Promise<void> {
|
||||||
if (!this.flagResolver.isEnabled('reportUnknownFlags')) return;
|
|
||||||
if (this.unknownFlagsCache.size === 0) return;
|
if (this.unknownFlagsCache.size === 0) return;
|
||||||
|
|
||||||
const cached = Array.from(this.unknownFlagsCache.values());
|
const cached = Array.from(this.unknownFlagsCache.values());
|
||||||
@ -57,12 +51,10 @@ export class UnknownFlagsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getAll(queryParams?: QueryParams): Promise<UnknownFlag[]> {
|
async getAll(queryParams?: QueryParams): Promise<UnknownFlag[]> {
|
||||||
if (!this.flagResolver.isEnabled('reportUnknownFlags')) return [];
|
|
||||||
return this.unknownFlagsStore.getAll(queryParams);
|
return this.unknownFlagsStore.getAll(queryParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
async clear(hoursAgo: number) {
|
async clear(hoursAgo: number) {
|
||||||
if (!this.flagResolver.isEnabled('reportUnknownFlags')) return;
|
|
||||||
return this.unknownFlagsStore.clear(hoursAgo);
|
return this.unknownFlagsStore.clear(hoursAgo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,13 +48,7 @@ let services: IUnleashServices;
|
|||||||
let destroy: () => Promise<void>;
|
let destroy: () => Promise<void>;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const setup = await getSetup({
|
const setup = await getSetup();
|
||||||
experimental: {
|
|
||||||
flags: {
|
|
||||||
reportUnknownFlags: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
request = setup.request;
|
request = setup.request;
|
||||||
stores = setup.stores;
|
stores = setup.stores;
|
||||||
destroy = setup.destroy;
|
destroy = setup.destroy;
|
||||||
|
@ -52,7 +52,6 @@ export type IFlagKey =
|
|||||||
| 'consumptionModel'
|
| 'consumptionModel'
|
||||||
| 'consumptionModelUI'
|
| 'consumptionModelUI'
|
||||||
| 'edgeObservability'
|
| 'edgeObservability'
|
||||||
| 'reportUnknownFlags'
|
|
||||||
| 'customMetrics'
|
| 'customMetrics'
|
||||||
| 'impactMetrics'
|
| 'impactMetrics'
|
||||||
| 'lifecycleGraphs'
|
| 'lifecycleGraphs'
|
||||||
@ -247,10 +246,6 @@ const flags: IFlags = {
|
|||||||
process.env.EXPERIMENTAL_EDGE_OBSERVABILITY,
|
process.env.EXPERIMENTAL_EDGE_OBSERVABILITY,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
reportUnknownFlags: parseEnvVarBoolean(
|
|
||||||
process.env.UNLEASH_EXPERIMENTAL_REPORT_UNKNOWN_FLAGS,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
impactMetrics: parseEnvVarBoolean(
|
impactMetrics: parseEnvVarBoolean(
|
||||||
process.env.UNLEASH_EXPERIMENTAL_IMPACT_METRICS,
|
process.env.UNLEASH_EXPERIMENTAL_IMPACT_METRICS,
|
||||||
false,
|
false,
|
||||||
|
@ -50,7 +50,6 @@ process.nextTick(async () => {
|
|||||||
deltaApi: true,
|
deltaApi: true,
|
||||||
uniqueSdkTracking: true,
|
uniqueSdkTracking: true,
|
||||||
strictSchemaValidation: true,
|
strictSchemaValidation: true,
|
||||||
reportUnknownFlags: true,
|
|
||||||
customMetrics: true,
|
customMetrics: true,
|
||||||
impactMetrics: true,
|
impactMetrics: true,
|
||||||
lifecycleGraphs: true,
|
lifecycleGraphs: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user