Skip to content

Commit

Permalink
Merge branch 'main' into gitar_simplifyProjectOverview_true
Browse files Browse the repository at this point in the history
  • Loading branch information
sjaanus committed Jan 8, 2025
2 parents bef6049 + e726947 commit 6006544
Show file tree
Hide file tree
Showing 37 changed files with 379 additions and 181 deletions.
53 changes: 8 additions & 45 deletions frontend/src/component/admin/auth/AuthSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Alert, Tab, Tabs } from '@mui/material';
import { Tab, Tabs } from '@mui/material';
import { PageContent } from 'component/common/PageContent/PageContent';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
Expand All @@ -15,7 +15,6 @@ import { TabPanel } from 'component/common/TabNav/TabPanel/TabPanel';
import { usePageTitle } from 'hooks/usePageTitle';

export const AuthSettings = () => {
const { authenticationType } = useUiConfig().uiConfig;
const { uiConfig, isEnterprise } = useUiConfig();

const tabs = [
Expand All @@ -35,17 +34,14 @@ export const AuthSettings = () => {
label: 'Google',
component: <GoogleAuth />,
},
{
label: 'SCIM',
component: <ScimSettings />,
},
].filter(
(item) => uiConfig.flags?.googleAuthEnabled || item.label !== 'Google',
);

if (isEnterprise()) {
tabs.push({
label: 'SCIM',
component: <ScimSettings />,
});
}

const [activeTab, setActiveTab] = useState(0);
usePageTitle(`Single sign-on: ${tabs[activeTab].label}`);

Expand All @@ -56,7 +52,7 @@ export const AuthSettings = () => {
withTabs
header={
<ConditionallyRender
condition={authenticationType === 'enterprise'}
condition={isEnterprise()}
show={
<Tabs
value={activeTab}
Expand Down Expand Up @@ -85,41 +81,7 @@ export const AuthSettings = () => {
}
>
<ConditionallyRender
condition={authenticationType === 'open-source'}
show={<PremiumFeature feature='sso' />}
/>
<ConditionallyRender
condition={authenticationType === 'demo'}
show={
<Alert severity='warning'>
You are running Unleash in demo mode. You have
to use the Enterprise edition in order configure
Single Sign-on.
</Alert>
}
/>
<ConditionallyRender
condition={authenticationType === 'custom'}
show={
<Alert severity='warning'>
You have decided to use custom authentication
type. You have to use the Enterprise edition in
order configure Single Sign-on from the user
interface.
</Alert>
}
/>
<ConditionallyRender
condition={authenticationType === 'hosted'}
show={
<Alert severity='info'>
Your Unleash instance is managed by the Unleash
team.
</Alert>
}
/>
<ConditionallyRender
condition={authenticationType === 'enterprise'}
condition={isEnterprise()}
show={
<div>
{tabs.map((tab, index) => (
Expand All @@ -133,6 +95,7 @@ export const AuthSettings = () => {
))}
</div>
}
elseShow={<PremiumFeature feature='sso' />}
/>
</PageContent>
</PermissionGuard>
Expand Down
14 changes: 10 additions & 4 deletions frontend/src/component/admin/cors/CorsForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ADMIN } from 'component/providers/AccessProvider/permissions';
import type React from 'react';
import { useState } from 'react';
import { TextField, Box } from '@mui/material';
Expand All @@ -7,23 +6,30 @@ import { useUiConfigApi } from 'hooks/api/actions/useUiConfigApi/useUiConfigApi'
import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { useId } from 'hooks/useId';
import { ADMIN, UPDATE_CORS } from '@server/types/permissions';
import { useUiFlag } from 'hooks/useUiFlag';

interface ICorsFormProps {
frontendApiOrigins: string[] | undefined;
}

export const CorsForm = ({ frontendApiOrigins }: ICorsFormProps) => {
const { setFrontendSettings } = useUiConfigApi();
const { setFrontendSettings, setCors } = useUiConfigApi();
const { setToastData, setToastApiError } = useToast();
const [value, setValue] = useState(formatInputValue(frontendApiOrigins));
const inputFieldId = useId();
const helpTextId = useId();
const isGranularPermissionsEnabled = useUiFlag('granularAdminPermissions');

const onSubmit = async (event: React.FormEvent) => {
try {
const split = parseInputValue(value);
event.preventDefault();
await setFrontendSettings(split);
if (isGranularPermissionsEnabled) {
await setCors(split);
} else {
await setFrontendSettings(split);
}
setValue(formatInputValue(split));
setToastData({ text: 'Settings saved', type: 'success' });
} catch (error) {
Expand Down Expand Up @@ -67,7 +73,7 @@ export const CorsForm = ({ frontendApiOrigins }: ICorsFormProps) => {
style: { fontFamily: 'monospace', fontSize: '0.8em' },
}}
/>
<UpdateButton permission={ADMIN} />
<UpdateButton permission={[ADMIN, UPDATE_CORS]} />
</Box>
</form>
);
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/component/admin/cors/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
import { ADMIN } from 'component/providers/AccessProvider/permissions';
import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader';
import { Box } from '@mui/material';
import { CorsHelpAlert } from 'component/admin/cors/CorsHelpAlert';
import { CorsForm } from 'component/admin/cors/CorsForm';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ADMIN, UPDATE_CORS } from '@server/types/permissions';

export const CorsAdmin = () => (
<div>
<PermissionGuard permissions={ADMIN}>
<PermissionGuard permissions={[ADMIN, UPDATE_CORS]}>
<CorsPage />
</PermissionGuard>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const StyledGridContainer = styled('div')(({ theme }) => ({
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
gap: theme.spacing(2),
gridAutoRows: '1fr',
}));

type PageQueryType = Partial<Record<'search', string>>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Box, styled } from '@mui/material';
import { InviteLinkBar } from '../InviteLinkBar/InviteLinkBar';
import { useUiFlag } from 'hooks/useUiFlag';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { LicensedUsersBox } from './LicensedUsersBox';

Expand All @@ -24,9 +23,8 @@ const StyledElement = styled(Box)(({ theme }) => ({
}));

export const UsersHeader = () => {
const licensedUsers = useUiFlag('licensedUsers');
const { isOss } = useUiConfig();
const licensedUsersEnabled = licensedUsers && !isOss();
const licensedUsersEnabled = !isOss();

return (
<StyledContainer>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/component/events/EventPage/EventPage.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ADMIN } from 'component/providers/AccessProvider/permissions';
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
import { EventLog } from 'component/events/EventLog/EventLog';
import { READ_LOGS, ADMIN } from '@server/types/permissions';

export const EventPage = () => (
<PermissionGuard permissions={ADMIN}>
<PermissionGuard permissions={[ADMIN, READ_LOGS]}>
<EventLog title='Event log' />
</PermissionGuard>
);
3 changes: 2 additions & 1 deletion frontend/src/component/loginHistory/LoginHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuar
import { LoginHistoryTable } from './LoginHistoryTable/LoginHistoryTable';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
import { READ_LOGS } from '@server/types/permissions';

export const LoginHistory = () => {
const { isEnterprise } = useUiConfig();
Expand All @@ -13,7 +14,7 @@ export const LoginHistory = () => {

return (
<div>
<PermissionGuard permissions={ADMIN}>
<PermissionGuard permissions={[ADMIN, READ_LOGS]}>
<LoginHistoryTable />
</PermissionGuard>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,14 @@ const StyledAccordion = styled(Accordion)(({ theme }) => ({
const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({
boxShadow: 'none',
padding: theme.spacing(1.5, 2),
borderRadius: theme.shape.borderRadiusMedium,
[theme.breakpoints.down(400)]: {
padding: theme.spacing(1, 2),
},
'&.Mui-focusVisible': {
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(0.5, 2, 0.3, 2),
},
}));

const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export const MilestoneCardName = ({
setEditMode(false);
}
}}
onClick={(ev) => {
ev.preventDefault();
ev.stopPropagation();
}}
/>
)}
{!editMode && (
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/hooks/api/actions/useUiConfigApi/useUiConfigApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ export const useUiConfigApi = () => {
propagateErrors: true,
});

/**
* @deprecated remove when `granularAdminPermissions` flag is removed
*/
const setFrontendSettings = async (
frontendApiOrigins: string[],
): Promise<void> => {
Expand All @@ -19,8 +22,18 @@ export const useUiConfigApi = () => {
await makeRequest(req.caller, req.id);
};

const setCors = async (frontendApiOrigins: string[]): Promise<void> => {
const req = createRequest(
'api/admin/ui-config/cors',
{ method: 'POST', body: JSON.stringify({ frontendApiOrigins }) },
'setCors',
);
await makeRequest(req.caller, req.id);
};

return {
setFrontendSettings,
setCors,
loading,
errors,
};
Expand Down
1 change: 0 additions & 1 deletion frontend/src/interfaces/uiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ export type UiFlags = {
productivityReportEmail?: boolean;
showUserDeviceCount?: boolean;
flagOverviewRedesign?: boolean;
licensedUsers?: boolean;
granularAdminPermissions?: boolean;
};

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@
"stoppable": "^1.1.0",
"ts-toolbelt": "^9.6.0",
"type-is": "^1.6.18",
"unleash-client": "^6.3.3",
"unleash-client": "^6.4.0",
"uuid": "^9.0.0"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ import type {
import type { Logger } from '../../logger';

import type { FeatureConfigurationClient } from '../feature-toggle/types/feature-toggle-strategies-store-type';
import type {
RevisionDeltaEntry,
ClientFeatureToggleDelta,
} from './delta/client-feature-toggle-delta';
import type { ClientFeatureToggleDelta } from './delta/client-feature-toggle-delta';
import type { ClientFeaturesDeltaSchema } from '../../openapi';

export class ClientFeatureToggleService {
private logger: Logger;
Expand Down Expand Up @@ -44,7 +42,7 @@ export class ClientFeatureToggleService {
async getClientDelta(
revisionId: number | undefined,
query: IFeatureToggleQuery,
): Promise<RevisionDeltaEntry | undefined> {
): Promise<ClientFeaturesDeltaSchema | undefined> {
if (this.clientFeatureToggleDelta !== null) {
return this.clientFeatureToggleDelta.getDelta(revisionId, query);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,37 @@ const syncRevisions = async () => {
// @ts-ignore
await app.services.clientFeatureToggleService.clientFeatureToggleDelta.onUpdateRevisionEvent();
};

test('archived features should not be returned as updated', async () => {
await app.createFeature('base_feature');
await syncRevisions();
const { body } = await app.request.get('/api/client/delta').expect(200);
const currentRevisionId = body.revisionId;

expect(body).toMatchObject({
updated: [
{
name: 'base_feature',
},
],
});

await app.archiveFeature('base_feature');
await app.createFeature('new_feature');

await syncRevisions();

const { body: deltaBody } = await app.request
.get('/api/client/delta')
.set('If-None-Match', currentRevisionId)
.expect(200);

expect(deltaBody).toMatchObject({
updated: [
{
name: 'new_feature',
},
],
removed: ['base_feature'],
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import type { OpenApiService } from '../../../services/openapi-service';
import { NONE } from '../../../types/permissions';
import { createResponseSchema } from '../../../openapi/util/create-response-schema';
import type { ClientFeatureToggleService } from '../client-feature-toggle-service';
import type { RevisionDeltaEntry } from './client-feature-toggle-delta';
import { clientFeaturesDeltaSchema } from '../../../openapi';
import {
type ClientFeaturesDeltaSchema,
clientFeaturesDeltaSchema,
} from '../../../openapi';
import type { QueryOverride } from '../client-feature-toggle.controller';

export default class ClientFeatureToggleDeltaController extends Controller {
Expand Down Expand Up @@ -75,7 +77,7 @@ export default class ClientFeatureToggleDeltaController extends Controller {

async getDelta(
req: IAuthRequest,
res: Response<RevisionDeltaEntry>,
res: Response<ClientFeaturesDeltaSchema>,
): Promise<void> {
if (!this.flagResolver.isEnabled('deltaApi')) {
throw new NotFoundError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { FeatureConfigurationClient } from '../../feature-toggle/types/feat
export interface FeatureConfigurationDeltaClient
extends FeatureConfigurationClient {
description: string;
impressionData: false;
impressionData: boolean;
}

export interface IClientFeatureToggleDeltaReadModel {
Expand Down
Loading

0 comments on commit 6006544

Please sign in to comment.